home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Applications / Portable Patmos 1.1 / patmos-src / src / sock_utl.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-01-19  |  9.0 KB  |  423 lines  |  [TEXT/R*ch]

  1. /*
  2.  * BSD-style socket emulation library for the Mac
  3.  * Original author: Tom Milligan
  4.  * Current author: Charlie Reiman - creiman@ncsa.uiuc.edu
  5.  *
  6.  * This source file is placed in the public domian.
  7.  * Any resemblance to NCSA Telnet, living or dead, is purely coincidental.
  8.  *
  9.  *      National Center for Supercomputing Applications
  10.  *      152 Computing Applications Building
  11.  *      605 E. Springfield Ave.
  12.  *      Champaign, IL  61820
  13.  */
  14.  
  15. #ifdef USEDUMP
  16. # pragma load "Socket.dump"
  17. #else
  18. # include <Events.h>
  19. # include <Types.h>
  20. # include <Memory.h>
  21. # include <Stdio.h>
  22. # include <OSUtils.h>
  23.  
  24. # include <s_types.h>
  25. # include <neti_in.h>
  26. # include <neterrno.h>
  27. # include <s_file.h>
  28. # include <s_ioctl.h>
  29. # include <s_socket.h>
  30. # include <s_time.h>
  31. # include <s_uio.h>
  32.  
  33. # include "sock_str.h"
  34. # include "sock_int.h"
  35. #endif
  36.  
  37. #include <StdLib.h>
  38.  
  39. extern SocketPtr sockets;
  40. extern AllPb *pbList;
  41. extern short pbLast;
  42. extern StreamHashEntPtr streams;
  43. extern SpinFn spinroutine;
  44.  
  45. long errno_long; /* same as errno, but of known length */
  46.  
  47. /*
  48.  * sock_init() - initialize everything.
  49.  * BUG NOTE: returns error codes, but no one that calls it actually checks the return
  50.  * codes. probably bad.
  51.  */
  52. int sock_init()
  53. {
  54.     OSErr io;
  55.     int i;
  56.     
  57.     if (sockets != NULL)
  58.         return 0;
  59.  
  60.     sock_find_shep((StreamPtr) NULL);        /* load resident segment */
  61.             
  62.     /*
  63.      * call up driver
  64.      */
  65.     
  66.     xOpenDriver();
  67.     
  68. #if SOCK_UTIL_DEBUG >= 2
  69.     dprintf("sock_init: first time through\n");
  70.     dprintf("sock_init: allocating %d bytes for %d socket records\n",
  71.             NUM_SOCKETS * sizeof(SocketRecord),NUM_SOCKETS);
  72. #endif
  73.  
  74.     /* allocate storage for socket records */
  75.     sockets = (SocketPtr)NewPtrClear(NUM_SOCKETS * sizeof(SocketRecord));
  76.     if (sockets == NULL)
  77.         return(sock_err(ENOMEM));
  78.         
  79.     /* allocate storage for pbs */
  80.     pbList = (AllPb *)NewPtrClear(NUM_PBS * sizeof (AllPb));
  81.     if ( pbList == NULL )
  82.         return sock_err(ENOMEM);
  83.  
  84.     /* allocate storage for stream->socket hash table */
  85.     streams = (StreamHashEntPtr)NewPtrClear(NUM_SOCKETS * sizeof(StreamHashEnt));
  86.     if ( streams == NULL )
  87.         return(sock_err(ENOMEM));
  88.     
  89.     /* initialize them */
  90.     for (i=0; i<NUM_SOCKETS; i++)
  91.     {
  92.         sock_clear_fd(i);
  93.     }
  94.     
  95.     /* load the MacTCP name server resolver */
  96. #if SOCK_UTIL_DEBUG >= 2
  97.     dprintf("sock_init: loading name server resolver\n");
  98. #endif
  99.  
  100.     io = OpenResolver(NULL);
  101.     
  102. #if SOCK_UTIL_DEBUG >= 1
  103.     if (io != noErr)
  104.         dprintf("sock_init: failed to load name server resolver code %d\n",io);
  105.     else
  106.         dprintf("sock_init: loaded name server ok.\n");
  107. #endif
  108.  
  109.     /* establish our clean up man */
  110. //    atexit(sock_close_all);
  111.     
  112. #if SOCK_UTIL_DEBUG >= 1
  113.     dprintf("sock_init: exiting.\n");
  114. #endif
  115. }
  116.  
  117. /*
  118.  * sock_close_all() - Close all sockets (aborting their connections) and
  119.  *                    release dynamic storage.
  120.  */
  121. void sock_close_all()
  122. {
  123.     int s;
  124.     SocketPtr sp;
  125.     TCPiopb        *tpb;
  126.     UDPiopb        *upb;
  127.  
  128.     for (s = 0 ; s < NUM_SOCKETS ; ++s) 
  129.     {
  130.         sp = sockets+s;
  131.         if (sp->status == SOCK_STATUS_USED) 
  132.         {
  133.             switch(sp->protocol) 
  134.             {
  135.                 case IPPROTO_UDP:
  136.                     upb = sock_fetch_pb(sp);        /* must succeed */
  137.                     (void) xUDPRelease(sp);
  138.                     break;
  139.                     
  140.                 case IPPROTO_TCP:
  141.                     tpb = sock_fetch_pb(sp);
  142.                     (void) xTCPRelease(tpb);
  143.                     break;
  144.             }
  145.             sock_clear_fd(s);
  146.         }
  147.     }
  148.     DisposPtr((Ptr)sockets);
  149.     DisposPtr((Ptr)streams);
  150.     DisposPtr((Ptr)pbList);
  151.     
  152.     /* release name server resources */
  153.     (void) CloseResolver();
  154. }
  155.  
  156. /*
  157.  *    sock_free_fd()
  158.  *
  159.  *    Get the next free file descriptor >= f.  Return -1 if none available.
  160.  */
  161. int sock_free_fd(
  162.     int f)
  163. {
  164.     int s;
  165.  
  166.     for (s = f; s < NUM_SOCKETS; s++)
  167.           if (! is_used(sockets+s))
  168.             return(s);
  169.     return(-1);
  170. }
  171.  
  172. /*
  173.  *    sock_dup_fd() - duplicate a socket table entry. Very dangerous (ie. dumb) routine.
  174.  *  IMPORTANT: It is up to the caller to straighten out the StreamHash table
  175.  *  to reflect the new situation.  Nasty things may happen if s/he doesn't.
  176.  */
  177. void sock_dup_fd(
  178.     int    s,
  179.     int    s1)
  180. {
  181.     BlockMove((Ptr)(sockets+s), (Ptr)(sockets+s1), sizeof(SocketRecord));    
  182.     sock_init_fd(s1);
  183. }
  184.  
  185. /*
  186.  *    sock_clear_fd() - Clear out a socket table entry freeing any 
  187.  *                    storage attached to it.
  188.  *  
  189.  *                    Then re-initialize it for reuse.
  190.  */
  191. void sock_clear_fd(
  192.     int s)
  193. {
  194.     SocketPtr sp = sockets+s;
  195.     StreamHashEntPtr shep;
  196.     
  197.     if ((shep=sock_find_shep(sp->stream))!=NULL)    /* in hash table */
  198.         shep->stream = -1;                    /* mark as deleted */
  199.         
  200.     bzero(sp, sizeof(SocketRecord));
  201.     sp->sa.sin_family = AF_UNSPEC;
  202.     sp->status &= ~SOCK_STATUS_USED;
  203.  
  204.     sock_init_fd(s);
  205. }
  206.  
  207.     
  208. /*
  209.  * Close relative of sock_find_shep, sock_new_shep returns a StreamHashEntPtr
  210.  * that is unused and most appropriate for the passed stream.
  211.  */
  212. StreamHashEntPtr sock_new_shep(StreamPtr newStream)
  213.     {
  214.     StreamHashEntPtr    shep;
  215.     int        counter,start;
  216.     
  217.     /* start at hash point */
  218.     start = counter = (newStream & (SOCKETS_MASK << 3) ) >> 3;    /* extract some arbitrary bits */
  219.     shep = streams + counter;
  220.     do
  221.          {
  222.         /*
  223.          * scan till we find entry or unused or deleted slot.
  224.          */
  225.         if ( (shep->stream == newStream) || (shep->stream == (StreamPtr) NULL) || 
  226.             (shep->stream == -1) )
  227.             break;
  228.         else
  229.             {
  230.             counter = (counter+1) & SOCKETS_MASK;
  231.             if (counter)
  232.                 shep++;
  233.             else
  234.                 shep = streams;
  235.             }
  236.         }
  237.     while(counter != start);
  238.     
  239.     if ( (shep->stream == (StreamPtr) NULL ) || (shep->stream == -1 ) )
  240.         return shep;
  241.     else
  242.         return NULL;    /* error: already in table or table full. Should never happen. (right...) */
  243.     }
  244.     
  245. /*
  246.  * sock_fetch_pb grabs a pb from the global pool, making sure it isn't
  247.  * used. It may block for a long time if all pb are in progress. Declared
  248.  * void * because I'm getting sick of typecasting every goddamn little pointer
  249.  */ 
  250. void *sock_fetch_pb(SocketPtr sp)
  251.     {
  252.     AllPb    *pb;
  253.     do
  254.         {
  255.         pbLast ++;
  256.         if (pbLast == NUM_PBS)
  257.             pbLast = 0;
  258.         
  259.         pb = pbList + pbLast;
  260.         } 
  261.     while ( pb->tcp.ioResult == inProgress );
  262.     
  263.     pb->tcp.tcpStream = sp->stream;        /* all the calls have the stream at the same offset */
  264.                                         /* thank god. */
  265.     return ((void *)pb);
  266.     }
  267.  
  268.  
  269. void sock_init_fd(
  270.     int s)
  271. {
  272.     SocketPtr sp = sockets+s;
  273.  
  274.     sp->fd = s;
  275. }
  276.  
  277.  
  278. /*
  279.  * Convert a MacTCP err code into a unix error code, if needed. Otherwise it
  280.  * will pass thru unmolested.
  281.  */
  282. int sock_err( int MacTCPerr )
  283.     {
  284.     switch ( MacTCPerr )
  285.         {
  286.         case ipBadLapErr:
  287.         case ipBadCnfgErr:
  288.         case ipNoCnfgErr:
  289.         case ipLoadErr:
  290.         case ipBadAddr:
  291.             errno = ENXIO;            /* device not configured */    /* a cheap cop out */
  292.             break;
  293.             
  294.         case connectionClosing:
  295.             errno = ESHUTDOWN;        /* Can't send after socket shutdown */
  296.             break;
  297.  
  298.         case connectionExists:
  299.             errno = EISCONN;        /* Socket is already connected */
  300.             break;
  301.  
  302.         case connectionTerminated:
  303.             errno = ENOTCONN;        /* Connection reset by peer */  /* one of many possible */
  304.             break;
  305.  
  306.         case openFailed:
  307.             errno = ECONNREFUSED;    /* Connection refused */
  308.             break;
  309.  
  310.         case duplicateSocket:        /* technically, duplicate port */
  311.             errno = EADDRINUSE;        /* Address already in use */
  312.             break;
  313.             
  314.         case ipDestDeadErr:
  315.             errno = EHOSTDOWN;        /* Host is down */
  316.             break;
  317.             
  318.         case ipRouteErr:
  319.             errno = EHOSTUNREACH;    /* No route to host */
  320.             break;
  321.             
  322.         default:
  323.             errno = MacTCPerr;        /* cop out; an internal err, unix err, or no err */
  324.             break;
  325.         }
  326. #if    SOCK_UTIL_DEBUG >= 1
  327.     dprintf("SOCK  error %d\n", errno);
  328. #endif
  329.  
  330.     errno_long = errno;
  331.     return (-1);
  332.     }
  333.  
  334. /*
  335.  *  sock_copy_addr
  336.  */
  337. void sock_copy_addr(
  338.     void *from,
  339.     void *to,
  340.     Int4 *tolen)
  341. {
  342.     *tolen = min(*tolen, sizeof(struct sockaddr_in));
  343.     BlockMove((Ptr)from, (Ptr)to, *tolen);
  344. }
  345.  
  346.  
  347. #if SOCK_UTIL_DEBUG > 1
  348. /*
  349.  * print the socket records.
  350.  */
  351. void sock_dump()
  352. {
  353.     int s;
  354.     char title[20];
  355.  
  356.     for (s=0; s<NUM_SOCKETS; s++) 
  357.     {
  358.         if (! is_used(sockets+s))
  359.             continue;
  360.         sprintf(title,"%2d",s);
  361.         sock_print(title,sockets+s);
  362.     }
  363. }
  364.  
  365. void sock_print(
  366.     char *title,
  367.     SocketPtr sp)
  368. {
  369.     dprintf("%s: %08x %s %08x addr %08x/%d %08x/%d state %d/%d err %d\n",
  370.             title, sp, 
  371.             (sp->protocol == IPPROTO_UDP ? "udp" : "tcp"),
  372.             (sp->protocol == IPPROTO_UDP ? sp->pb.udp.udpStream : sp->pb.tcp.tcpStream),
  373.             sp->sa.sin_addr.s_addr,sp->sa.sin_port,
  374.             sp->peer.sin_addr.s_addr,sp->peer.sin_port,
  375.             sp->sstate,xTCPState(&sp->pb),
  376.             sp->asyncerr);
  377. }
  378. #endif
  379.  
  380.  
  381.  
  382. #pragma segment SOCK_RESIDENT
  383. /*
  384.  * sock_find_shep returns a StreamHashEntPtr for the passed
  385.  * stream. Will return 0 if the stream doesn't exits.
  386.  */
  387. StreamHashEntPtr sock_find_shep(StreamPtr theStream)
  388.     {
  389.     StreamHashEntPtr    shep;
  390.     int     counter,start;
  391.     
  392.     if (!goodptr(theStream))                /* DO NOT CHANGE THESE TWO LINES! */
  393.         return NULL;                        /* used to load the resident segment */
  394.         
  395.     /* start at hash point */
  396.     start = counter = (theStream & (SOCKETS_MASK << 3) ) >> 3;    /* extract a bunch of arbitrary bits */
  397.     shep = streams + counter;
  398.     do
  399.          {
  400.         /*
  401.          * scan till we find entry or unused slot. Uses linear
  402.          * collision resolution because it's too complicated to
  403.          * do anything else for this small of a hash table.
  404.          */
  405.         if ( (shep->stream == theStream) || (shep->stream == (StreamPtr) NULL))
  406.             break;
  407.         else
  408.             {
  409.             counter = (counter+1) & SOCKETS_MASK;
  410.             if (counter)
  411.                 shep++;
  412.             else
  413.                 shep = streams;
  414.             }
  415.         }
  416.     while(counter != start);
  417.     
  418.     if ( shep->stream == theStream ) /* found it */
  419.         return shep;
  420.     else
  421.         return NULL;
  422.     }
  423.