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

  1. /*
  2. **  server3.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 utilizes selectwait() to do so (a server could also
  10. **  spawn multiple processes to do so).  It is more complex than the simple
  11. **  server, but is nicer under frequent and/or heavy use, and allows users to
  12. **  copy a file from one location on a remote machine to another location on
  13. **  the same remote machine (i.e.  "ncopy sprite!ram:x sprite!work:y").  Using
  14. **  selectwait() (or multiple processes) also makes it reasonable to implement
  15. **  exit-on-break-signal. A system requester will not pop up if the server
  16. **  recieves a request to read/write to/from a non-existent device.
  17. **
  18. **  Note that this server really does not properly handle copying from one
  19. **  locations on a remote machine to another location on the same remote
  20. **  machine.  It works fine for files not more than about 8k, but will hang
  21. **  for files larger than that.  The reason is that it sends all of a file
  22. **  at once.  If the target is another machine, the other machine's ncopy or
  23. **  server will read the data as this server writes it.  But if this server
  24. **  is also supposed to read the data, 8 TCP packets will be buffered, then
  25. **  send() will block until some of them are read and acknowledged.  This
  26. **  problem could be solved in the server by including a select() in the
  27. **  send loop, by not allowing ncopy to transfer to and from the same machine,
  28. **  or by redesigning the ncopy protocol.  Any of these solutions would unduly
  29. **  complicate and excede the scope of this example.  Note that the number '8'
  30. **  is an implementation-dependent number.
  31. **
  32. **  You should be familiar with the ncopy client (ncopy.c and transfer.c) and
  33. **  the simple ncopy server (server1.c) before studying this server.
  34. **
  35. */
  36.  
  37.  
  38. #include "ncopy.h"
  39.  
  40. struct Library *SockBase;
  41. #define MAXSOCKS 10
  42.  
  43. char vers[] = "\0$VER: server3 1.0 (28.02.91)";
  44.  
  45. int process(int s, int state, fd_set *mask, int highSock);
  46. int nhs(int s, fd_set *mask);
  47. int init(void);
  48.  
  49. /*  state constants  */
  50. #define SCLOSE         0  /*  Need to close the socket  */
  51. #define SINIT        1  /*  Need to initialize connection  */
  52. #define SDATA        2  /*  Need to recieve data and write to disk  */
  53.  
  54. struct timeval NoTime = {0L, 0L};
  55.  
  56. main(int argc, char **argv)
  57. {
  58. int s,            /*  socket to accept connections on, new socket  */
  59.     ns,            /*  new socket      */
  60.     i,            /*  index in for loops  */
  61.     state[FD_SETSIZE],    /*  where we are in communication on all socket  */
  62.     highSock;        /*  the highest open socket  */
  63. fd_set sockmask, mask;     /*  mask of all open sockets, return val  */
  64. long umask;
  65.  
  66.     highSock = s = init();
  67.     FD_ZERO(&sockmask);
  68.     FD_SET(s, &sockmask);
  69.     while(1)
  70.     {
  71.         mask = sockmask;
  72.         umask = SIGBREAKF_CTRL_C;
  73.  
  74.         if(selectwait(highSock+1, &mask, NULL, NULL, NULL,
  75.                   &umask) == -1)
  76.         {
  77.             perror("select");
  78.             goto cleanup;
  79.         }
  80.  
  81.         for(i=0; i <= highSock; i++)
  82.             if(FD_ISSET(i, &mask))
  83.                 if (i == s)
  84.                 {
  85.                     ns = accept(s, NULL, NULL);
  86.                     if(ns != -1)
  87.                     {
  88.                         state[ns] = SINIT;
  89.                         FD_SET(ns, &sockmask);
  90.                         if(ns > highSock)
  91.                             highSock = ns;
  92.                     }
  93.                 } else
  94.                 {
  95.                     state[i] = process(i, state[i], &sockmask, highSock);
  96.                     if(state[i] == SCLOSE)
  97.                     {
  98.                         if(i == highSock)
  99.                             highSock = nhs(i,&sockmask);
  100.                         s_close(i);
  101.                         FD_CLR(i, &sockmask);
  102.                     }
  103.                 }
  104.     }
  105.  
  106. cleanup:
  107.     for(i=0; i<=highSock; i++)
  108.         if( FD_ISSET(i, &sockmask) )
  109.         {
  110.             s_close(i);
  111.         }
  112.     cleanup_sockets();
  113.     CloseLibrary(SockBase);
  114. }
  115.  
  116.  
  117. int nhs(int s, fd_set *mask)
  118. {
  119.     while(s--)
  120.     {
  121.         if(FD_ISSET(s, mask))
  122.             return s;
  123.     }
  124.     return FD_SETSIZE;
  125. }
  126.  
  127.  
  128. int init(void)
  129. {
  130. struct sockaddr_in sin;    /*  socket address (internet) to establish  */
  131. int s,             /*  socket to accept connections on  */
  132.     len = sizeof(sin);
  133.  
  134.     /*  Open Shared Socket library:
  135.     */
  136.         if(SockBase = OpenLibrary( "inet:libs/socket.library", 0L ))
  137.         {
  138.                 setup_sockets( MAXSOCKS, &errno );
  139.     }else
  140.     {
  141.         puts("Can't open socket.library.");
  142.         exit(RETURN_ERROR);
  143.     }
  144.  
  145.     if( (s = socket(AF_INET, SOCK_STREAM, 0)) == -1)
  146.     {
  147.         perror("socket");
  148.         goto cleanup;;
  149.     }
  150.  
  151.     bzero(&sin, len);
  152.     sin.sin_family = AF_INET;
  153.     /*
  154.     **  While prototyping a program, pick an unused port number above
  155.     **  1024 like I did here.  For a real program, assign a name and a
  156.     **  port number above 1024 and stick it in inet:db/servers on all
  157.     **  machines which will use the application.  That way the user can
  158.     **  reconfigure port numbers used by new applications if necessary.
  159.     **  You can modify the server to get the port number from the
  160.     **  database by using code like this (instead of "sin.sin_port=
  161.     **  htons(6666)" below):
  162.     **
  163.     **  struct servent *servptr;
  164.     **  char serv[] = "servicename";
  165.     **
  166.     **  if( (servptr = getservbyname(serv, "tcp")) == NULL)
  167.     **  {
  168.     **      printf("Unknown service %s.  Check inet:db/services.\n",serv);
  169.     **    return RETURN_ERROR;
  170.     **  }
  171.     **  sin.sin_port = servptr->s_port;
  172.     */
  173.     sin.sin_port = htons(6666);
  174.     sin.sin_addr.s_addr = INADDR_ANY;
  175.     if(bind(s, (struct sockaddr *)&sin, len) < 0)
  176.     {
  177.         perror("bind");
  178.         s_close(s);
  179.         goto cleanup;
  180.     }
  181.  
  182.     listen(s,5);
  183.     return s;
  184.  
  185. cleanup:
  186.     cleanup_sockets();
  187.     CloseLibrary(SockBase);
  188.     exit(RETURN_ERROR);
  189. }
  190.  
  191.  
  192. int process(int s, int state, fd_set *mask, int highSock)
  193. {
  194. char buffer[LENGTH];
  195. static int mode[FD_SETSIZE];    /*  AmigaDOS file open modes  */
  196. static BPTR file[FD_SETSIZE];    /*  File handles  */
  197. int n;                /*  number of bytes read/written  */
  198.  
  199.     switch(state)
  200.     {
  201.     case SINIT:
  202.         recv(s, (char *)&(mode[s]), sizeof(int), 0);
  203.         recv(s, buffer, LENGTH, 0);
  204.         if( !(file[s] = Open(buffer, mode[s])) )
  205.         {
  206.         int len;
  207.  
  208.             len = strlen(buffer);
  209.             strncat(buffer, "': ", LENGTH-4);  /*  4 not 3 'cause of nul  */
  210.             Fault(IoErr(), NULL, buffer+len+3, LENGTH-len-4);
  211.             send(s, buffer, strlen(buffer)+1, 0);
  212.             return SCLOSE;
  213.         }
  214.         send(s, "\0", 1, 0);
  215.         if(mode[s] == MODE_NEWFILE)
  216.         {
  217.             return SDATA;
  218.         }
  219. /*  fall through if MODE_OLDFILE  */
  220.     case SDATA:
  221.         if(mode[s] == MODE_OLDFILE)
  222.         {
  223.             while(1)
  224.             {
  225.                 n = Read(file[s], (void *)buffer, LENGTH);
  226.                        if(n <= 0)
  227.                     goto close;
  228.                 if(send(s, buffer, n, 0) < 0)
  229.                     goto close;
  230.             }
  231.         }else
  232.         {
  233.             n = recv(s, buffer, LENGTH, 0);
  234.             if(n <= 0)
  235.                 goto close;
  236.             if(Write(file[s], (void *)buffer, n) < 0)
  237.                 goto close;
  238.             return SDATA;
  239.         }
  240.     default:
  241.         ;
  242.     /*  in a real program, should do something more intellegent here  */
  243.     }
  244. close:
  245.     Close(file[s]);
  246.     return SCLOSE;
  247. }
  248.