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

  1. /*********************************************************************
  2. Project    :    GUSI                -    Grand Unified Socket Interface
  3. File        :    GUSIPPC.cp        -    PPC Sockets
  4. Author    :    Matthias Neeracher
  5. Started    :    18May92                                Language    :    MPW C/C++
  6. Modified    :    02Aug92    MN    Put some further work in
  7.                 03Aug92    MN    Approximately correct, except for sync/async
  8.                 03Aug92    MN    Introduce additional buffering
  9.                 10Aug92    MN    Correct select()
  10.                 30Aug92    MN    Move hasPPC here
  11.                 07Sep92    MN    Implement ioctl()
  12.                 13Sep92    MN    Always complete write
  13.                 06Dec92    MN    Check flags
  14.                 17Dec92    MN    Forgot to clear errno in PPCSocketDomain::socket()
  15.                 07Feb93    MN    New configuration technique
  16.                 20Jun93    MN    Changed sa_constr_ppc
  17.                 01Sep93    MN    Throw out nonbreaking spaces
  18.                 30Dec93    MN    Fiddle with select()
  19. Last        :    30Dec93
  20. *********************************************************************/
  21.  
  22. #include "GUSIPPC_P.h"
  23.  
  24. #include <Errors.h>
  25. #include <ADSP.h>
  26. #include <Devices.h>
  27. #include <GestaltEqu.h>
  28. #include <PLStringFuncs.h>
  29.  
  30. class PPCSocket;                             // That's what this file's all about
  31.  
  32. struct PPCPB {
  33.     PPCParamBlockRec    ppc;
  34.     PPCSocket *            sock;
  35. };
  36.  
  37. class PPCSocket : public Socket    {        
  38.     friend class PPCSocketDomain;    
  39.     friend pascal void PPCReadHellHound(PPCPB * pb);
  40.     friend pascal void PPCWriteHellHound(PPCPB * pb);
  41.  
  42.     enum {
  43.         notBound, 
  44.         notOpen,
  45.         isListening,
  46.         isOpen,
  47.         isAccepted}        status;
  48.     Boolean                nonblocking;
  49.     Boolean                readPending;
  50.     Boolean                writePending;
  51.     Boolean                readShutDown;
  52.     Boolean                writeShutDown;
  53.     LocationNameRec    location;
  54.     PPCPortRec            port;
  55.     LocationNameRec    peerLoc;
  56.     PPCPortRec            peerPort;
  57.     PPCPB                    pb;
  58.     PPCPB    *                rpb;
  59.     RingBuffer *        rb;
  60.     RingBuffer *        wb;
  61.     
  62.                     PPCSocket();
  63.                     PPCSocket(const PPCSocket & acceptFrom);
  64.                     
  65.     virtual         ~PPCSocket();
  66.     
  67.     int            Alloc();
  68.     void            HellHoundsOnMyTrail();
  69. public:
  70.     virtual int    bind(void * name, int namelen);
  71.     virtual int getsockname(void * name, int * namelen);
  72.     virtual int getpeername(void *name, int *namelen);
  73.     virtual int    fcntl(unsigned int cmd, int arg);
  74.     virtual int listen(int qlen);
  75.     virtual int connect(void * address, int addrlen);
  76.     virtual Socket * accept(void * address, int * addrlen);
  77.     virtual int recvfrom(void * buffer, int buflen, int flags, void * from, int * fromlen);
  78.     virtual int sendto(void * buffer, int buflen, int flags, void * to, int tolen);
  79.     virtual int shutdown(int how);
  80.     virtual int select(Boolean * canRead, Boolean * canWrite, Boolean * exception);
  81.     virtual int    ioctl(unsigned int request, void *argp);
  82. };    
  83.  
  84. PPCSocketDomain    PPCSockets;
  85.  
  86. /************************ PPC Toolbox initialization ************************/
  87.  
  88. pascal OSErr PPCInit_P()
  89. {
  90.     OSErr        err;
  91.     long        attr;
  92.         
  93.     if (err = Gestalt(gestaltPPCToolboxAttr, &attr))
  94.         return err;
  95.         
  96.     if (!(attr & gestaltPPCSupportsRealTime))
  97.         err = PPCInit();
  98.  
  99.     return err;
  100. }
  101.  
  102. Feature hasPPC(PPCInit_P);
  103.  
  104. /********************* Link stuffing procedures *********************/
  105.  
  106. #pragma segment GUSIResident
  107.  
  108. pascal void PPCReadHellHound(PPCPB * pb)
  109. {
  110.     if (!pb->sock->rb)                                    // We're closing
  111.         return;
  112.         
  113.     RingBuffer &     buf     =    *pb->sock->rb;
  114.     PPCReadPBRec & p         =    pb->ppc.readParam;
  115.     Boolean &        pend    =    pb->sock->readPending;
  116.     
  117.     if (buf.Locked())
  118.         buf.Later(Deferred(PPCReadHellHound), pb);
  119.     else    {
  120.         buf.Later(nil, nil);
  121.         if (pend) {
  122.             pend    =    false;
  123.             
  124.             if (p.ioResult)    {
  125.                 pb->sock->readShutDown    =    true;
  126.                 
  127.                 return;
  128.             }
  129.             
  130.             buf.Validate(p.actualLength);
  131.         }
  132.         
  133.         if (!buf.Free()) 
  134.             buf.Later(Deferred(PPCReadHellHound), pb);
  135.         else {
  136.             long    max    =    1000000;
  137.             
  138.             p.ioCompletion    =    PPCCompProcPtr(PPCReadHellHound);
  139.             p.bufferPtr        =    buf.Producer(max);
  140.             p.bufferLength    =    max;
  141.             pend                =    true;
  142.             
  143.             PPCReadAsync(&p);
  144.         }
  145.     }
  146. }
  147.  
  148. pascal void PPCWriteHellHound(PPCPB * pb)
  149. {
  150.     if (!pb->sock->wb)                                    // We're closing
  151.         return;
  152.         
  153.     RingBuffer &      buf     =    *pb->sock->wb;
  154.     PPCWritePBRec & p         =    pb->ppc.writeParam;
  155.     Boolean &         pend    =    pb->sock->writePending;
  156.     
  157.     if (buf.Locked())
  158.         buf.Later(Deferred(PPCWriteHellHound), pb);
  159.     else    {
  160.         buf.Later(nil, nil);
  161.         
  162.         if (pend) {
  163.             pend    =    false;
  164.             
  165.             if (p.ioResult)    {
  166.                 pb->sock->writeShutDown    =    true;
  167.                 
  168.                 return;
  169.             }
  170.  
  171.             buf.Invalidate(p.actualLength);
  172.         }
  173.         
  174.         if (!buf.Valid()) 
  175.             buf.Later(Deferred(PPCWriteHellHound), pb);
  176.         else {
  177.             long    max    =    1000000;
  178.             
  179.             p.ioCompletion    =    PPCCompProcPtr(PPCWriteHellHound);
  180.             p.bufferPtr        =    buf.Consumer(max);
  181.             p.bufferLength    =    max;
  182.             p.more            =    false;
  183.             p.userData        =    0;
  184.             p.blockCreator    =    'GU∑I';
  185.             p.blockType        =    'GU∑I';
  186.             pend                =    true;
  187.             
  188.             PPCWriteAsync(&p);
  189.         }
  190.     }
  191. }
  192.  
  193. #pragma segment GUSI
  194.  
  195. /************************ PPCSocket members ************************/
  196.  
  197. PPCSocket::PPCSocket()
  198. {
  199.     status            =    PPCSocket::notBound;
  200.     nonblocking        =    false;
  201.     pb.sock            =    this;
  202.     rpb                =    nil;
  203.     rb                    =    nil;
  204.     wb                    =    nil;
  205.     readPending        =    false;
  206.     writePending    =    false;
  207.     readShutDown    =    false;
  208.     writeShutDown    =    false;
  209. }
  210.  
  211. PPCSocket::PPCSocket(const PPCSocket & acceptFrom)
  212. {
  213.     status            =    PPCSocket::isAccepted;
  214.     nonblocking        =    acceptFrom.nonblocking;
  215.     pb.ppc            =    acceptFrom.pb.ppc;
  216.     pb.sock            =    this;
  217.     rpb                =    nil;
  218.     rb                    =    nil;
  219.     wb                    =    nil;
  220.     readPending        =    false;
  221.     writePending    =    false;
  222.     readShutDown    =    false;
  223.     writeShutDown    =    false;
  224.     location            =    acceptFrom.location;
  225.     port                =    acceptFrom.port;
  226.     peerLoc            =    acceptFrom.peerLoc;
  227.     peerPort            =    acceptFrom.peerPort;
  228. }
  229.  
  230. PPCSocket::~PPCSocket()
  231. {
  232.     if (rb)    {
  233.         delete rb;
  234.         
  235.         rb = nil;
  236.     }
  237.     
  238.     if (wb)    {
  239.         delete wb;
  240.         
  241.         wb = nil;
  242.     }
  243.  
  244.     switch (status) {
  245.     case PPCSocket::isAccepted:
  246.         PPCEndSync(&pb.ppc.endParam);
  247.         
  248.         break;                                        // Don't close the port
  249.     case PPCSocket::isListening:
  250.     case PPCSocket::isOpen:
  251.         PPCEndSync(&pb.ppc.endParam);
  252.  
  253.         /* Fall through */
  254.     case PPCSocket::notOpen:
  255.         PPCCloseSync(&pb.ppc.closeParam);
  256.         /* Fall through */
  257.     case PPCSocket::notBound:
  258.         break;
  259.     }
  260. }
  261.  
  262. int PPCSocket::Alloc()
  263. {
  264.     if (!rpb)
  265.         rpb    =    new PPCPB;
  266.     
  267.     if (!rpb)
  268.         goto error;
  269.     
  270.     rpb->sock    =    this;
  271.     
  272.     if (!rb)
  273.         rb    =    new RingBuffer(2048);
  274.     
  275.     if (!rb)    
  276.         goto error;
  277.     if (!*rb)
  278.         goto errRB;
  279.     
  280.     if (!wb)
  281.         wb =    new RingBuffer(2048);
  282.     
  283.     if (!wb)    
  284.         goto errRB;
  285.     if (!*wb)
  286.         goto errWB;
  287.     
  288.     return 0;
  289.  
  290. errWB:
  291.     delete wb;
  292.     
  293.     wb    =    nil;
  294. errRB:
  295.     delete rb;
  296.     
  297.     rb    =    nil;
  298. error:
  299.     return GUSI_error(ENOMEM);
  300. }
  301.  
  302. void PPCSocket::HellHoundsOnMyTrail()
  303. {
  304.     rpb->ppc.readParam.sessRefNum        =    pb.ppc.startParam.sessRefNum;
  305.     
  306.     PPCReadHellHound(rpb);
  307.     PPCWriteHellHound(&pb);
  308. }
  309.  
  310. int PPCSocket::fcntl(unsigned int cmd, int arg)
  311. {
  312.     switch (cmd)    {
  313.     case F_GETFL:
  314.         if (nonblocking)
  315.             return FNDELAY;
  316.         else
  317.             return 0;
  318.     case F_SETFL:
  319.         if (arg & FNDELAY)
  320.             nonblocking = true;
  321.         else
  322.             nonblocking = false;
  323.             
  324.         return 0;
  325.     default:
  326.         return GUSI_error(EOPNOTSUPP);
  327.     }
  328. }
  329.  
  330. int PPCSocket::ioctl(unsigned int request, void *argp)
  331. {
  332.     switch (request)    {
  333.     case FIONBIO:
  334.         nonblocking    =    (Boolean) *(long *) argp;
  335.         
  336.         return 0;
  337.     case FIONREAD:
  338.         switch(status)    {
  339.         case PPCSocket::isAccepted:
  340.         case PPCSocket::isOpen:
  341.             break;
  342.         default:
  343.             return GUSI_error(ENOTCONN);    
  344.         }
  345.     
  346.         *(unsigned long *) argp    = rb->Valid();
  347.         
  348.         return 0;
  349.     default:
  350.         return GUSI_error(EOPNOTSUPP);
  351.     }
  352. }
  353.  
  354. int PPCSocket::bind(void *sa_name, int)
  355. {
  356.     struct sockaddr_ppc *    addr = (struct sockaddr_ppc *) sa_name;
  357.     
  358.     if (addr->family != AF_PPC)
  359.         GUSI_error(EAFNOSUPPORT);
  360.         
  361.     if (status != PPCSocket::notBound)
  362.         return GUSI_error(EINVAL);
  363.     
  364.     location = addr->location;
  365.     port        = addr->port;
  366.     
  367.     pb.ppc.openParam.ioCompletion        =    nil;
  368.     pb.ppc.openParam.serviceType        =    ppcServiceRealTime;
  369.     pb.ppc.openParam.resFlag            =    0;
  370.     pb.ppc.openParam.portName            =    &port;
  371.     pb.ppc.openParam.locationName        =    &location;
  372.     pb.ppc.openParam.networkVisible    =    true;
  373.     
  374.     switch (PPCOpenSync(&pb.ppc.openParam))    {
  375.     case noErr:
  376.         break;
  377.     case nameTypeErr:
  378.     case badReqErr:
  379.     case badPortNameErr:
  380.     case badLocNameErr:
  381.         return GUSI_error(EINVAL);
  382.     case noGlobalsErr:
  383.         return GUSI_error(ENOMEM);
  384.     case portNameExistsErr:
  385.     case nbpDuplicate:
  386.         return GUSI_error(EADDRINUSE);
  387.     default:
  388.         return GUSI_error(EFAULT);
  389.     }
  390.     
  391.     status =    PPCSocket::notOpen;
  392.     
  393.     return 0;
  394. }
  395.  
  396. int PPCSocket::getsockname(void *name, int *namelen)
  397. {
  398.     struct sockaddr_ppc    addr;
  399.     
  400.     addr.family            =    AF_PPC;
  401.     addr.location        =    location;
  402.     addr.port            =    port;
  403.     
  404.     memcpy(name, &addr, *namelen = min(*namelen, sizeof(struct sockaddr_ppc)));
  405.     
  406.     return 0;
  407. }
  408.  
  409. int PPCSocket::getpeername(void *name, int *namelen)
  410. {
  411.     struct sockaddr_ppc    addr;
  412.     
  413.     addr.family            =    AF_PPC;
  414.     addr.location        =    peerLoc;
  415.     addr.port            =    peerPort;
  416.     
  417.     memcpy(name, &addr, *namelen = min(*namelen, sizeof(struct sockaddr_ppc)));
  418.     
  419.     return 0;
  420. }
  421.  
  422. int PPCSocket::listen(int)
  423. {    
  424.     switch (status)    {
  425.     case PPCSocket::notBound:
  426.         return GUSI_error(EINVAL);
  427.     case PPCSocket::isOpen:
  428.     case PPCSocket::isListening:
  429.         return GUSI_error(EISCONN);
  430.     default:
  431.         break;
  432.     }
  433.     
  434.     pb.ppc.informParam.autoAccept        =    true;
  435.     pb.ppc.informParam.portName            = &peerPort;
  436.     pb.ppc.informParam.locationName     = &peerLoc;
  437.     pb.ppc.informParam.userName            =    nil;
  438.     
  439.     if (PPCInformAsync(&pb.ppc.informParam))
  440.         return GUSI_error(EINVAL);
  441.         
  442.     status = PPCSocket::isListening;
  443.     
  444.     return 0;
  445. }
  446.  
  447. int PPCSocket::connect(void *sa_name, int)
  448. {
  449.     Boolean                         guest;
  450.     struct sockaddr_ppc *    addr = (struct sockaddr_ppc *) sa_name;
  451.     Str32                            uname;
  452.     
  453.     switch (status)    {
  454.     case PPCSocket::notBound:
  455.         return GUSI_error(EINVAL);
  456.     case PPCSocket::isOpen:
  457.     case PPCSocket::isListening:
  458.     case PPCSocket::isAccepted:
  459.         return GUSI_error(EISCONN);
  460.     default:
  461.         break;
  462.     }
  463.     
  464.     if (Alloc())
  465.         return -1;
  466.  
  467.     if (addr->family != AF_PPC)
  468.         GUSI_error(EAFNOSUPPORT);
  469.     
  470.     peerLoc    = addr->location;
  471.     peerPort    = addr->port;
  472.     uname[0] = 0;
  473.         
  474.     pb.ppc.startParam.serviceType        =    ppcServiceRealTime;
  475.     pb.ppc.startParam.resFlag            =    0;
  476.     pb.ppc.startParam.portName            = &peerPort;
  477.     pb.ppc.startParam.locationName     = &peerLoc;
  478.     pb.ppc.startParam.userData            =    0;
  479.     
  480.     if (StartSecureSession(&pb.ppc.startParam, uname, true, true, &guest, "\p"))
  481.         return GUSI_error(EINVAL);
  482.         
  483.     status                                     =     PPCSocket::isOpen;
  484.     
  485.     HellHoundsOnMyTrail();
  486.     
  487.     return 0;
  488. }
  489.  
  490. Socket * PPCSocket::accept(void * address, int * addrlen)
  491. {
  492.     PPCSocket    *    newsock;
  493.     
  494.     if (status != PPCSocket::isListening)
  495.         return (Socket *) GUSI_error_nil(ENOTCONN);
  496.  
  497.     if (nonblocking && pb.ppc.informParam.ioResult == 1)
  498.         return (Socket *) GUSI_error_nil(EWOULDBLOCK);
  499.         
  500.     SPINP(pb.ppc.informParam.ioResult == 1, SP_MISC, 0);
  501.  
  502.     if (pb.ppc.informParam.ioResult)
  503.         return (Socket *) GUSI_error_nil(EFAULT);
  504.     
  505.     newsock    =    new PPCSocket(*this);
  506.  
  507.     if (!newsock)
  508.         return (Socket *) GUSI_error_nil(ENOMEM);
  509.         
  510.     if (newsock->Alloc())    {
  511.         delete newsock;
  512.         
  513.         return (Socket *) GUSI_error_nil(ENOMEM);
  514.     }
  515.     
  516.     newsock->HellHoundsOnMyTrail();
  517.                                                     
  518.     if (address && addrlen)
  519.         getpeername(address, addrlen);
  520.  
  521.     pb.ppc.informParam.autoAccept        =    true;
  522.     pb.ppc.informParam.portName        = &peerPort;
  523.     pb.ppc.informParam.locationName     = &peerLoc;
  524.     pb.ppc.informParam.userName        =    nil;
  525.     
  526.     PPCInformAsync(&pb.ppc.informParam);
  527.         
  528.     return newsock;
  529. }
  530.  
  531. int PPCSocket::recvfrom(void * buffer, int buflen, int flags, void * from, int *)
  532. {
  533.     long    len    =    buflen;
  534.     
  535.     if (from)
  536.         return GUSI_error(EOPNOTSUPP);
  537.     if (flags)
  538.         return GUSI_error(EOPNOTSUPP);
  539.     
  540.     switch(status)    {
  541.     case PPCSocket::isAccepted:
  542.     case PPCSocket::isOpen:
  543.         break;
  544.     default:
  545.         return GUSI_error(ENOTCONN);    
  546.     }
  547.     
  548.     if (!rb->Valid())    
  549.         if (readShutDown)
  550.             return 0;
  551.         else if (nonblocking)
  552.             return GUSI_error(EWOULDBLOCK);
  553.         else
  554.             SPIN(!rb->Valid(), SP_STREAM_READ, 0);
  555.     
  556.     rb->Consume(Ptr(buffer), len);
  557.     
  558.     return len;
  559. }
  560.  
  561. int PPCSocket::sendto(void * buffer, int buflen, int flags, void * to, int)
  562. {
  563.     long    len    =    buflen;
  564.     long    done    =    0;
  565.     
  566.     if (to)
  567.         return GUSI_error(EOPNOTSUPP);
  568.     if (flags)
  569.         return GUSI_error(EOPNOTSUPP);
  570.     
  571.     switch(status)    {
  572.     case PPCSocket::isAccepted:
  573.     case PPCSocket::isOpen:
  574.         break;
  575.     default:
  576.         return GUSI_error(ENOTCONN);    
  577.     }
  578.     
  579.     if (writeShutDown)
  580.         return GUSI_error(ESHUTDOWN);
  581.     
  582.     if (!wb->Free())
  583.         if (nonblocking)
  584.             return GUSI_error(EWOULDBLOCK);
  585.         
  586.     for (;;) {
  587.         wb->Produce(Ptr(buffer), len);
  588.         
  589.         done        +=    len;
  590.         
  591.         if (nonblocking)
  592.             break;
  593.         
  594.         buflen    -=    int(len);
  595.         
  596.         if (!buflen)
  597.             break;
  598.         
  599.         buffer     =    Ptr(buffer) + len;
  600.         len        =    buflen;
  601.         
  602.         SPIN(!wb->Free(), SP_STREAM_WRITE, 0);
  603.     }
  604.     
  605.     return done;
  606. }
  607.  
  608. int PPCSocket::shutdown(int how)
  609. {
  610.     if (how < 0 || how > 2)
  611.         return GUSI_error(EINVAL);
  612.     
  613.     if (how)
  614.         writeShutDown    =    true;
  615.     if (!(how & 1))
  616.         readShutDown    =    true;
  617.         
  618.     return 0;
  619. }
  620.  
  621. int PPCSocket::select(Boolean * canRead, Boolean * canWrite, Boolean *)
  622. {
  623.     int    goodies     =     0;
  624.     
  625.     if (canRead)
  626.         switch (status) {
  627.         case PPCSocket::isListening:
  628.             if (pb.ppc.informParam.ioResult != 1) {
  629.                 *canRead =     true;
  630.                 ++goodies;
  631.             }
  632.             break;
  633.         case PPCSocket::isAccepted:
  634.         case PPCSocket::isOpen:
  635.             if (rb->Valid() || readShutDown) {
  636.                 *canRead =     true;
  637.                 ++goodies;
  638.             } 
  639.             break;
  640.         default:
  641.             *canRead =     true;
  642.             ++goodies;
  643.             break;
  644.         }
  645.     
  646.     if (canWrite)
  647.         switch (status) {
  648.         case PPCSocket::isAccepted:
  649.         case PPCSocket::isOpen:
  650.             if (wb->Free()) {
  651.                 *canWrite = true;
  652.                 ++goodies;
  653.             }
  654.             break;
  655.         default:
  656.             *canWrite = true;
  657.             ++goodies;
  658.             break;
  659.         }
  660.     
  661.     return goodies;
  662. }
  663.  
  664. /********************* PPCSocketDomain member **********************/
  665.  
  666. extern "C" void GUSIwithPPCSockets()
  667. {
  668.     PPCSockets.DontStrip();
  669. }
  670.  
  671. PPCSocketDomain::PPCSocketDomain()
  672.     :    SocketDomain(AF_PPC)    
  673. {
  674. }
  675.  
  676. Socket * PPCSocketDomain::socket(int type, short)
  677. {
  678.     PPCSocket * sock    =    nil;
  679.     
  680.     errno = 0;
  681.     
  682.     if (!hasPPC)
  683.         GUSI_error(EOPNOTSUPP);
  684.     else 
  685.         switch (type)    {
  686.         case SOCK_STREAM:
  687.             sock = new PPCSocket();
  688.             break;
  689.         default:
  690.             GUSI_error(ESOCKTNOSUPPORT);
  691.         }    
  692.     
  693.     if (sock && errno)    {
  694.         delete sock;
  695.         
  696.         return nil;
  697.     } else
  698.         return sock;
  699. }
  700.  
  701. static sa_constr_ppc *    CurConstr;
  702.  
  703. static pascal Boolean GUSIBrowseFilter(LocationNamePtr, PortInfoPtr port)
  704. {
  705.     if (CurConstr->flags & PPC_CON_MATCH_NAME)
  706.         if (PLstrcmp(port->name.name, CurConstr->match.name))
  707.             return false;
  708.     if (CurConstr->flags & PPC_CON_MATCH_TYPE)
  709.         if (port->name.portKindSelector != ppcByString || PLstrcmp(port->name.u.portTypeStr, CurConstr->match.u.portTypeStr))
  710.             return false;
  711.     
  712.     return true;
  713. }
  714.  
  715. int PPCSocketDomain::choose(int, char * prompt, void * constraint, int flags, void * name, int * namelen)
  716. {
  717.     sockaddr_ppc            addr;
  718.     char *                    end;
  719.     Str255                    promp;
  720.     StringPtr                nbp    = nil;
  721.     PortInfoRec                info;
  722.     static sa_constr_ppc constr;
  723.     
  724.     if (flags & (CHOOSE_NEW | CHOOSE_DIR))
  725.         return GUSI_error(EINVAL);
  726.         
  727.     end         =     (char *) memccpy(promp+1, prompt, 0, 254);
  728.     promp[0]    =    end-(char *)promp-2;
  729.     CurConstr=    (sa_constr_ppc *) constraint;
  730.     
  731.     if (!CurConstr || !(CurConstr->flags & PPC_CON_NEWSTYLE)) {
  732.         if (CurConstr && ((char *) constraint)[0]) {
  733.             constr.flags    =    PPC_CON_NEWSTYLE + PPC_CON_MATCH_NBP;
  734.             nbp                =    StringPtr(constraint);
  735.         } else
  736.             constr.flags     =    PPC_CON_NEWSTYLE;
  737.         
  738.         CurConstr    =    &constr;
  739.     } else if (CurConstr->flags & PPC_CON_MATCH_NBP)
  740.         nbp = CurConstr->nbpType;
  741.     
  742.     if (
  743.         PPCBrowser(
  744.             promp, 
  745.             "\p", 
  746.             false, 
  747.             &addr.location, 
  748.             &info, 
  749.             (CurConstr->flags & (PPC_CON_MATCH_NAME | PPC_CON_MATCH_TYPE)) ? &GUSIBrowseFilter : PPCFilterProcPtr(nil),
  750.             nbp ? nbp : "\pPPCToolBox")
  751.     )
  752.         return GUSI_error(EINTR);
  753.  
  754.     addr.family    =    AF_PPC;
  755.     addr.port    =    info.name;
  756.     
  757.     memcpy(name, &addr, *namelen = min(*namelen, sizeof(sockaddr_ppc)));
  758.     
  759.     return 0;
  760. }
  761.