home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Libraries / GUSI 1.4.1 / GUSI / GUSIPAP.cp < prev    next >
Encoding:
Text File  |  1994-05-01  |  12.5 KB  |  696 lines  |  [TEXT/MPS ]

  1. /*********************************************************************
  2. Project    :    GUSI                -    Grand Unified Socket Interface
  3. File        :    GUSIPAP.cp        -    Printer Access Protocol Sockets
  4. Author    :    Matthias Neeracher
  5.  
  6.     Based on code from 
  7.         Sak Wathanasin <sw@nan.co.uk>
  8.         David A. Holzgang, _Programming the LaserWriter_, Addison-Wesley 1991
  9.         Apple's Q&A stack
  10.     
  11. Language    :    MPW C/C++
  12.  
  13. $Log: GUSIPAP.cp,v $
  14. Revision 1.2  1994/05/01  23:30:32  neeri
  15. Enable recvfrom with non-NULL from address.
  16.  
  17. Revision 1.1  1994/02/25  02:29:50  neeri
  18. Initial revision
  19.  
  20. Revision 0.4  1993/12/30  00:00:00  neeri
  21. Fiddle with select
  22.  
  23. Revision 0.3  1993/09/01  00:00:00  neeri
  24. Throw out nonbreaking spaces
  25.  
  26. Revision 0.2  1993/04/03  00:00:00  neeri
  27. close() has to do shutdown as well.
  28.  
  29. Revision 0.1  1993/03/01  00:00:00  neeri
  30. Be more clever about handling shutdowns
  31.  
  32. *********************************************************************/
  33.  
  34. #include "GUSI_P.h"
  35.  
  36. #include <Resources.h>
  37. #include <AppleTalk.h>
  38. #include <Errors.h>
  39. #include <Folders.h>
  40. #include <PLStringFuncs.h>
  41. #include <TextUtils.h>
  42. #include <Timer.h>
  43.  
  44. #include <sys/types.h>
  45.  
  46. const long NiceDoggie    =    20;        // Rest Hellhound for 20msec
  47. const long MaxPAP            =    4096;        //    Maximum transaction size
  48.  
  49. class PAPSocket;                             // That's what this file's all about
  50.  
  51. class PAPID {
  52.     void        GetPAPCode(short vRefNum, long dirID, StringPtr name);
  53.     
  54.     Handle    papCode;
  55.     Handle    papName;    
  56. public:
  57.     PAPID();
  58.     
  59.     ~PAPID();
  60.     
  61.     Ptr    Code()            {    return *papCode;    }
  62.     Ptr    Name()            {    return *papName;    }
  63.     operator void *()        {    return papCode;    }
  64. };
  65.  
  66. struct PAPPB {
  67.     TMTask            timer;
  68.     short                length;
  69.     short                eof;
  70.     short                state;
  71.     PAPSocket *        sock;
  72. };
  73.  
  74. struct PAPStatusRec { 
  75.     long      systemStuff;
  76.    char      statusstr[256];
  77. };
  78.         
  79.  
  80. class PAPSocket : public Socket    {        
  81.     friend class PAPSocketDomain;    
  82.     friend pascal void PAPReadTimer();
  83.     friend pascal void PAPWriteTimer();
  84.     friend pascal void PAPReadHellHound(PAPPB *);
  85.     friend pascal void PAPWriteHellHound(PAPPB *);
  86.  
  87.     enum {
  88.         opening,
  89.         open,
  90.         closed
  91.     }                        status;
  92.     Boolean                nonblocking;
  93.     Boolean                readPending;
  94.     Boolean                writePending;
  95.     Boolean                readShutDown;
  96.     Boolean                writeShutDown;
  97.     short                    papRefNum;
  98.     RingBuffer *        rb;
  99.     RingBuffer *        wb;
  100.     long                    ourA5;
  101.     PAPID                    papID;
  102.     PAPStatusRec        papStatus;
  103.     PAPPB                    wpb;
  104.     PAPPB                    rpb;
  105.     
  106.                     PAPSocket();
  107.                     
  108.     virtual         ~PAPSocket();
  109.     
  110.     int            Powerup();
  111. public:
  112.     virtual int    fcntl(unsigned int cmd, int arg);
  113.     virtual int    recvfrom(void * buffer, int buflen, int flags, void * from, int *);
  114.     virtual int sendto(void * buffer, int buflen, int flags, void * to, int);
  115.     virtual int select(Boolean * canRead, Boolean * canWrite, Boolean * exception);
  116.     virtual int    ioctl(unsigned int request, void *argp);
  117.     virtual int shutdown(int how);
  118. };    
  119.  
  120. class PAPSocketDomain : public DeviceSocketDomain {
  121. public:
  122.     PAPSocketDomain()    :    DeviceSocketDomain(AF_PAP)    {    }
  123.     
  124.     virtual     Socket * open(const char * filename, int oflag);
  125. };
  126.  
  127. PAPSocketDomain    PAPSockets;
  128.  
  129. /***************************** PAP glue *****************************/
  130.  
  131. pascal short PAPOpen(
  132.     short *             refNum, 
  133.     char *             printerName,
  134.     short             flowQuantum, 
  135.     PAPStatusRec * statusBuf, 
  136.     short *            compState,
  137.     Ptr                papCode
  138. )    =    {0x205F, 0x4EA8, 0x0000};
  139.  
  140. pascal short PAPRead(
  141.     short                refNum, 
  142.     char *            buffer,
  143.     short *            length, 
  144.     short *            eof,
  145.     short *            compState,
  146.     Ptr                papCode
  147. )    =    {0x205F, 0x4EA8, 0x0004};
  148.  
  149. pascal short PAPWrite(
  150.     short                 refNum,
  151.      char *            buffer,
  152.      short                length,
  153.      short                eof,
  154.      short *            compState,
  155.     Ptr                papCode
  156. )    =    {0x205F, 0x4EA8, 0x0008};
  157.  
  158. pascal short PAPStatus(
  159.     char    *            printerName,
  160.      PAPStatusRec *    statusBuff,
  161.      AddrBlock *        netAddr,
  162.     Ptr                papCode
  163. )    =    {0x205F, 0x4EA8, 0x000C};
  164.  
  165. pascal short PAPClose(
  166.      short                refNum,
  167.     Ptr                papCode
  168. )    =    {0x205F, 0x4EA8, 0x0010};
  169.  
  170. pascal short PAPUnload(
  171.     Ptr                papCode
  172. )    =    {0x205F, 0x4EA8, 0x0014};    
  173.  
  174. /********************* Link stuffing procedures *********************/
  175.  
  176. #pragma segment GUSIResident
  177.  
  178. PAPPB * GetPAPInfo() = 0x2009;                    // MOVE.L A1,D0
  179.  
  180. pascal void PAPReadTimer()
  181. {
  182.     PAPPB *    pb        =    GetPAPInfo();
  183.     long        oldA5    =    SetA5(pb->sock->ourA5);
  184.     
  185.     PAPReadHellHound(pb);
  186.     
  187.     SetA5(oldA5);
  188. }
  189.  
  190. pascal void PAPWriteTimer()
  191. {
  192.     PAPPB *    pb        =    GetPAPInfo();
  193.     long        oldA5    =    SetA5(pb->sock->ourA5);
  194.     
  195.     PAPWriteHellHound(pb);
  196.     
  197.     SetA5(oldA5);
  198. }
  199.  
  200. pascal void PAPReadHellHound(PAPPB * pb)
  201. {
  202.     if (pb->state > 0) {
  203.         PrimeTime(QElemPtr(pb), NiceDoggie);        // See you again 
  204.         
  205.         return;
  206.     }
  207.     
  208.     if (!pb->sock->rb)                                    // We're closing
  209.         return;
  210.     
  211.     PAPSocket &        sock    =    *pb->sock;    
  212.     RingBuffer &     buf     =    *sock.rb;
  213.     Boolean &        pend    =    sock.readPending;
  214.         
  215.     if (buf.Locked())
  216.         buf.Later(Deferred(PAPReadHellHound), pb);
  217.     else    {
  218.         buf.Later(nil, nil);
  219.         if (pend) {
  220.             pend    =    false;
  221.             
  222.             if (pb->state)    {
  223.                 pb->sock->readShutDown    =    true;
  224.                 
  225.                 return;
  226.             }
  227.             
  228.             buf.Validate(pb->length);
  229.             
  230.             if (pb->eof){
  231.                 pb->sock->readShutDown    =    true;
  232.                 
  233.                 return;
  234.             }
  235.         }
  236.         
  237.         if (!buf.Free()) 
  238.             buf.Later(Deferred(PAPReadHellHound), pb);
  239.         else {
  240.             char *    buffer;
  241.             long        max    =    MaxPAP;
  242.             
  243.             buffer            =    buf.Producer(max);
  244.             pb->length        =    short(max);
  245.             pend                =    true;
  246.             
  247.             PAPRead(
  248.                 sock.papRefNum,
  249.                 buffer, 
  250.                 &pb->length,
  251.                 &pb->eof,
  252.                 &pb->state,
  253.                 sock.papID.Code());
  254.                 
  255.             PrimeTime(QElemPtr(pb), NiceDoggie);        // See you again 
  256.         }
  257.     }
  258.  
  259. }
  260.  
  261. pascal void PAPWriteHellHound(PAPPB * pb)
  262. {
  263.     if (pb->state > 0) {
  264.         PrimeTime(QElemPtr(pb), NiceDoggie);        // See you again 
  265.         
  266.         return;
  267.     }
  268.     
  269.     if (!pb->sock->wb)                                    // We're closing
  270.         return;
  271.         
  272.     PAPSocket &        sock    =    *pb->sock;    
  273.     RingBuffer &    buf     =    *sock.wb;
  274.     Boolean &        pend    =    sock.writePending;
  275.         
  276.     if (buf.Locked())
  277.         buf.Later(Deferred(PAPWriteHellHound), pb);
  278.     else    {
  279.         buf.Later(nil, nil);
  280.         
  281.         if (pend) {
  282.             if (pb->state)    {
  283.                 pb->sock->writeShutDown    =    true;
  284.                 pb->eof                        =    1;
  285.                 
  286.                 return;
  287.             }
  288.  
  289.             buf.Invalidate(pb->length);
  290.             pend    =    false;
  291.         }
  292.         
  293.         if (!buf.Valid()) {
  294.             if (pb->sock->writeShutDown && !pb->eof)
  295.                 PAPWrite(
  296.                     sock.papRefNum,
  297.                      0,
  298.                      0,
  299.                      pb->eof = 1,
  300.                      &pb->state,
  301.                     sock.papID.Code());
  302.             else
  303.                 buf.Later(Deferred(PAPWriteHellHound), pb);
  304.         } else {
  305.             char *     buffer;
  306.             long        max    =    MaxPAP;
  307.             
  308.             buffer            =    buf.Consumer(max);
  309.             pb->length        =    short(max);
  310.             pend                =    true;
  311.             
  312.             PAPWrite(
  313.                 sock.papRefNum,
  314.                  buffer,
  315.                  pb->length,
  316.                  0,
  317.                  &pb->state,
  318.                 sock.papID.Code());
  319.                 
  320.             PrimeTime(QElemPtr(pb), NiceDoggie);        // See you again
  321.         }
  322.     }
  323. }
  324.  
  325. #pragma segment GUSIPAP
  326.  
  327. /************************** PAPID members **************************/
  328.  
  329. void PAPID::GetPAPCode(short vRefNum, long dirID, StringPtr name)
  330. {
  331.     short        res;
  332.     
  333.     res = HOpenResFile(vRefNum, dirID, name, fsRdPerm);
  334.     
  335.     if (res == -1)
  336.         return;
  337.         
  338.     papCode = Get1Resource('PDEF', 10);
  339.     
  340.     if (papCode) {
  341.         DetachResource(papCode);
  342.         MoveHHi(papCode);
  343.         HLock(papCode);
  344.     } else 
  345.         goto done;
  346.  
  347.     papName = Get1Resource('PAPA', -8192);
  348.     
  349.     if (papName) {
  350.         DetachResource(papName);
  351.         MoveHHi(papName);
  352.         HLock(papName);
  353.     } else {
  354.         DisposeHandle(papCode);
  355.         
  356.         papCode = nil;
  357.     }
  358.  
  359. done:    
  360.     CloseResFile(res);
  361. }
  362.  
  363. PAPID::PAPID()
  364. {
  365.     OSErr                err;
  366.     short                saveRes;
  367.     short                prVol;
  368.     long                prDir;
  369.     StringHandle    printer;
  370.         
  371.     papCode    =    nil;
  372.     papName    =    nil;
  373.  
  374.     if (err = FindFolder(
  375.                     kOnSystemDisk, 
  376.                     kExtensionFolderType, 
  377.                     kDontCreateFolder,
  378.                     &prVol,
  379.                     &prDir)
  380.     )
  381.         return;
  382.         
  383.     saveRes = CurResFile();
  384.     UseResFile(0);
  385.             
  386.     if (printer = StringHandle(Get1Resource('STR ', -8192))) {
  387.         HLock(Handle(printer));
  388.         
  389.         GetPAPCode(prVol, prDir, *printer);
  390.         
  391.         ReleaseResource(Handle(printer));
  392.     } 
  393.  
  394.     if (!papCode)
  395.         GetPAPCode(prVol, prDir, "\pLaserWriter");
  396.     
  397.     UseResFile(saveRes);
  398. }
  399.  
  400. PAPID::~PAPID()
  401. {
  402.     if (papName)    
  403.         DisposeHandle(papName);
  404.     if (papCode)
  405.         DisposeHandle(papCode);
  406. }
  407.  
  408. /************************ PAPSocket members ************************/
  409.  
  410. PAPSocket::PAPSocket()
  411. {
  412.     status            =    PAPSocket::opening;
  413.     nonblocking        =    false;
  414.     rb                    =    new RingBuffer(4096);
  415.     wb                    =    new RingBuffer(4096);
  416.     readPending        =    false;
  417.     writePending    =    false;
  418.     readShutDown    =    false;
  419.     writeShutDown    =    false;
  420.     ourA5                =    SetCurrentA5();
  421.     
  422.     if (!papID) {
  423.         GUSI_error(ENETDOWN);
  424.         
  425.         return;
  426.     } else if (!rb || !wb) {
  427.         GUSI_error(ENOMEM);
  428.         
  429.         return;
  430.     }
  431.     
  432.     if (PAPOpen(&papRefNum, papID.Name(), 8, &papStatus, &wpb.state, papID.Code()))
  433.         GUSI_error(ENETDOWN);
  434. }
  435.  
  436. PAPSocket::~PAPSocket()
  437. {
  438.     char dummy;
  439.     
  440.     shutdown(1);                                                // Got nothing morte to say
  441.     while (recvfrom(&dummy, 1, 0, nil, nil) > 0)        // Wait for printer to complete
  442.         ;
  443.         
  444.     PAPUnload(papID.Code());
  445.  
  446.     if (rb)
  447.         delete rb;
  448.     
  449.     if (wb)
  450.         delete wb;
  451. }
  452.  
  453. int PAPSocket::Powerup()
  454. {
  455.     switch (status) {
  456.     case PAPSocket::opening:
  457.         if (wpb.state > 0 && nonblocking)
  458.             return GUSI_error(EWOULDBLOCK);
  459.             
  460.         SPIN(wpb.state > 0, SP_MISC, 0);
  461.         
  462.         if (wpb.state) {
  463.             status = PAPSocket::closed;
  464.             
  465.             return GUSI_error(ENETDOWN);
  466.         } 
  467.         
  468.         status    =    PAPSocket::open;
  469.         
  470.         // Opening was successful, start hellhounds
  471.         
  472.         rpb.timer.tmAddr        =    PAPReadTimer;
  473.         rpb.timer.tmWakeUp    =    0;
  474.         rpb.timer.tmReserved    =    0;
  475.         rpb.sock                    =    this;
  476.         
  477.         wpb.timer.tmAddr        =    PAPWriteTimer;
  478.         wpb.timer.tmWakeUp    =    0;
  479.         wpb.timer.tmReserved    =    0;
  480.         wpb.sock                    =    this;
  481.         wpb.eof                    =    0;
  482.         
  483.         InsTime((QElem *) &rpb.timer);
  484.         InsTime((QElem *) &wpb.timer);
  485.         
  486.         PAPReadHellHound(&rpb);
  487.         PAPWriteHellHound(&wpb);
  488.     
  489.         return 0;
  490.     case PAPSocket::open:
  491.         return 0;
  492.     case PAPSocket::closed:
  493.         return GUSI_error(ENOTCONN);
  494.     }
  495. }
  496.  
  497. int PAPSocket::fcntl(unsigned int cmd, int arg)
  498. {
  499.     switch (cmd)    {
  500.     case F_GETFL:
  501.         if (nonblocking)
  502.             return FNDELAY;
  503.         else
  504.             return 0;
  505.     case F_SETFL:
  506.         if (arg & FNDELAY)
  507.             nonblocking = true;
  508.         else
  509.             nonblocking = false;
  510.             
  511.         return 0;
  512.     default:
  513.         return GUSI_error(EOPNOTSUPP);
  514.     }
  515. }
  516.  
  517. int PAPSocket::ioctl(unsigned int request, void *argp)
  518. {
  519.     switch (request)    {
  520.     case FIONBIO:
  521.         nonblocking    =    (Boolean) *(long *) argp;
  522.         
  523.         return 0;
  524.     case FIONREAD:
  525.         if (Powerup())
  526.             return -1;
  527.             
  528.         if (status != PAPSocket::open)
  529.             return GUSI_error(ENOTCONN);    
  530.     
  531.         *(unsigned long *) argp    = rb->Valid();
  532.         
  533.         return 0;
  534.     default:
  535.         return GUSI_error(EOPNOTSUPP);
  536.     }
  537. }
  538.  
  539. int PAPSocket::recvfrom(void * buffer, int buflen, int flags, void * from, int * fromlen)
  540. {
  541.     /* This behaviour borders on the pathological, but this is what I currently
  542.        believe to be the least troublesome behaviour that is still correct.
  543.     */
  544.     if (from)
  545.         *fromlen = 0;
  546.     if (flags)
  547.         return GUSI_error(EOPNOTSUPP);
  548.  
  549.     if (Powerup())
  550.         return -1;
  551.         
  552.     if (!rb->Valid())    
  553.         if (readShutDown)
  554.             return 0;
  555.         else if (nonblocking)
  556.             return GUSI_error(EWOULDBLOCK);
  557.         else
  558.             SPIN(!rb->Valid() && !readShutDown, SP_STREAM_READ, 0);
  559.     
  560.     long    len    =    buflen;
  561.     
  562.     rb->Consume(Ptr(buffer), len);
  563.     
  564.     return len;
  565. }
  566.  
  567. int PAPSocket::sendto(void * buffer, int buflen, int flags, void * to, int)
  568. {
  569.     if (to)
  570.         return GUSI_error(EOPNOTSUPP);
  571.     if (flags)
  572.         return GUSI_error(EOPNOTSUPP);
  573.     
  574.     if (Powerup())
  575.         return -1;
  576.         
  577.     if (writeShutDown)
  578.         return GUSI_error(ESHUTDOWN);
  579.     
  580.     if (!wb->Free())
  581.         if (nonblocking)
  582.             return GUSI_error(EWOULDBLOCK);
  583.         
  584.     long    len    =    buflen;
  585.     long    done    =    0;
  586.     
  587.     for (;;) {
  588.         wb->Produce(Ptr(buffer), len);
  589.         
  590.         done        +=    len;
  591.         
  592.         if (nonblocking)
  593.             break;
  594.         
  595.         buflen    -=    int(len);
  596.         
  597.         if (!buflen)
  598.             break;
  599.         
  600.         buffer     =    Ptr(buffer) + len;
  601.         len        =    buflen;
  602.         
  603.         SPIN(!wb->Free() && !writeShutDown, SP_STREAM_WRITE, 0);
  604.         
  605.         if (writeShutDown)
  606.             break;
  607.     }
  608.     
  609.     return done;
  610. }
  611.  
  612. int PAPSocket::shutdown(int how)
  613. {
  614.     if (how < 0 || how > 2)
  615.         return GUSI_error(EINVAL);
  616.     
  617.     if (how) {
  618.         writeShutDown    =    true;
  619.         
  620.         if (status == PAPSocket::open)
  621.             wb->Undefer();                            //    Wake up write hellhound
  622.     }
  623.     if (!(how & 1))
  624.         readShutDown    =    true;
  625.         
  626.     return 0;
  627. }
  628.  
  629. int PAPSocket::select(Boolean * canRead, Boolean * canWrite, Boolean *)
  630. {
  631.     int        goodies     =     0;
  632.     
  633.     if (canRead)
  634.         switch (status) {
  635.         case PAPSocket::open:
  636.             if (rb->Valid() || readShutDown) {
  637.                 *canRead = true;
  638.                 ++goodies;
  639.             }
  640.             break;
  641.         case PAPSocket::opening:
  642.             break;
  643.         case PAPSocket::closed:
  644.             *canRead = true;
  645.             ++goodies;
  646.             break;
  647.         }
  648.     
  649.     if (canWrite)
  650.         switch (status) {
  651.         case PAPSocket::opening:
  652.             if (!(wpb.state > 0)) {
  653.                 *canWrite = true;
  654.                 ++goodies;
  655.             }
  656.             break;
  657.         case PAPSocket::open:
  658.             if (wb->Free() || writeShutDown) {
  659.                 *canWrite = true;
  660.                 ++goodies;
  661.             }
  662.             break;
  663.         case PAPSocket::closed:
  664.             *canRead = true;
  665.             ++goodies;
  666.             break;
  667.         }
  668.         
  669.     return goodies;
  670. }
  671.  
  672. /********************* PAPSocketDomain member **********************/
  673.  
  674. extern "C" void GUSIwithPAPSockets()
  675. {
  676.     PAPSockets.DontStrip();
  677. }
  678.  
  679. Socket * PAPSocketDomain::open(const char * filename, int)
  680. {
  681.     Socket *    sock;
  682.     
  683.     if (equalstring((char *) filename, (char *) "printer", false, true)) {
  684.         errno = 0;
  685.         sock     = new PAPSocket();
  686.         
  687.         if (sock && errno) {
  688.             delete sock;
  689.             
  690.             return nil;
  691.         } else
  692.             return sock;
  693.     } else
  694.         return (Socket *) TryNextDevice;
  695. }
  696.