home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD v1.2 / amidev_cd_12.iso / devcon / milan_1991 / devcon91.2 / network / socket / examples / server2.c < prev    next >
C/C++ Source or Header  |  1992-09-01  |  7KB  |  274 lines

  1. /*
  2. **  server2.c
  3. **
  4. **  Written by Dale Larson, Software Engineer, Commodore-Amiga, Inc.
  5. **  Copyright 1991, Commodore-Amiga, Inc.
  6. **  Permission to use granted provided this notice remains intact.
  7. **
  8. **  This is a version of the ncopy server which processes multiple requests
  9. **  simultaneously.  It spawns multiple processes to do so (it could also
  10. **  use selectwait() to do [see server3.c]).  It is more complex than the
  11. **  simple server, but not much, and it is nicer under frequent and/or heavy
  12. **  use.  It also allows users to copy a file from one location on a remote
  13. **  machine to another location on the same remote machine (i.e.
  14. **  "ncopy sprite!ram:x sprite!work:y").  A system requester will not
  15. **  pop up if the server recieves a request to read/write to/from a
  16. **  non-existent device.
  17. **
  18. **  This server has no provision for exiting.
  19. **
  20. **  You should be familiar with the ncopy client (ncopy.c and transfer.c) and
  21. **  the simple ncopy server (server1.c) before studying this server.
  22. **
  23. **  Thanks to Randell Jessup for his idea on how to easily arbitrate access
  24. **  to the global Ns (which is used to pass info to child processes).
  25. */
  26.  
  27.  
  28. #include "ncopy.h"
  29.  
  30. struct Library *SockBase;
  31. #define MAXSOCKS 10
  32.  
  33. char vers[] = "\0$VER: server2 1.0 (25.02.91)";
  34.  
  35. void send_file(int s, BPTR file);
  36. void get_file(int s, BPTR file);
  37. void handle_request(void);
  38. int  init(void);
  39.  
  40. /*  Not in SAS 5.10 or Manx 5.0d includes  */
  41. struct Process *CreateNewProcTags( unsigned long tag1type, ... );
  42.  
  43. /*  global variable for New socket read by new processes:  */
  44. int Ns = 0;
  45.  
  46.  
  47. /*
  48. **  main()
  49. **
  50. **  Call init() then wait to accept connections. Once a connection has been
  51. **  accepted, start a new process to execute the handler function with the
  52. **  socket which accept() connected to a remote machine.  Go back to accepting
  53. **  connections.
  54. */
  55. main(int argc, char **argv)
  56. {
  57. int s;             /*  socket to accept connections on  */
  58. struct Process *pid;
  59.  
  60.     s = init();
  61.  
  62.     /*
  63.     **  Accept connections from s and process them on ns.
  64.     */
  65.     while(1)
  66.     {
  67.         /*
  68.         **  Make sure that there is not a child process which hasn't
  69.         **  had a chance to copy its socket.  Ns must be initialized
  70.         **  to zero before this while() and children must set Ns
  71.         **  to zero when they have copied it.
  72.         */
  73.         if(Ns)
  74.         {
  75.             Delay(1);
  76.             continue;
  77.         }
  78.         if( (Ns = accept(s,NULL,NULL)) >= 0 )
  79.         {
  80.         static char proc_name[20];
  81.  
  82.             sprintf(proc_name, "ncopy server #%2d", Ns);
  83.             pid = CreateNewProcTags(NP_Entry, (LONG)handle_request,
  84.                         NP_Name, (LONG)proc_name,
  85.                         NP_WindowPtr, -1L,
  86.                         TAG_DONE);
  87.             if(!pid)
  88.             {
  89.                 s_close(Ns);
  90.                 Ns = 0;
  91.             }
  92.         }
  93.     }
  94. }
  95.  
  96.  
  97. /*
  98. **  init()
  99. **
  100. **  Get a socket, bind a name to it, express a willingness to accept
  101. **  connections to it (listen) and return the socket.  Exit on error.
  102. */
  103. int init(void)
  104. {
  105. struct sockaddr_in sin;    /*  socket address (internet) to establish  */
  106. int s,             /*  socket to accept connections on  */
  107.     len = sizeof(sin);
  108.  
  109.     /*  Open Shared Socket library:
  110.     */
  111.         if(SockBase = OpenLibrary( "inet:libs/socket.library", 0L ))
  112.         {
  113.                 setup_sockets( MAXSOCKS, &errno );
  114.     }else
  115.     {
  116.         puts("Can't open socket.library.");
  117.         exit(RETURN_ERROR);
  118.     }
  119.  
  120.     /*
  121.     **  Initialize a socket.
  122.     */
  123.     if( (s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  124.     {
  125.         perror("socket");
  126.         exit(RETURN_ERROR);
  127.     }
  128.  
  129.     /*
  130.     **  Bind name to socket.
  131.     **  Since we got sin off the stack, it could contain anything, and so
  132.     **  we zero it before initializing it.
  133.     */
  134.     bzero(&sin, len);
  135.     sin.sin_family = AF_INET;
  136.     /*
  137.     **  While prototyping a program, pick an unused port number above
  138.     **  1024 like I did here.  For a real program, assign a name and a
  139.     **  port number above 1024 and stick it in inet:db/servers on all
  140.     **  machines which will use the application.  That way the user can
  141.     **  reconfigure port numbers used by new applications if necessary.
  142.     **  You can modify the server to get the port number from the
  143.     **  database by using code like this (instead of "sin.sin_port=
  144.     **  htons(6666)" below):
  145.     **
  146.     **  struct servent *servptr;
  147.     **  char serv[] = "servicename";
  148.     **
  149.     **  if( (servptr = getservbyname(serv, "tcp")) == NULL)
  150.     **  {
  151.     **      printf("Unknown service %s.  Check inet:db/services.\n",serv);
  152.     **    return RETURN_ERROR;
  153.     **  }
  154.     **  sin.sin_port = servptr->s_port;
  155.     */
  156.     sin.sin_port = htons(6666);
  157.     sin.sin_addr.s_addr = INADDR_ANY;
  158.     if(bind(s, (struct sockaddr *)&sin, len) < 0)
  159.     {
  160.         perror("bind");
  161.         exit(RETURN_ERROR);
  162.     }
  163.  
  164.     /*
  165.     **  Put socket into "listen" state (ready to accept connections).
  166.     */
  167.     listen(s,5);
  168.     return s;
  169. }
  170.  
  171.  
  172. /*
  173. **  handle_request()
  174. **
  175. **  Handles a request to send or receive a file on a given socket.
  176. **  Handling a request consists of the following:
  177. **      1)  receive the mode (send or receive -- MODE_OLDFILE or MODE_NEWFILE)
  178. **    2)  receive the filename
  179. **    3)  attempt to open the file
  180. **    4)  return "\0" for succesful open,
  181. **        specially formated informative error message otherwise
  182. **    5)  call function to send or receive the file
  183. **    6)  closes the file we opened and the socket we were passed
  184. */
  185. void handle_request(void)
  186. {
  187. int s;        /*  socket passed by parent  */
  188. char buffer[LENGTH];
  189. int mode;    /*  AmigaDOS file open mode (MODE_OLDFILE or MODE_NEWFILE)  */
  190. BPTR file;    /*  BCPL pointer to an AmigaDOS file handle  */
  191.  
  192.     geta4();
  193.  
  194.  
  195.         s = Ns;
  196.     Ns = 0;  /*  So that parent may feel free to use it again  */
  197.  
  198.  
  199.     /*  Get the mode.
  200.     **  Don't worry about making sure that we got what we wanted because we
  201.     **  can't really screw anything up and we can't send an error message
  202.     **  if our communcications are error-prone.
  203.     */
  204.     recv(s, (char *)&mode, sizeof(int), 0);
  205.  
  206.     /*  Get the filename which we'll read or write (depending on mode).
  207.     **  (Assume that we get only null-terminated strings.)
  208.     */
  209.     recv(s, buffer, LENGTH, 0);
  210.  
  211.     /*
  212.     **  Attempt to open file.
  213.     */
  214.     if( !(file = Open(buffer, mode)) )
  215.     {
  216.     int len;
  217.  
  218.         len = strlen(buffer);
  219.         strncat(buffer, "': ", LENGTH-4);  /*  4 not 3 'cause of nul  */
  220.         Fault(IoErr(), NULL, buffer+len+3, LENGTH-len-4);
  221.         send(s, buffer, strlen(buffer)+1, 0);
  222.         s_close(s);
  223.         return;
  224.     }
  225.  
  226.     /*
  227.     **  Indicate succesful opening of file.
  228.     */
  229.     send(s, "\0", 1, 0);
  230.  
  231.     /*
  232.     **  Send or recieve the file.
  233.     */
  234.     if(mode == MODE_OLDFILE)
  235.         send_file(s, file);
  236.     else
  237.         get_file(s, file);
  238.  
  239.     Close(file);
  240.     s_close(s);
  241. }
  242.  
  243.  
  244. void send_file(int s, BPTR file)
  245. {
  246. char    buffer[LENGTH];
  247. long    actualLength;
  248.  
  249.     do
  250.     {
  251.         actualLength = Read(file, (void *)buffer, LENGTH);
  252.             if(actualLength < 0)
  253.             return;  /*  Error, but we have no way to report it.  */
  254.         if(send(s, buffer, actualLength, 0) < 0)
  255.             return;  /*  Error, but we have no way to report it.  */
  256.     }while(actualLength);
  257. }
  258.  
  259.  
  260. void get_file(int s, BPTR file)
  261. {
  262. char    buffer[LENGTH];
  263. int     n;
  264.  
  265.     do
  266.     {
  267.         n = recv(s, buffer, LENGTH, 0);
  268.         if(n < 0)
  269.             return;  /*  Error, but we have no way to report it.  */
  270.         if(Write(file, (void *)buffer, n) < 0)
  271.             return;  /*  Error, but we have no way to report it.  */
  272.     }while(n);
  273. }
  274.