home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Libraries / GUSI / GUSIUnix.cp < prev    next >
Encoding:
Text File  |  1993-12-30  |  23.6 KB  |  1,144 lines  |  [TEXT/MPS ]

  1. /*********************************************************************
  2. Project    :    GUSI                -    Grand Unified Socket Interface
  3. File        :    GUSIUnix.cp        -    Implementation of Unix domain calls
  4. Author    :    Matthias Neeracher
  5. Started    :    31Mar92                                Language    :    MPW C/C++
  6. Modified    :    31Mar92    MN    unix domain socket calls
  7.                 18Apr92    MN    On with the show, good health to you
  8.                 20Apr92    MN    C++ rewrite
  9.                 24Apr92    MN    Introducing UnixStreamSocket, UnixDgramSocket
  10.                 21May92    MN    Implemented select()
  11.                 13Jul92    MN    In spirit of Unix implementation, use file, not hash table
  12.                 26Jul92    MN    Error in using memccpy()
  13.                 10Aug92    MN    select() for accept/connect
  14.                 12Sep92    MN    Renamed Paths.h to GUSIFSp_P.h
  15.                 13Sep92    MN    Always complete write
  16.                 15Nov92    MN    Rename GUSIFSp_P.h to TFileSpec.h (there we go again)
  17.                 17Jan93    MN    Be more careful about User interrupts
  18.                 07Feb93    MN    New configuration scheme
  19. Last        :    07Feb93
  20. *********************************************************************/
  21.  
  22. #include "GUSI_P.h"
  23. #include "TFileSpec.h"
  24.  
  25. #include <Processes.h>
  26. #include <Resources.h>
  27. #include <SysEqu.h>
  28. #include <Finder.h>
  29.  
  30. #pragma segment GUSIUnix
  31.  
  32. class UnixSocketDomain : public SocketDomain {
  33. public:
  34.     UnixSocketDomain()    :    SocketDomain(AF_UNIX)    {        }
  35.  
  36.     virtual Socket *     socket(int type, short protocol);
  37.     virtual int         choose(
  38.                                 int         type, 
  39.                                 char *     prompt, 
  40.                                 void *     constraint,        
  41.                                 int         flags,
  42.                                  void *     name, 
  43.                                 int *     namelen);
  44. };
  45.  
  46. static UnixSocketDomain    UnixSockets;
  47.  
  48. class UnixSocket;                                    // That's what this file's all about
  49. class UnixStreamSocket;
  50. class UnixDgramSocket;
  51.  
  52. struct UnixSocketAddr : TFileSpec {
  53.     Boolean        valid;
  54.     Boolean        owned;
  55.     
  56.     UnixSocketAddr();
  57.     UnixSocketAddr(TFileSpec spec);
  58. };
  59.  
  60. // The interface of this class should never be changed now the first version 
  61. // of GUSI is released. All further changes should be done by making a subclass.
  62. // The Version() method must return *increasing* version numbers.
  63.  
  64. // Version 2 adds support for aborting a connection, see below
  65.  
  66. class UnixChannel : public SingleObject {
  67.     UnixSocketAddr    address;
  68.     
  69.     void UnBind();
  70. protected:
  71.     UnixSocket *     sock;
  72. public:
  73.     UnixChannel    *    nextListener;
  74.     int                errno;
  75.     
  76.     UnixChannel(UnixSocket * owner);
  77.     virtual ~UnixChannel();
  78.     
  79.     virtual int            Version();
  80.     
  81.     virtual Boolean    Bind(UnixSocketAddr & addr);
  82.     virtual Boolean    Connect(UnixChannel * ch);
  83.     virtual Boolean    Accept(UnixChannel * ch);
  84.  
  85.     virtual int            Read(void * buffer, int len);
  86.     virtual int            Write(void * buffer, int len);
  87.     virtual int            Send(UnixChannel * from, void * buffer, int len);
  88.     virtual int         ReadAvail();
  89.     virtual int            WriteAvail();
  90.     virtual int            BufSize();
  91.     virtual void         DiscardRead(int len);
  92.     virtual void         ShutDown(int how);
  93.     virtual void        Disconnect();
  94.     
  95.     virtual int            GUSI_error(int err);
  96.  
  97.     virtual UnixSocketAddr & 
  98.                             Address();
  99. };
  100.  
  101. class UnixChannel2 : public UnixChannel {
  102. public:
  103.     UnixChannel2(UnixSocket * owner);
  104.  
  105.     virtual int            Version();
  106.     virtual void        Orphan();
  107.     virtual void        AbortConnect(UnixChannel * ch);
  108. };
  109.  
  110. class UnixSocket : public Socket {
  111.     friend class UnixChannel;
  112.     friend class UnixChannel2;
  113. protected:
  114.     char                status;
  115.     char                state;
  116.     Boolean            nonblocking;
  117.     char                protocol;
  118.     Ptr                readBuf;
  119.     short                readBufSize;
  120.     short                readPos;
  121.     short             validBytes;
  122.     short                curListener;
  123.     short                maxListener;
  124.     UnixChannel *    chan;
  125.     UnixChannel    *    peer;
  126.     UnixChannel *    firstListener;
  127.     UnixChannel *    lastListener;
  128.  
  129.                     UnixSocket(short prot);
  130.     void            defaultbind();
  131. public:
  132.     enum {channelUnknown, channelAncient, channelSupportsConnAbort};
  133.     
  134.     virtual int    bind(void * name, int namelen);
  135.     virtual int getsockname(void * name, int * namelen);
  136.     virtual int getpeername(void * name, int * namelen);
  137.     virtual int    fcntl(unsigned int cmd, int arg);
  138.     virtual int    ioctl(unsigned int request, void *argp);
  139.     virtual int shutdown(int how);
  140.     virtual int select(Boolean * canRead, Boolean * canWrite, Boolean * exception);
  141.     virtual         ~UnixSocket();
  142. };
  143.  
  144. class UnixStreamSocket : public UnixSocket {
  145.     friend class UnixSocketDomain;
  146.     
  147.                     UnixStreamSocket();
  148. public:
  149.     virtual int listen(int qlen);
  150.     virtual int connect(void * address, int addrlen);
  151.     virtual Socket * accept(void * address, int * addrlen);
  152.     virtual int recvfrom(void * buffer, int buflen, int flags, void * from, int * fromlen);
  153.     virtual int sendto(void * buffer, int buflen, int flags, void * to, int tolen);
  154.     
  155.     virtual         ~UnixStreamSocket();
  156. };
  157.  
  158. class UnixDgramSocket : public UnixSocket {
  159.     friend class UnixSocketDomain;
  160.     
  161.                     UnixDgramSocket();
  162. public:
  163.     virtual int connect(void * address, int addrlen);
  164.     virtual int recvfrom(void * buffer, int buflen, int flags, void * from, int * fromlen);
  165.     virtual int sendto(void * buffer, int buflen, int flags, void * to, int tolen);
  166.     
  167.     virtual         ~UnixDgramSocket();
  168. };
  169.  
  170. struct UnixSocketID {
  171.     UnixChannel    *            chan;
  172.     
  173.     AddrBlock                machine;
  174.     ProcessSerialNumber    process;
  175.     
  176.                 UnixSocketID()                                        {}
  177.                 UnixSocketID(UnixChannel * ch);
  178.     Boolean    Validate();
  179. };
  180.  
  181. /********************** UnixSocketAddr members ***********************/
  182.  
  183. inline UnixSocketAddr::UnixSocketAddr() 
  184.     : valid(false), owned(true)            
  185. {
  186. }
  187.  
  188. inline UnixSocketAddr::UnixSocketAddr(TFileSpec spec) 
  189.     : TFileSpec(spec), valid(false), owned(true)            
  190. {
  191. }
  192.  
  193. /************************ UnixSocket members ************************/
  194.  
  195. static UnixSocketAddr * CanonizeName(void * name, int len);
  196. static void                 UncanonizeName(UnixSocketAddr & name, void * addr, int * addrlen);
  197. static UnixChannel *     LookupName(UnixSocketAddr name);
  198.  
  199. UnixSocket::UnixSocket(short prot)
  200. {
  201.     GUSI_error(0);
  202.     
  203.     readBufSize        =    DEFAULT_BUFFER_SIZE;
  204.     status            =    SOCK_STATUS_USED;
  205.     state                =    SOCK_STATE_UNCONNECTED;
  206.     nonblocking        =    false;
  207.     protocol            =    prot;
  208.     readPos            =    0;
  209.     validBytes        =    0;
  210.     curListener        =    0;
  211.     maxListener        =    0;
  212.     firstListener    =    nil;
  213.     lastListener    =    nil;
  214.     chan                =    nil;
  215.     peer                =    nil;
  216.     readBuf            =    NewPtr(readBufSize);
  217.     
  218.     if (!readBuf)
  219.         GUSI_error(ENOMEM);
  220. }
  221.  
  222. UnixSocket::~UnixSocket()
  223. {
  224.     if (readBuf)
  225.         DisposPtr(readBuf);
  226.     
  227.     if (protocol == SOCK_STREAM)
  228.         if (peer)
  229.             peer->Disconnect();
  230.         else 
  231.             while (firstListener) {
  232.                 firstListener->Disconnect();
  233.                 
  234.                 firstListener = firstListener->nextListener;
  235.             }
  236.         
  237.     if (chan)
  238.         delete chan;
  239. }
  240.  
  241. void UnixSocket::defaultbind()
  242. {
  243.     struct sockaddr_un    addr;
  244.     
  245.     addr.sun_family    =    AF_UNIX;
  246.     tmpnam(addr.sun_path);
  247.     
  248.     bind(&addr, strlen(addr.sun_path)+2);
  249. }
  250.  
  251. int UnixSocket::fcntl(unsigned int cmd, int arg)
  252. {
  253.     switch (cmd)    {
  254.     case F_GETFL:
  255.         if (nonblocking)
  256.             return FNDELAY;
  257.         else
  258.             return 0;
  259.     case F_SETFL:
  260.         if (arg & FNDELAY)
  261.             nonblocking = true;
  262.         else
  263.             nonblocking = false;
  264.             
  265.         return 0;
  266.     default:
  267.         return GUSI_error(EOPNOTSUPP);
  268.     }
  269. }
  270.  
  271. int UnixSocket::ioctl(unsigned int request, void *argp)
  272. {
  273.     switch (request)    {
  274.     case FIONBIO:
  275.         nonblocking    =    (Boolean) *(long *) argp;
  276.         
  277.         return 0;
  278.     case FIONREAD:
  279.         if (chan)
  280.             *(long *) argp = chan->ReadAvail();
  281.         else
  282.             *(long *) argp    = 0;
  283.  
  284.         return 0;
  285.     default:
  286.         return GUSI_error(EOPNOTSUPP);
  287.     }
  288. }
  289.  
  290. int UnixSocket::bind(void *sa_name, int sa_namelen)
  291. {
  292.     UnixSocketAddr *    addr;
  293.     
  294.     if (chan && chan->Address().valid)
  295.             return GUSI_error(EINVAL);
  296.     
  297.     addr    =    CanonizeName(sa_name, sa_namelen);
  298.     
  299.     if (!addr)
  300.         return -1;
  301.     
  302.     if (LookupName(*addr))
  303.         return GUSI_error(EADDRINUSE);
  304.  
  305.     if (!chan && !(chan = new UnixChannel2(this)))
  306.         return GUSI_error(ENOMEM);
  307.     
  308.     if (!chan->Bind(*addr))
  309.         return GUSI_error(ENOMEM);
  310.     
  311.     return 0;
  312. }
  313.  
  314. int UnixSocket::getsockname(void *name, int *namelen)
  315. {
  316.     UncanonizeName(chan->Address(), name, namelen);
  317.     
  318.     return 0;
  319. }
  320.  
  321. int UnixSocket::getpeername(void *name, int *namelen)
  322. {
  323.     if (!peer)
  324.         return GUSI_error(ENOTCONN);
  325.         
  326.     UncanonizeName(peer->Address(), name, namelen);
  327.     
  328.     return 0;
  329. }
  330.  
  331. int UnixSocket::select(Boolean * canRead, Boolean * canWrite, Boolean *)
  332. {
  333.     int    goodies = 0;
  334.     
  335.     if (canRead)
  336.         if ((state == SOCK_STATE_LIS_CON) || !chan || chan->ReadAvail())    {
  337.             *canRead    =     true;
  338.             ++goodies;
  339.         } 
  340.     
  341.     if (canWrite)
  342.         if (!peer || peer->WriteAvail())    {
  343.             *canWrite    =     true;
  344.             ++goodies;
  345.         } 
  346.     
  347.     return goodies;
  348. }
  349.  
  350. int UnixSocket::shutdown(int how)
  351. {
  352.     if (!chan)
  353.         return GUSI_error(ENOTCONN);
  354.  
  355.     chan->ShutDown(how);
  356.     
  357.     return 0;
  358. }
  359.  
  360. /********************* UnixStreamSocket members *********************/
  361.  
  362. UnixStreamSocket::UnixStreamSocket()
  363.     :    UnixSocket(SOCK_STREAM)
  364. {
  365. }
  366.  
  367. UnixStreamSocket::~UnixStreamSocket()
  368. {
  369. }
  370.  
  371. int UnixStreamSocket::listen(int qlen)
  372. {
  373.     if (state != SOCK_STATE_UNCONNECTED)
  374.         return GUSI_error(EISCONN);
  375.         
  376.     state            =    SOCK_STATE_LISTENING;
  377.     maxListener    =    qlen;
  378.     
  379.     return 0;
  380. }
  381.  
  382. int UnixStreamSocket::connect(void *sa_name, int sa_namelen)
  383. {
  384.     UnixSocketAddr *    addr;
  385.     UnixChannel    *    other;
  386.     
  387.     if (peer)
  388.         return GUSI_error(EISCONN);
  389.     
  390.     addr    =    CanonizeName(sa_name, sa_namelen);
  391.     
  392.     if (!addr)
  393.         return -1;
  394.     
  395.     other = LookupName(*addr);
  396.     
  397.     if (!other)
  398.         return GUSI_error(EADDRNOTAVAIL);
  399.  
  400.     if (!chan && !(chan = new UnixChannel2(this)))
  401.         return GUSI_error(ENOMEM);
  402.     
  403.     if (!chan->Address().valid)
  404.         defaultbind();
  405.     
  406.     if (!other->Connect(chan))
  407.         return GUSI_error(ECONNREFUSED);
  408.         
  409.     state    =    SOCK_STATE_CONNECTING;
  410.     
  411.     if (nonblocking)
  412.         return GUSI_error(EINPROGRESS);
  413.         
  414.     SAFESPIN(state == SOCK_STATE_CONNECTING, SP_MISC, 0);
  415.     
  416.     if (state == SOCK_STATE_CONNECTED)
  417.         return 0;
  418.     else if (!errno)
  419.         return GUSI_error(ECONNREFUSED);
  420.         
  421.     // User abort, a tricky situation. What we do depends on the peer channel
  422.     // version.
  423.     
  424.     if (other->Version() >= channelSupportsConnAbort)    // The new way
  425.         ((UnixChannel2 *) other)->AbortConnect(chan);    // This type cast is safe
  426.     else                                                                // The old way
  427.         ((UnixChannel2 *) chan)->Orphan();                    // This type cast is safe            
  428.     
  429.     return -1;
  430. }
  431.  
  432. Socket * UnixStreamSocket::accept(void * address, int * addrlen)
  433. {
  434.     UnixStreamSocket *    newsock;
  435.     
  436.     if (state != SOCK_STATE_LISTENING && state != SOCK_STATE_LIS_CON)
  437.         return (Socket *) GUSI_error_nil(ENOTCONN);
  438.  
  439. restart:    
  440.     if (!curListener)
  441.         if (nonblocking)
  442.             return (Socket *) GUSI_error_nil(EWOULDBLOCK);
  443.         else
  444.             SPINP(state == SOCK_STATE_LISTENING, SP_MISC, 0);
  445.             
  446.     if (!curListener)
  447.             return (Socket *) GUSI_error_nil(EFAULT);                    // I *really* hope this won't happen 
  448.  
  449.     newsock    =    new UnixStreamSocket;
  450.     
  451.     if (!newsock)
  452.         return (Socket *) GUSI_error_nil(ENOMEM);
  453.     
  454.     newsock->state            =    SOCK_STATE_CONNECTED;
  455.     newsock->peer            =    firstListener;
  456.     newsock->chan            =    new UnixChannel2(newsock);
  457.     
  458.     if (!newsock->chan)    {
  459.         delete newsock;
  460.         
  461.         return (Socket *) GUSI_error_nil(ENOMEM);
  462.     }
  463.     
  464.     newsock->chan->Address()            =    chan->Address();
  465.     newsock->chan->Address().owned    =    false;
  466.     
  467.     firstListener    =    firstListener->nextListener;
  468.     
  469.     if (!firstListener)
  470.         lastListener = nil;
  471.     
  472.     if (!--curListener)
  473.         state = SOCK_STATE_LISTENING;
  474.     
  475.     if (newsock->peer->Accept(newsock->chan) == -1)    {
  476.         newsock->peer = nil;
  477.         
  478.         delete newsock;
  479.         
  480.         goto restart;
  481.     }
  482.  
  483.     UncanonizeName(newsock->peer->Address(), address, addrlen);
  484.     
  485.     return newsock;
  486. }
  487.  
  488. int UnixStreamSocket::recvfrom(void * buffer, int buflen, int flags, void * from, int *)
  489. {
  490.     int                avail;
  491.     
  492.     if (flags || from)
  493.         return GUSI_error(EOPNOTSUPP);
  494.     if (!chan || !peer)
  495.         return GUSI_error(ENOTCONN);    
  496.         
  497.     if ((avail = chan->ReadAvail()) == -1)
  498.         if (chan->errno == ESHUTDOWN)
  499.             return 0;
  500.         else
  501.             return GUSI_error(chan->errno);
  502.     
  503.     if (nonblocking && !avail)
  504.         return GUSI_error(EWOULDBLOCK);
  505.     
  506.     errno    =    0;
  507.     SPIN(!(avail = chan->Read(buffer, buflen)), SP_STREAM_READ, 0);
  508.     if (avail == -1 && !errno)
  509.         if (chan->errno == ESHUTDOWN)
  510.             return 0;
  511.         else
  512.             GUSI_error(chan->errno);
  513.             
  514.     return avail;
  515. }
  516.  
  517. int UnixStreamSocket::sendto(void * buffer, int buflen, int flags, void * to, int)
  518. {
  519.     int     avail;
  520.     int    done;
  521.     
  522.     if (flags || to)
  523.         return GUSI_error(EOPNOTSUPP);
  524.     if (!chan || !peer)
  525.         return GUSI_error(ENOTCONN);    
  526.         
  527.     if ((avail = peer->WriteAvail()) == -1)
  528.         return GUSI_error(peer->errno);
  529.     
  530.     if (nonblocking && !avail)
  531.         return GUSI_error(EWOULDBLOCK);
  532.     
  533.     for (
  534.         done = errno = 0; 
  535.         !errno && buflen; 
  536.         buflen -= avail, buffer = Ptr(buffer) + avail
  537.     )    {
  538.         SPIN(!(avail = peer->Write(buffer, buflen)), SP_STREAM_WRITE, 0);
  539.         if (avail == -1) {
  540.             if (!errno)
  541.                 GUSI_error(peer->errno);
  542.                 
  543.             break;
  544.         } 
  545.         
  546.         done += avail;
  547.         
  548.         if (nonblocking)
  549.             break;
  550.     }
  551.             
  552.     return done ? done : (buflen ? -1 : 0);
  553. }
  554.  
  555. /********************* UnixDgramSocket members **********************/
  556.  
  557. UnixDgramSocket::UnixDgramSocket()
  558.     :    UnixSocket(SOCK_DGRAM)
  559. {
  560. }
  561.  
  562. UnixDgramSocket::~UnixDgramSocket()
  563. {
  564. }
  565.  
  566. int UnixDgramSocket::connect(void *sa_name, int sa_namelen)
  567. {
  568.     UnixSocketAddr *    addr;
  569.     
  570.     addr    =    CanonizeName(sa_name, sa_namelen);
  571.     
  572.     if (!addr)
  573.         return -1;
  574.     
  575.     peer = LookupName(*addr);
  576.     
  577.     if (!peer)
  578.         return GUSI_error(EADDRNOTAVAIL);
  579.     
  580.     state    =    SOCK_STATE_CONNECTED;
  581.     
  582.     return 0;
  583. }
  584.  
  585. int UnixDgramSocket::recvfrom(void * buffer, int buflen, int flags, void * from, int * fromlen)
  586. {
  587.     UnixChannel *     partner;
  588.     int                length;
  589.     int                avail;
  590.     
  591.     if (flags)
  592.         return GUSI_error(EOPNOTSUPP);
  593.     if (!chan || !chan->Address().valid)
  594.         return GUSI_error(ENOTCONN);    // fuck UNIX semantics; it's impossible for another
  595.                                                 // socket to communicate with this one, anyway
  596.         
  597.     if ((avail = chan->ReadAvail()) == -1)
  598.         return GUSI_error(chan->errno);
  599.     
  600.     // Datagram sockets communicate the sender's address in the first 4 bytes
  601.     // The transfer will be atomic, so only one spin is needed
  602.     
  603.     if (nonblocking && !avail)
  604.         return GUSI_error(EWOULDBLOCK);
  605.     
  606.     errno    =    0;
  607.     SPIN(!(avail = chan->Read(&partner, sizeof(UnixChannel *))), SP_DGRAM_READ, 0);
  608.     if (errno)
  609.         return -1;
  610.     else if (avail == -1)
  611.         return GUSI_error(chan->errno);
  612.     else if (avail < sizeof(UnixChannel *))
  613.         return GUSI_error(EFAULT);
  614.  
  615.     if ((avail = chan->Read(&length, sizeof(long))) == -1)
  616.         return GUSI_error(chan->errno);
  617.     
  618.     buflen = min(buflen, length);
  619.     
  620.     if ((avail = chan->Read(buffer, buflen)) == -1)
  621.         return GUSI_error(chan->errno);
  622.         
  623.     chan->DiscardRead(length - buflen);
  624.     
  625.     UncanonizeName(partner->Address(), from, fromlen);
  626.         
  627.     return avail;
  628. }
  629.  
  630. int UnixDgramSocket::sendto(void * buffer, int buflen, int flags, void * to, int tolen)
  631. {
  632.     UnixSocketAddr *    addr;
  633.     UnixChannel *         partner;
  634.     int                    length;
  635.     int                    avail;
  636.     
  637.     if (flags)
  638.         return GUSI_error(EOPNOTSUPP);
  639.     if (!chan)
  640.         chan = new UnixChannel2(this);
  641.     if (peer)    
  642.         partner    =    peer;
  643.     else {
  644.         addr    =    CanonizeName(to, tolen);
  645.         
  646.         if (!addr)
  647.             return -1;
  648.         
  649.         partner = LookupName(*addr);
  650.         
  651.         if (!partner)
  652.             return GUSI_error(EADDRNOTAVAIL);
  653.     }
  654.             
  655.     length    =    sizeof(UnixChannel *) + sizeof(int) + buflen;
  656.     
  657.     if (length > partner->BufSize())
  658.         return GUSI_error(EMSGSIZE);
  659.     if ((avail = partner->WriteAvail()) == -1)
  660.         return GUSI_error(partner->errno);
  661.     if (avail < length)
  662.         if (nonblocking)
  663.             return GUSI_error(EWOULDBLOCK);
  664.         else
  665.             SPIN((avail=partner->WriteAvail()) != -1 && avail<length, SP_DGRAM_WRITE, 0);
  666.     
  667.     if (avail == -1)
  668.         return GUSI_error(partner->errno);
  669.         
  670.     errno    =    0;
  671.     SPIN(!(avail = partner->Send(chan, buffer, buflen)), SP_DGRAM_WRITE, 0);
  672.     if (errno)
  673.         return -1;
  674.     else if (avail == -1)
  675.         return GUSI_error(partner->errno);
  676.         
  677.     return avail;
  678. }
  679.  
  680. /*********************** UnixChannel members ************************/
  681.  
  682. UnixChannel::UnixChannel(UnixSocket * owner)
  683.     :    address(UnixSocketAddr()), sock(owner)
  684. {
  685. }
  686.  
  687. UnixChannel::~UnixChannel()
  688. {
  689.     if (address.valid)
  690.         UnBind();
  691. }
  692.  
  693. void UnixChannel::UnBind()
  694. {
  695.     if (address.owned)
  696.         HDelete(address.vRefNum, address.parID, address.name);        
  697. }
  698.  
  699. int UnixChannel::Version()
  700. {
  701.     return 1;
  702. }
  703.  
  704. Boolean UnixChannel::Bind(UnixSocketAddr & addr)
  705. {
  706.     short                resFile;
  707.     short                oldResFile    =    CurResFile();
  708.     Handle            ID;
  709.     UnixSocketID    me(this);
  710.     FInfo                info;
  711.     
  712.     address    =    addr;
  713.     
  714.     if (PtrToHand(&me, &ID, sizeof(UnixSocketID)))
  715.         return false;
  716.         
  717.     HDelete(address.vRefNum, address.parID, address.name);
  718.     HCreate(address.vRefNum, address.parID, address.name, 'GU∑I', '∑OCK');
  719.     HCreateResFile(address.vRefNum, address.parID, address.name);
  720.     resFile = HOpenResFile(address.vRefNum, address.parID, address.name, fsRdWrPerm);
  721.     
  722.     if (resFile == -1)    {
  723.         DisposeHandle(ID);
  724.         return false;
  725.     }
  726.     
  727.     AddResource(ID, 'GU∑I', GUSIRsrcID, "\p");
  728.     
  729.     if (ResError()) {
  730.         CloseResFile(resFile);
  731.         HDelete(address.vRefNum, address.parID, address.name);
  732.         DisposeHandle(ID);
  733.         UseResFile(oldResFile);
  734.         return false;
  735.     }
  736.  
  737.     CopyIconFamily(*(short *) CurApRefNum, GUSIRsrcID, resFile, kCustomIconResource);
  738.     
  739.     CloseResFile(resFile);
  740.     UseResFile(oldResFile);
  741.  
  742.     HGetFInfo(address.vRefNum, address.parID, address.name, &info);
  743.     info.fdFlags    |=    (1 << 10);
  744.     info.fdFlags    &= ~(1 << 8);
  745.     HSetFInfo(address.vRefNum, address.parID, address.name, &info);
  746.         
  747.     return true;
  748. }
  749.  
  750. Boolean UnixChannel::Connect(UnixChannel * ch)
  751. {
  752.     if (sock->curListener >= sock->maxListener)
  753.         return false;
  754.         
  755.     switch (sock->state)    {
  756.     case SOCK_STATE_LISTENING:
  757.         sock->state    =    SOCK_STATE_LIS_CON;
  758.         // Fall through
  759.     case SOCK_STATE_LIS_CON:
  760.         if (!sock->lastListener)
  761.             sock->firstListener    =    ch;
  762.         else
  763.             sock->lastListener->nextListener = ch;
  764.             
  765.         sock->lastListener = ch;
  766.         ++sock->curListener;
  767.         
  768.         return true;
  769.     default:
  770.         return false;
  771.     }
  772. }
  773.  
  774. Boolean UnixChannel::Accept(UnixChannel * ch)
  775. {
  776.     if (!sock)
  777.         return true;
  778.         
  779.     sock->peer    =    ch;
  780.     sock->state    =    SOCK_STATE_CONNECTED;
  781.     
  782.     return true;
  783. }
  784.  
  785. int UnixChannel::Read(void * buffer, int len)
  786. {
  787.     if (sock->status & SOCK_STATUS_NOREAD)
  788.         return GUSI_error(ESHUTDOWN);
  789.         
  790.     Ptr    startBuf    = (Ptr) buffer;
  791.     int    section;
  792.         
  793.     if (sock->validBytes > 0)    {
  794.         section    =    sock->readBufSize-sock->readPos;
  795.         
  796.         if (section > sock->validBytes)
  797.             section = sock->validBytes;
  798.         if (section > len)
  799.             section = len;
  800.         
  801.         BlockMove(sock->readBuf+sock->readPos, buffer, section);
  802.         
  803.         buffer                = (char *) buffer + section;
  804.         sock->readPos        +=    section;
  805.         sock->validBytes    -=    section;
  806.         len                     -= section;
  807.         
  808.         if (sock->readPos == sock->readBufSize)
  809.             sock->readPos    =    0;
  810.     } else if (sock->state != SOCK_STATE_CONNECTED)
  811.         return GUSI_error(ESHUTDOWN);
  812.         
  813.     if (len > 0 && sock->validBytes > 0)    {
  814.         section     =    (len > sock->validBytes) ? sock->validBytes : len;
  815.         
  816.         BlockMove(sock->readBuf, buffer, section);
  817.         
  818.         buffer                = (char *) buffer + section;
  819.         sock->readPos        +=    section;
  820.         sock->validBytes    -=    section;
  821.     }
  822.         
  823.     return (char *) buffer-startBuf;        
  824. }
  825.  
  826. int UnixChannel::Write(void * buffer, int len)
  827. {    
  828.     if (!sock || (sock->status & SOCK_STATUS_NOWRITE))
  829.         return GUSI_error(ESHUTDOWN);
  830.  
  831.     Ptr    startBuf    =    (Ptr) buffer;
  832.     int    avail        =    sock->readBufSize - sock->validBytes;
  833.     int    section    =    avail - sock->readPos;
  834.         
  835.     if (section > 0)    {
  836.         if (section > len)
  837.             section = len;
  838.             
  839.         BlockMove(buffer, sock->readBuf+sock->readPos+sock->validBytes, section);
  840.         
  841.         buffer                 = (char *) buffer + section;
  842.         sock->validBytes    +=    section;
  843.         len                     -= section;
  844.         avail                    -=    section;
  845.     }
  846.     
  847.     if (len > 0 && avail > 0)    {
  848.         section     =    (len > avail) ? avail : len;
  849.         
  850.         BlockMove(buffer, sock->readBuf+sock->readPos-avail, section);
  851.         
  852.         buffer                 = (char *) section;
  853.         sock->validBytes    +=    section;
  854.     }
  855.         
  856.     return (char *) buffer-startBuf;        
  857. }
  858.  
  859. int UnixChannel::Send(UnixChannel * from, void * buffer, int len)
  860. {
  861.     int length    =    sizeof(UnixChannel *) + sizeof(int) + len;
  862.  
  863.     if (sock->peer && sock->peer != from)
  864.         return GUSI_error(ECONNREFUSED);
  865.     
  866.     if (WriteAvail() < length)
  867.         return 0;
  868.     
  869.     Write(&from, sizeof(UnixChannel *));
  870.     Write(&len, sizeof(int));
  871.     
  872.     return Write(buffer, len);
  873. }
  874.  
  875. int UnixChannel::ReadAvail()
  876. {
  877.     if (sock->status & SOCK_STATUS_NOREAD)
  878.         return GUSI_error(ESHUTDOWN);
  879.         
  880.     return sock->validBytes;
  881. }
  882.  
  883. int UnixChannel::WriteAvail()
  884. {
  885.     if (!sock || (sock->status & SOCK_STATUS_NOWRITE))
  886.         return GUSI_error(ESHUTDOWN);
  887.         
  888.     return sock->readBufSize - sock->validBytes;
  889. }
  890.  
  891. int UnixChannel::BufSize()
  892. {
  893.     return sock->readBufSize;
  894. }
  895.  
  896. void UnixChannel::ShutDown(int how)
  897. {
  898.     switch(how) {
  899.     case 0 : 
  900.         sock->status |= SOCK_STATUS_NOREAD;
  901.         break;
  902.     case 1 : 
  903.         sock->status |= SOCK_STATUS_NOWRITE;
  904.         break;
  905.     case 2 :
  906.         sock->status |= SOCK_STATUS_NOREAD | SOCK_STATUS_NOWRITE;
  907.     }
  908. }
  909.  
  910. void UnixChannel::DiscardRead(int len)
  911. {
  912.     if (sock->validBytes <= len)    {
  913.         sock->validBytes    =    0;
  914.         sock->readPos        =    0;
  915.     } else {
  916.         sock->validBytes    -=    len;
  917.         sock->readPos        = (sock->readPos+len) % sock->readBufSize;
  918.     }
  919. }
  920.  
  921. void UnixChannel::Disconnect()
  922. {
  923.     if (sock) {
  924.         sock->peer    =    nil;
  925.         sock->state    =    SOCK_STATE_UNCONNECTED;
  926.     }
  927. }
  928.  
  929. int UnixChannel::GUSI_error(int err)
  930. {
  931.     errno    =    err;
  932.  
  933.     return -1;
  934. }
  935.  
  936. UnixSocketAddr & UnixChannel::Address()
  937. {
  938.     return address;
  939. }
  940.  
  941. /*********************** UnixChannel2 members ************************/
  942.  
  943. UnixChannel2::UnixChannel2(UnixSocket * owner)
  944.     :    UnixChannel(owner)
  945. {
  946. }
  947.  
  948. int UnixChannel2::Version()
  949. {
  950.     return 2;
  951. }
  952.  
  953. void UnixChannel2::Orphan()
  954. {
  955.     // Sever ties to owner
  956.     
  957.     sock->chan    =    nil;
  958.     sock             =     nil;
  959. }
  960.  
  961. void UnixChannel2::AbortConnect(UnixChannel * ch)
  962. {
  963.     UnixChannel    * prev = nil;
  964.     
  965.     for (UnixChannel * chan = sock->firstListener; chan; chan = chan->nextListener) {
  966.         if (chan == ch)    {    // Got it !
  967.             if (prev)
  968.                 prev->nextListener    =    chan->nextListener;
  969.             else
  970.                 sock->firstListener    =    chan->nextListener;
  971.             
  972.             if (!chan->nextListener)
  973.                 sock->lastListener    =    prev;
  974.             
  975.             if (!--sock->curListener)
  976.                 sock->state = SOCK_STATE_LISTENING;
  977.             
  978.             break;
  979.         }
  980.         prev = chan;
  981.     }
  982. }
  983.  
  984. /********************* UnixSocketID members **********************/
  985.  
  986. UnixSocketID::UnixSocketID(UnixChannel * ch)
  987.     : chan(ch)
  988. {
  989.     short    net;
  990.     short node;
  991.     
  992.     AppleTalkIdentity(net, node);
  993.     
  994.     machine.aNet    =    net;
  995.     machine.aNode    =    node;
  996.     machine.aSocket=    0;
  997.     
  998.     if (!hasProcessMgr || GetCurrentProcess(&process))    {
  999.         process.highLongOfPSN = kNoProcess;
  1000.         process.lowLongOfPSN = kNoProcess;
  1001.     }    
  1002. }
  1003.  
  1004. Boolean UnixSocketID::Validate()
  1005. {
  1006.     UnixSocketID    me(nil);
  1007.     ProcessInfoRec    info;
  1008.     
  1009.     if (memcmp(&machine, &me.machine, sizeof(AddrBlock)))
  1010.         return false;
  1011.         
  1012.     if (!hasProcessMgr)
  1013.         return (!process.highLongOfPSN && !process.lowLongOfPSN);
  1014.     
  1015.     info.processInfoLength    =    sizeof(ProcessInfoRec);
  1016.     info.processName            =    nil;
  1017.     info.processAppSpec        =    nil;
  1018.     
  1019.     return !GetProcessInformation(&process, &info);
  1020. }
  1021.  
  1022. /********************* UnixSocketDomain member **********************/
  1023.  
  1024. extern "C" void GUSIwithUnixSockets()
  1025. {
  1026.     UnixSockets.DontStrip();
  1027. }
  1028.  
  1029. Socket * UnixSocketDomain::socket(int type, short)
  1030. {
  1031.     UnixSocket * sock    =    nil;
  1032.     
  1033.     switch (type)    {
  1034.     case SOCK_STREAM:
  1035.         sock = new UnixStreamSocket();
  1036.         break;
  1037.     case SOCK_DGRAM:
  1038.         sock = new UnixDgramSocket();
  1039.         break;
  1040.     default:
  1041.         GUSI_error(ESOCKTNOSUPPORT);
  1042.     }    
  1043.     
  1044.     if (sock && errno)    {
  1045.         delete sock;
  1046.         
  1047.         return nil;
  1048.     } else
  1049.         return sock;
  1050. }
  1051.  
  1052. int UnixSocketDomain::choose(int, char * prompt, void *, int flags, void * name, int * namelen)
  1053. {
  1054.     struct sockaddr_un *    addr = (sockaddr_un *) name;
  1055.     sa_constr_file            constr;
  1056.     
  1057.     addr->sun_family    = AF_UNIX;
  1058.  
  1059.     constr.numTypes    =    1;
  1060.     constr.types[0]    =    '∑OCK';
  1061.     
  1062.     *namelen -= 2;
  1063.     if (FileSockets.choose(0, prompt, &constr, flags, addr->sun_path, namelen))
  1064.         return -1;
  1065.     
  1066.     *namelen += 2;
  1067.     
  1068.     return 0;
  1069. }
  1070.  
  1071.  
  1072. /************************* Name conversions *************************/
  1073.  
  1074. static char                    canonPath[120];
  1075. static UnixSocketAddr    canonAddr;
  1076.  
  1077. static UnixSocketAddr * CanonizeName(void * name, int len)
  1078. {
  1079.     struct sockaddr_un *    addr = (sockaddr_un *) name;
  1080.     
  1081.     if (!name || !len || addr->sun_family != AF_UNIX)    {
  1082.         GUSI_error(EAFNOSUPPORT);
  1083.         
  1084.         return nil;
  1085.     }
  1086.     
  1087.     len -= 2;
  1088.     memcpy(canonPath, addr->sun_path, len);
  1089.     
  1090.     canonPath[len] =     0;
  1091.     canonAddr        =    TFileSpec(canonPath);
  1092.     
  1093.     if (canonAddr.Error())
  1094.         return nil;
  1095.     else
  1096.         canonAddr.valid    =    true;
  1097.         
  1098.     return &canonAddr;
  1099. }
  1100.  
  1101. static void UncanonizeName(UnixSocketAddr & name, void * addr, int * addrlen)
  1102. {
  1103.     struct sockaddr_un *    uaddr = (sockaddr_un *) addr;
  1104.     char    *                     path    =    name.FullPath();
  1105.     char     *                     end;
  1106.     
  1107.     if (!addr || *addrlen < sizeof(short))    {
  1108.         if (addrlen)
  1109.             *addrlen = 0;
  1110.         
  1111.         return;
  1112.     }
  1113.     
  1114.     *addrlen             -= 2;
  1115.     uaddr->sun_family =     AF_UNIX;
  1116.     
  1117.     if (end = (char *) memccpy(uaddr->sun_path, path, 0, *addrlen))
  1118.         *addrlen = end-uaddr->sun_path-1;
  1119.     
  1120.     *addrlen             +=     2;
  1121. }
  1122.  
  1123. static UnixChannel * LookupName(UnixSocketAddr name)
  1124. {
  1125.     short                file;
  1126.     Handle            hdl;
  1127.     UnixChannel *    cur    =    nil;
  1128.     UnixSocketID    id;
  1129.  
  1130.     file    =    HOpenResFile(name.vRefNum, name.parID, name.name, fsRdPerm);
  1131.  
  1132.     if (file != -1)    {
  1133.         if (hdl = Get1Resource('GU∑I', GUSIRsrcID))    {
  1134.             id = **(UnixSocketID **) hdl;
  1135.             
  1136.             if (id.Validate())
  1137.                 cur = id.chan;
  1138.         }
  1139.         CloseResFile(file);
  1140.     }
  1141.     
  1142.     return cur;
  1143. }
  1144.