home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Tools / ObjectTcl-1.1 / OtclOserver.C < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-30  |  31.1 KB  |  1,493 lines

  1. // System Includes
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <sys/types.h>
  6. #include <errno.h>
  7.  
  8. #if defined(_EVEREST) || defined(_SUNOS5)
  9.  
  10. #include <sys/select.h>
  11. #include <ulimit.h>
  12. //#include <strings.h>
  13.  
  14. // Needs ulimit and select
  15.  
  16. #endif
  17.  
  18. #ifdef _WINDOWS
  19.  
  20. #include <winsock.h>
  21. #include <process.h>
  22.  
  23. #else
  24.  
  25. #include <unistd.h>
  26. #include <sys/socket.h>
  27. #include <netinet/in.h>
  28. #include <netinet/tcp.h>
  29. #include <arpa/inet.h>
  30. #include <netdb.h>
  31.  
  32. #endif
  33.  
  34. #include "OtclOserver.H"
  35. #include "Otcl.H"
  36. #include "OtclError.H"
  37. #include "OtclObject.H"
  38.  
  39. #ifdef _SUNOS4
  40. #include "sunos4.h"
  41. #endif
  42.  
  43. #ifdef _SUNOS5
  44. #include <sys/systeminfo.h>
  45. #define GETHOSTNAME(b,l) sysinfo(SI_HOSTNAME,(b),(l))
  46. #else
  47. #define GETHOSTNAME(b,l) gethostname((b),(l))
  48. #endif
  49.  
  50. #ifdef _WINDOWS
  51.  
  52. #define FD_SIZE FD_SETSIZE
  53. #define CLOSE_SOCKET(s) closesocket(s)
  54.  
  55. #else
  56.  
  57. #define FD_SIZE ulimit(4,0)
  58. #define CLOSE_SOCKET(s) close(s)
  59.  
  60. #endif
  61.  
  62. // Static Class Attributes
  63. fd_set *OtclOserver::incommingFdSet = new fd_set;
  64. fd_set *OtclOserver::incommingFdSubset = new fd_set;
  65. OtclChannel **OtclOserver::incommingChannel = (OtclChannel**)malloc((unsigned int)FD_SIZE * sizeof(OtclChannel*));
  66.  
  67. OtclChannel *OtclOserver::listener = NULL;
  68. char **OtclOserver::incommingThread = (char**)malloc((unsigned int)FD_SIZE *
  69.                                                sizeof(char*));
  70. char *OtclOserver::currentThread = OtclOserver::createOurThreadId();
  71. void (*OtclOserver::addReadFd) (int) = NULL;
  72. void (*OtclOserver::rmvReadFd) (int) = NULL;
  73. Tcl_HashTable *OtclOserver::outgoingChannel = NULL;
  74. char *OtclOserver::address = NULL;
  75.  
  76. OtclChannel::OtclChannel (char *addrStr, Tcl_Interp *interp, int &result)
  77. {
  78.    extern int errno;
  79.    extern int sys_nerr;
  80.    extern char *sys_errlist[];
  81.  
  82.    skt = -1;
  83.    result = TCL_OK;
  84.  
  85.    char *colon = strchr(addrStr,':');
  86.    if (colon == NULL)
  87.    {
  88.       result = TCL_ERROR;
  89.       Otcl::setTclResult(interp,ADDRESS_NO_COLON_ERR,addrStr);
  90.       return;
  91.    }
  92.  
  93.    *colon = NULL;
  94.    char *host = addrStr;
  95.    int port = atoi(colon+1);
  96.  
  97.    if (port == 0)
  98.    {
  99.       result = TCL_ERROR;
  100.       Otcl::setTclResult(interp,ADDRESS_INVALID_PORT_ERR,addrStr);
  101.       *colon = ':';
  102.       return;
  103.    }
  104.  
  105.    skt = socket(AF_INET,SOCK_STREAM,0);
  106.    if (skt == -1)
  107.    {
  108.       result = TCL_ERROR;
  109.       Otcl::setTclResult(interp,COULDNT_SOCKET_ERR,(errno > sys_nerr ?
  110.                          "- unknown reason" : sys_errlist[errno]));
  111.       *colon = ':';
  112.       return;
  113.    }
  114.  
  115.    struct hostent *hp = gethostbyname(host);
  116.    if (hp == NULL)
  117.    {
  118.       result = TCL_ERROR;
  119.       Otcl::setTclResult(interp,COULDNT_GET_HOSTNAME_ERR,host);
  120.       CLOSE_SOCKET(skt);
  121.       skt = -1;
  122.       *colon = ':';
  123.       return;
  124.    }
  125.  
  126.    struct sockaddr_in address;
  127.    address.sin_family = AF_INET;
  128.    address.sin_port = htons(port);
  129.    memcpy(&address.sin_addr,hp->h_addr_list[0],hp->h_length);
  130.  
  131.    if (connect(skt,(sockaddr*)&address,sizeof(address)) == -1)
  132.    {
  133.       result = TCL_ERROR;
  134.       Otcl::setTclResult(interp,COULDNT_CONNECT_ERR,addrStr,(errno > sys_nerr ?
  135.                          "- unknown reason" : sys_errlist[errno]));
  136.       CLOSE_SOCKET(skt);
  137.       skt = -1;
  138.       *colon = ':';
  139.       return;
  140.    }
  141.  
  142.    *colon = ':';
  143. }
  144.  
  145. OtclChannel::OtclChannel (int fd)
  146. {
  147.    skt = fd;
  148. }
  149.  
  150. OtclChannel::~OtclChannel ()
  151. {
  152.    if (skt != -1)
  153.    {
  154.       CLOSE_SOCKET(skt);
  155.    }
  156. }
  157.  
  158. int OtclChannel::sendFull (char *buffer, int length)
  159. {
  160.    int totalBytesSent = 0;
  161.    int bytesSent = 0;
  162.    while (totalBytesSent != length)
  163.    {
  164.       bytesSent = ::send(skt,buffer,length,0);
  165.       if (bytesSent == -1 || bytesSent == 0)
  166.       {
  167.          return -1;
  168.       }
  169.       totalBytesSent += bytesSent;
  170.    }
  171.    return 0;
  172. }
  173.  
  174. int OtclChannel::recvFull (char *buffer, int length)
  175. {
  176.    int totalBytesRecv = 0;
  177.    int bytesRecv = 0;
  178.    while (totalBytesRecv < length)
  179.    {
  180.       bytesRecv = ::recv(skt,buffer,length,0);
  181.       if (bytesRecv == -1 || bytesRecv == 0)
  182.       {
  183.          return -1;
  184.       }
  185.       totalBytesRecv += bytesRecv;
  186.    }
  187.    return 0;
  188. }
  189.  
  190. int OtclChannel::streamOut (char c)
  191. {
  192.    return sendFull(&c,1);
  193. }
  194.  
  195. int OtclChannel::streamOut (long l)
  196. {
  197.    long tmp = htonl(l);
  198.    return sendFull((char*)&tmp,sizeof(long));
  199. }
  200.  
  201. int OtclChannel::streamOutNullTerminated (char *s)
  202. {
  203.    long length = (s == NULL? -1 : strlen(s));
  204.    if (streamOut(length) == -1)
  205.    {
  206.       return -1;
  207.    }
  208.    if (length >= 0)
  209.    {
  210.       return sendFull(s,(int)length);
  211.    }
  212.    return 0;
  213. }
  214.  
  215. int OtclChannel::streamIn (char &c)
  216. {
  217.    char *cptr = &c;
  218.    return recvFull(cptr,1);
  219. }
  220.  
  221. int OtclChannel::streamIn (long &l)
  222. {
  223.    long  nl;
  224.    int result = recvFull((char*)&nl,sizeof(long));
  225.    l = ntohl(nl);
  226.    return result;
  227. }
  228.  
  229. int OtclChannel::streamInNullTerminated (char *&s)
  230. {
  231.    long length;
  232.    if (streamIn(length) == -1)
  233.    {
  234.       return -1;
  235.    }
  236.  
  237.    if (length >= 0)
  238.    {
  239.       s = (char*)malloc((unsigned int) ((length + 1) * sizeof(char)));
  240.       if (recvFull(s,(int)length) == -1)
  241.       {
  242.          free(s);
  243.          return -1;
  244.       }
  245.       s[length] = NULL;
  246.    }
  247.    else
  248.    {
  249.       s = NULL;
  250.    }
  251.  
  252.    return 0;
  253. }
  254.  
  255. int OtclChannel::operator == (int fd)
  256. {
  257.    if (skt == fd)
  258.    {
  259.       return OTCL_TRUE;
  260.    }
  261.    else
  262.    {
  263.       return OTCL_FALSE;
  264.    }
  265. }
  266.  
  267. int OtclChannel::getFd (void)
  268. {
  269.    return skt;
  270. }
  271.  
  272.  
  273. int OtclOserver::initialiseCmd (Tcl_Interp *interp, int argc, char *argv[])
  274. {
  275.    ARGC_RANGE(3,5)
  276.    {
  277.       return Otcl::setTclError(interp,ARGS_OSERVER_INIT_ERR);
  278.    }
  279.  
  280.    if (listener != NULL)
  281.    {
  282.       return Otcl::setTclError(interp,OTCL_OSERVER_ALREADY_INIT_ERR);
  283.    }
  284.  
  285.    int minPort = -1;
  286.    int maxPort = -1;
  287.  
  288.    if (argc > 3)
  289.    {
  290.       minPort = atoi(argv[3]);
  291.       if (minPort < 0)
  292.       {
  293.          return Otcl::setTclError(interp,OTCL_OSERVER_MIN_PORT_ERR);
  294.       }
  295.    }
  296.    if (argc == 5)
  297.    {
  298.       maxPort = atoi(argv[4]);
  299.       if (maxPort < minPort)
  300.       {
  301.          return Otcl::setTclError(interp,OTCL_OSERVER_MAX_PORT_ERR);
  302.       }
  303.    }
  304.  
  305.    if (minPort == -1)
  306.    {
  307.       // No port or range of ports specified, use default
  308.       // range
  309.       minPort = MIN_TCP_IP_PORT;
  310.       maxPort = MAX_TCP_IP_PORT;
  311.    }
  312.  
  313.    int skt = socket(AF_INET,SOCK_STREAM,0);
  314.    if (skt == -1)
  315.    {
  316.       return Otcl::setTclError(interp,COULDNT_SOCKET_ERR);
  317.    }
  318.  
  319.    struct sockaddr_in bindAddr;
  320.    memset(&bindAddr,NULL,sizeof(bindAddr));
  321.    bindAddr.sin_family = AF_INET;
  322.    bindAddr.sin_addr.s_addr = htonl(INADDR_ANY);
  323.  
  324.    int port;
  325.    if (maxPort == -1)
  326.    {
  327.       bindAddr.sin_port = htons(minPort);
  328.       if (::bind(skt,(struct sockaddr *)&bindAddr,sizeof(bindAddr)) == -1)
  329.       {
  330.          CLOSE_SOCKET(skt);
  331.          return Otcl::setTclError(interp,CANNOT_BIND_TO_PORT_ERR,minPort);
  332.       }
  333.       port = minPort;
  334.    }
  335.    else
  336.    {
  337.       port = minPort;
  338.       do
  339.       {
  340.          port++;
  341.          bindAddr.sin_port = htons(port);
  342.       }
  343.       while (port <= maxPort && ::bind(skt,(struct sockaddr *)&bindAddr,
  344.                                       sizeof(bindAddr)) == -1);
  345.       if (port > maxPort)
  346.       {
  347.          CLOSE_SOCKET(skt);
  348.          return Otcl::setTclError(interp,NO_AVAILABLE_PORTS_ERR,minPort,
  349.                                                                 maxPort);
  350.       }
  351.    }
  352.  
  353.    ::listen(skt,5);
  354.    listener = new OtclChannel(skt);
  355.    FD_ZERO(incommingFdSet);
  356.    FD_ZERO(incommingFdSubset);
  357.    FD_SET(skt,incommingFdSet);
  358.    FD_SET(skt,incommingFdSubset);
  359.  
  360.    // Maybe an issue with fdset not being cleared if we aren't a server!
  361.    // TO DO tink about
  362.  
  363.    if (addReadFd != NULL)
  364.    {
  365.       // The client code is providing its own main loop
  366.       // inform it of the new Fd to watch out for
  367.       (*addReadFd)(skt);
  368.    }
  369.  
  370.    char suffix[128];
  371.    char name[128];
  372.    GETHOSTNAME(name,128);
  373.    hostent *he = gethostbyname(name);
  374.    if (he)
  375.    {
  376.       strcpy(name,he->h_name);
  377.    }
  378.    sprintf(suffix,"@%s:%d",name,port);
  379.    Otcl::otclPtr->setObjectReferenceSuffix(suffix);
  380.  
  381.    // We don't need to '@' in our internal address
  382.    address = (char*)malloc(strlen(suffix) * sizeof(char));
  383.    sprintf(address,"%s:%d",name,port);
  384.  
  385.    // Initialise incomming threads and channels.
  386.    int l = (int)FD_SIZE;
  387.    for (int i = 0; i < l; i++)
  388.    {
  389.       incommingThread[i] = NULL;
  390.       incommingChannel[i] = NULL;
  391.    }
  392.    incommingChannel[skt] = listener;
  393.  
  394.  
  395.    Otcl::setTclResult(interp,"%d",port);
  396.    return TCL_OK;
  397. }
  398.  
  399. void OtclOserver::readableFd (int fd)
  400. {
  401.    if (listener != NULL && (listener->getFd() == fd))
  402.    {
  403.       // new client connection. Accept the connection and give it 
  404.       // a channel, register the new client channel with the main
  405.       // loop for read events.
  406.  
  407.       int a = 55;
  408.       a++;
  409.       processConnectionRequest();
  410.       a++;
  411.       return;
  412.    }
  413.  
  414.    OtclChannel *channel = incommingChannel[fd];
  415.    if (channel != NULL)
  416.    {
  417.       // stack current thread id.
  418.       char *oldThreadId = currentThread;
  419.       currentThread = NULL;
  420.  
  421.       if (incommingThread[fd] != NULL)
  422.       {
  423.          // We have already read the thread id from the channel
  424.          // and it was stored in incommingThread[fd]
  425.          currentThread = incommingThread[fd];
  426.          incommingThread[fd] = NULL;
  427.   
  428.          // The fd will have been removed from the fdSubset, so put it back
  429.          FD_SET(fd,incommingFdSubset);
  430.       }
  431.       else if (channel->streamInNullTerminated(currentThread) == -1)
  432.       {
  433.             // Problem with channel. Clean it up and de-register our
  434.             // interest. Probably a client disconnected.
  435.             cleanupIncommingChannel(fd);
  436.             currentThread = NULL; // Just in case the read garbaged it!
  437.       }
  438.  
  439.       if (currentThread != NULL)
  440.       {
  441.          processRequest(fd,Otcl::tclInterp);
  442.  
  443.          free(currentThread);
  444.       }
  445.  
  446.       // restore the stacked thread id.
  447.       currentThread = oldThreadId;
  448.    }
  449. }
  450.  
  451. int OtclOserver::oserverCmd (Tcl_Interp *interp, int argc, char *argv[])
  452. {
  453.    ARGC_MIN(3)
  454.    {
  455.       return Otcl::setTclError(interp,ARGS_OSERVER_INIT_ERR);
  456.    }
  457.  
  458.    if (strcmp("init",argv[2]) == 0)
  459.    {
  460.       return initialiseCmd(interp,argc,argv);
  461.    }
  462.  
  463.    if (strcmp("process",argv[2]) == 0)
  464.    {
  465.       return processCmd(interp,argc,argv);
  466.    }
  467.  
  468.    if (strcmp("getAddress",argv[2]) == 0)
  469.    {
  470.       return getAddressCmd(interp,argc,argv);
  471.    }
  472.  
  473.    return Otcl::setTclError(interp,UNKNOWN_OSERVER_COMMAND_ERR,argv[2]);
  474. }
  475.  
  476. int OtclOserver::processCmd (Tcl_Interp *interp, int argc, char *argv[])
  477. {
  478.    ARGC_RANGE(3,4)
  479.    {
  480.       return Otcl::setTclError(interp,ARGS_OSERVER_PROCESS_ERR);
  481.    }
  482.  
  483.    if (listener == NULL)
  484.    {
  485.       return Otcl::setTclError(interp,OTCL_OSERVER_MUST_INIT_FIRST_ERR);
  486.    }
  487.  
  488.    char *script = (argc == 4? argv[3] : NULL);
  489.    int scriptResult = TCL_OK;
  490.    int finished = OTCL_FALSE;
  491.    int result;
  492.    fd_set selectSet;
  493.    int available;
  494.    int maxFds = (int)FD_SIZE;
  495.    do
  496.    {
  497.  
  498.       // select on all outer descriptors
  499.       selectSet = *incommingFdSet;
  500.       available = select(maxFds,&selectSet,NULL,NULL,0);
  501.       if (available == -1 || available == 0)
  502.       {
  503.          result = TCL_ERROR;
  504.          finished = OTCL_TRUE;
  505.          Otcl::setTclResult(interp,OTCL_OSERVER_SELECT_ERR);
  506.       }
  507.       else
  508.       {
  509.          int fd = 0;
  510.          while (available != 0)
  511.          {
  512.             if (FD_ISSET(fd,&selectSet))
  513.             {
  514.                 available--;
  515.                 readableFd(fd);
  516.             }
  517.             fd++;
  518.          }
  519.       }
  520.  
  521.       if (script != NULL)
  522.       {
  523.          result = Tcl_Eval(interp,script);
  524.          if (result == TCL_ERROR)
  525.          {
  526.             finished = OTCL_TRUE;
  527.          }
  528.          else
  529.          {
  530.             if (interp->result == NULL || strcmp(interp->result,"0") == 0)
  531.             {
  532.                finished = OTCL_TRUE;
  533.             }
  534.          }
  535.       }
  536.    }
  537.    while (finished == OTCL_FALSE);
  538.  
  539.    return result;
  540. }
  541.  
  542. int OtclOserver::getAddressCmd (Tcl_Interp *interp, int argc, char *[])
  543. {
  544.    ARGC_VALUE(3)
  545.    {
  546.       return Otcl::setTclError(interp,ARGS_OTCL_OSERVER_GET_ADDRESS_ERR);
  547.    }
  548.  
  549.    if (address != NULL)
  550.    {
  551.       Tcl_SetResult(interp,address,TCL_STATIC);
  552.    }
  553.    else
  554.    {
  555.       Tcl_SetResult(interp,"",TCL_STATIC);
  556.    }
  557.  
  558.    return TCL_OK;
  559. }
  560.  
  561. char *OtclOserver::createOurThreadId (void)
  562. {
  563.    // The thread id for this process is made up of the
  564.    // hostname:pid
  565.    char hostname[128];
  566.    char threadId[128];
  567.    GETHOSTNAME(hostname,128);
  568.    struct hostent *hp = gethostbyname(hostname);
  569.    if (hp)
  570.    {
  571.       strcpy(hostname,hp->h_name); 
  572.    }
  573.    sprintf(threadId,"%s:%d",hostname,getpid());
  574.    
  575.    return strdup(threadId);
  576. }
  577.  
  578. OtclResponse *OtclOserver::sendRequest (Tcl_Interp *interp,
  579.                                         char *address,
  580.                                         OtclRequest *rqst)
  581. {
  582.    // Find, or make a channel
  583.    OtclChannel *channel;
  584.    if (outgoingChannel == NULL)
  585.    {
  586.       // The outgoing channel hash table hasn't been created, so create it
  587.       outgoingChannel = new Tcl_HashTable;
  588.       Tcl_InitHashTable(outgoingChannel,TCL_STRING_KEYS);
  589.    }
  590.    int newEntry;
  591.    Tcl_HashEntry *he = Tcl_CreateHashEntry(outgoingChannel,address,&newEntry);
  592.    if (newEntry)
  593.    {
  594.       int result;
  595.       channel = new OtclChannel(address,interp,result);
  596.       if (result != TCL_OK)
  597.       {
  598.          // Has an error constructing the channel
  599.          delete channel;
  600.          return new OtclResponse(result,interp);
  601.       }
  602.       Tcl_SetHashValue(he,channel);
  603.    }
  604.    else
  605.    {
  606.       channel = (OtclChannel*)Tcl_GetHashValue(he);
  607.    }
  608.  
  609.    // Stream out current thread id
  610.    if (channel->streamOutNullTerminated(currentThread) == -1)
  611.    {
  612.       // Error streaming out the current thread id
  613.       delete channel;
  614.       Tcl_DeleteHashEntry(he);
  615.       return new OtclResponse(TCL_ERROR,"Outgoing connection error.");
  616.    }
  617.  
  618.    // stream out request object
  619.    if (rqst->streamOut(channel) == -1)
  620.    {
  621.       // Error streaming out request
  622.       delete channel;
  623.       Tcl_DeleteHashEntry(he);
  624.       return new OtclResponse(TCL_ERROR,"Outgoing connection error.");
  625.    }
  626.  
  627.    fd_set readSet;
  628.    int available;
  629.    int maxFds = (int)FD_SIZE;
  630.  
  631.    do 
  632.    {
  633.  
  634.       // We want to look for a reply from the request channel and keep
  635.       // an eye out for any other requests on the input channels that
  636.       // haven't got a request queued up because it's for the wrong thread id.
  637.       readSet = *incommingFdSubset;
  638.       FD_SET(channel->getFd(),&readSet);
  639.  
  640.       available = select(maxFds,&readSet,NULL,NULL,0);
  641.  
  642.       if (available == 0)
  643.       {
  644.          // We timed out, how I don't know but we timed out!
  645.          return new OtclResponse(TCL_ERROR,"Error in select loop");
  646.       }
  647.  
  648.       if (available == -1)
  649.       {
  650.          if (available == EINTR)
  651.          {
  652.            // A signal broke our select, restart the select
  653.            continue;
  654.          }
  655.  
  656.          // We have had a real error
  657.          return new OtclResponse(TCL_ERROR,"Error in select loop");
  658.       }
  659.  
  660.       // There are 1 or more descriptors available
  661.  
  662.       if (FD_ISSET(channel->getFd(),&readSet))
  663.       {
  664.          // We have our reply. Break out of loop
  665.          break;
  666.       }
  667.  
  668.       // Iterate over incomming channels
  669.       int i = 0;
  670.       while (i < maxFds && available > 0)
  671.       {
  672.  
  673.          if (incommingChannel[i] != NULL && FD_ISSET(i,&readSet))
  674.          {
  675.             available--;
  676.  
  677.             if (incommingChannel[i] == listener)
  678.             {
  679.                processConnectionRequest();
  680.             }
  681.             else
  682.             {
  683.                // A channel that isn't our listener has something pending
  684.                // Read the thread id.
  685.                if (incommingChannel[i]->streamInNullTerminated(
  686.                                             incommingThread[i]) == -1)
  687.                {
  688.                   // Error on the channel. Close down the channel and
  689.                   // de-register it from all of the fd sets.
  690.                   cleanupIncommingChannel(i);
  691.                }
  692.                if (strcmp(incommingThread[i],currentThread) == 0)
  693.                {
  694.                  // The request is for the current thread so process it
  695.                  free(incommingThread[i]);
  696.                  incommingThread[i] = NULL;
  697.                  processRequest(i,interp);
  698.                }
  699.                else
  700.                {
  701.                  // The incomming request is for a different thread
  702.                  // Request will be queued by removing the channel from the
  703.                  // incommingFdSubset. The request thread id has been placed
  704.                  // in the appropriate incommingThread[x] slot
  705.                  FD_CLR((unsigned int)i,incommingFdSubset);
  706.                }
  707.             }
  708.          }
  709.  
  710.          i++;
  711.       }
  712.  
  713.    }
  714.    while (OTCL_TRUE);
  715.  
  716.    // The only way out of the above loop is for the original request
  717.    // to have been replied to.
  718.  
  719.    // Read in response from channel
  720.    OtclResponse *response = new OtclResponse();
  721.    if (response->streamIn(channel) == -1)
  722.    {
  723.      // Error on the channel. Didn't get the request back.
  724.      delete response;
  725.      response = new OtclResponse(TCL_ERROR,"Error on channel before response.");
  726.    }
  727.    
  728.    return response;
  729. }
  730.  
  731. void OtclOserver::processRequest (int fd, Tcl_Interp *interp)
  732. {
  733.    // read the type
  734.    char requestType;
  735.    OtclChannel *channel = incommingChannel[fd];
  736.    if (channel->streamIn(requestType) == -1)
  737.    {
  738.       // Channel hasn an error, close it
  739.       cleanupIncommingChannel(fd);
  740.    }
  741.    else
  742.    {
  743.       // Create the appropriate request type;
  744.       OtclRequest *request;
  745.       switch (requestType)
  746.       {
  747.          case INSTANCE_METHOD_RQST:
  748.             request = new OtclInstanceMethodRqst();
  749.             break;
  750.  
  751.          case DELETE_OBJECT_RQST:
  752.             request = new OtclDeleteObjectRqst();
  753.             break;
  754.  
  755.          case CLASS_METHOD_RQST:
  756.             request = new OtclClassMethodRqst();
  757.             break;
  758.  
  759.          case NEW_OBJECT_RQST:
  760.             request = new OtclNewObjectRqst();
  761.             break;
  762.  
  763.          default:
  764.             // Nasty error, unknown message type, TO DO
  765.             return;
  766.       }
  767.  
  768.       // Stream in the request
  769.       if (request->streamIn(channel) == -1)
  770.       {
  771.          cleanupIncommingChannel(fd);
  772.          delete request;
  773.       }
  774.       else
  775.       {
  776.          // Perform the request and record the result;
  777.          OtclResponse response(request->perform(interp),interp);
  778.  
  779.          // Stream out the response
  780.          delete request;
  781.          if (response.streamOut(channel) == -1)
  782.          {
  783.             cleanupIncommingChannel(fd);
  784.          }
  785.       }
  786.    }
  787. }
  788.  
  789. void OtclOserver::cleanupIncommingChannel (int fd)
  790. {
  791.    delete incommingChannel[fd];
  792.    FD_CLR((unsigned int)fd,incommingFdSet);
  793.    FD_CLR((unsigned int)fd,incommingFdSubset);
  794.    if (rmvReadFd != NULL)
  795.    {
  796.       // There is an outer loop registered beyond Object Tcl
  797.       // inform it that we no longer need to monitor this channel.
  798.       (*rmvReadFd)(fd);
  799.    }
  800. }
  801.  
  802. void OtclOserver::processConnectionRequest (void)
  803. {
  804.    struct sockaddr_in clientAddr;
  805.    int clientAddrLen = sizeof(clientAddr);
  806.  
  807.    // Should probably hide this inside OtclChannel. TO DO
  808.    int client = ::accept(listener->getFd(),(struct sockaddr*)&clientAddr,&clientAddrLen);
  809.    if (client == -1)
  810.    {
  811.       // This can only be a really hard error
  812.  
  813.       perror("OtclOserver:: listening socket accept error ");
  814.  
  815.       exit(1);
  816.    }
  817.  
  818.    incommingChannel[client] = new OtclChannel(client);
  819.    FD_SET(client,incommingFdSet);
  820.    FD_SET(client,incommingFdSubset);
  821.  
  822.    if (addReadFd != NULL)
  823.    {
  824.       // There is a main loop outside of Object Tcl control, inform it
  825.       // of new incomming file descriptor.
  826.       (*addReadFd)(client);
  827.    }
  828. }
  829.  
  830. OtclRequest::OtclRequest()
  831. {
  832. }
  833.  
  834. OtclRequest::~OtclRequest ()
  835. {
  836. }
  837.  
  838. OtclInstanceMethodRqst::OtclInstanceMethodRqst ()
  839. {
  840.    symRef = NULL;
  841.    method = NULL;
  842.    argc = 0;
  843.    argv = NULL;
  844. }
  845.  
  846. OtclInstanceMethodRqst::OtclInstanceMethodRqst (char *symRefParam,
  847.                                                 char *methodParam,
  848.                                                 long argcParam,
  849.                                                 char *argvParam[])
  850. {
  851.    symRef = strdup(symRefParam);
  852.    method = strdup(methodParam);
  853.    argc = argcParam;
  854.  
  855.    if (argc != 0)
  856.    {
  857.       argv = (char**)malloc((unsigned int)argc * sizeof(char*));
  858.       for (long l = 0; l < argc; l++)
  859.       {
  860.          argv[l] = strdup(argvParam[l]);
  861.       }
  862.    }
  863.    else
  864.    {
  865.       argv = NULL;
  866.    }
  867. }
  868.  
  869. OtclInstanceMethodRqst::~OtclInstanceMethodRqst ()
  870. {
  871.    clear();
  872. }
  873.  
  874. void OtclInstanceMethodRqst::clear (void)
  875. {
  876.    if (symRef != NULL)
  877.    {
  878.       free(symRef);
  879.    }
  880.    if (method != NULL)
  881.    {
  882.       free(method);
  883.    }
  884.    if (argv != NULL)
  885.    {
  886.       for (long l = 0; l < argc; l++)
  887.       {
  888.          free(argv[l]);
  889.       }
  890.       free(argv);
  891.    }
  892. }
  893.  
  894. int OtclInstanceMethodRqst::streamOut (OtclChannel *channel)
  895. {
  896.    if (channel->streamOut(INSTANCE_METHOD_RQST) == -1)
  897.    {
  898.       return -1;
  899.    }
  900.    if (channel->streamOutNullTerminated(symRef) == -1)
  901.    {
  902.       return -1;
  903.    }
  904.    if (channel->streamOutNullTerminated(method) == -1)
  905.    {
  906.      return -1;
  907.    }
  908.    if (channel->streamOut(argc) == -1)
  909.    {
  910.       return -1;
  911.    }
  912.    for (long l = 0; l < argc; l++)
  913.    {
  914.       if (channel->streamOutNullTerminated(argv[l]) == -1)
  915.       {
  916.          return -1;
  917.       }
  918.    }
  919.  
  920.    return 0;
  921. }
  922.  
  923. int OtclInstanceMethodRqst::streamIn (OtclChannel *channel)
  924. {
  925.    clear();
  926.    if (channel->streamInNullTerminated(symRef) == -1)
  927.    {
  928.       return -1;
  929.    }
  930.    if (channel->streamInNullTerminated(method) == -1)
  931.    {
  932.      return -1;
  933.    }
  934.    if (channel->streamIn(argc) == -1)
  935.    {
  936.       return -1;
  937.    }
  938.    if (argc != 0)
  939.    {
  940.       argv = (char**)malloc((unsigned int)argc * sizeof(char*));
  941.    }
  942.    else
  943.    {
  944.       argv = NULL;
  945.    }
  946.    for (long l = 0; l < argc; l++)
  947.    {
  948.       if (channel->streamInNullTerminated(argv[l]) == -1)
  949.       {
  950.          return -1;
  951.       }
  952.    }
  953.  
  954.    return 0;
  955. }
  956.  
  957. int OtclInstanceMethodRqst::perform (Tcl_Interp *interp)
  958. {
  959.    int returnCode;
  960.    OtclObject *otclo = Otcl::otclPtr->giveOtclObject(symRef,interp,returnCode);
  961.    if (otclo != NULL)
  962.    {
  963.       return otclo->executeMethod(interp,method,(unsigned int)argc,argv);
  964.    }
  965.    else
  966.    {
  967.       return Otcl::setTclError(interp,UNKNOWN_OBJECT_ERR,symRef);
  968.    }
  969. }
  970.  
  971. OtclResponse::OtclResponse ()
  972. {
  973.    returnValue = TCL_OK;
  974.    result = NULL;
  975. }
  976.  
  977. OtclResponse::OtclResponse (int returnValueParam, Tcl_Interp *interp)
  978. {
  979.    returnValue = returnValueParam;
  980.    if (interp->result != NULL)
  981.    {
  982.       result = strdup(interp->result);
  983.    }
  984.    else
  985.    {
  986.       result = NULL;
  987.    }
  988. }
  989.  
  990. OtclResponse::OtclResponse (int returnValueParam, char *resultParam)
  991. {
  992.    returnValue = returnValueParam;
  993.    result = strdup(resultParam);
  994. }
  995.  
  996. OtclResponse::~OtclResponse ()
  997. {
  998.    clear();
  999. }
  1000.  
  1001. void OtclResponse::clear (void)
  1002. {
  1003.    if (result != NULL)
  1004.    {
  1005.       free(result);
  1006.       result = NULL;
  1007.    }
  1008. }
  1009.  
  1010. int OtclResponse::streamOut (OtclChannel *channel)
  1011. {
  1012.    if (channel->streamOut(returnValue) == -1)
  1013.    {
  1014.       return -1;
  1015.    }
  1016.    return channel->streamOutNullTerminated(result);
  1017. }
  1018.  
  1019. int OtclResponse::streamIn (OtclChannel *channel)
  1020. {
  1021.    clear();
  1022.    if (channel->streamIn(returnValue) == -1)
  1023.    {
  1024.       return -1;
  1025.    }
  1026.    return channel->streamInNullTerminated(result);
  1027. }
  1028.  
  1029. void OtclResponse::setTclInterp (Tcl_Interp *interp)
  1030. {
  1031.    Tcl_SetResult(interp,result,TCL_VOLATILE);
  1032. }
  1033.  
  1034. int OtclResponse::getReturnValue (void)
  1035. {
  1036.    return returnValue;
  1037. }
  1038.  
  1039. OtclRemoteObject::OtclRemoteObject (char *symRef, int &result,
  1040.                                     Tcl_Interp *interp)
  1041. {
  1042.    remoteSymRef = strdup(symRef);
  1043.    char *at = strchr(symRef,'@');
  1044.    if (at != NULL)
  1045.    {
  1046.       address = strdup(at+1);
  1047.    }
  1048.    else
  1049.    {
  1050.      address = strdup("");
  1051.    }
  1052.  
  1053.    if (strcmp(address,"") == 0)
  1054.    {
  1055.       result = Otcl::setTclError(interp,NOT_REMOTE_OBJECT_ERR,symRef);
  1056.    }
  1057.    else 
  1058.    {
  1059.       result = TCL_OK;
  1060.    }
  1061. }
  1062.  
  1063. OtclRemoteObject::~OtclRemoteObject ()
  1064. {
  1065.    free(remoteSymRef);
  1066.    free(address);
  1067. }
  1068.  
  1069. int OtclRemoteObject::executeMethod (Tcl_Interp *interp, char *method,
  1070.                                      int argc, char *argv[])
  1071. {
  1072.    OtclInstanceMethodRqst rqst(remoteSymRef,method,argc,argv);
  1073.  
  1074.    OtclResponse *response =
  1075.       OtclOserver::sendRequest(interp,address,&rqst);
  1076.  
  1077.    response->setTclInterp(interp);
  1078.    int returnValue = response->getReturnValue();
  1079.  
  1080.    delete response;
  1081.  
  1082.    return returnValue;
  1083. }
  1084.  
  1085. int OtclRemoteObject::discard (Tcl_Interp *interp, int)
  1086. {
  1087.    OtclDeleteObjectRqst rqst(remoteSymRef);
  1088.  
  1089.    OtclResponse *response = OtclOserver::sendRequest(interp,address,&rqst);
  1090.  
  1091.    response->setTclInterp(interp);
  1092.    int returnValue = response->getReturnValue();
  1093.    delete response;
  1094.  
  1095.    delete this;
  1096.  
  1097.    return returnValue;
  1098. }
  1099.  
  1100. int OtclRemoteObject::discard (Tcl_Interp *interp, char *sr)
  1101. {
  1102.    OtclDeleteObjectRqst rqst(sr);
  1103.  
  1104.    char *addr = strchr(sr,'@');
  1105.    if (addr != NULL)
  1106.    {
  1107.       addr++;
  1108.    }
  1109.    else
  1110.    {
  1111.       return Otcl::setTclError(interp,OTCL_BAD_REMOTE_OBJECT_ERR,addr);
  1112.    }
  1113.  
  1114.    OtclResponse *response = OtclOserver::sendRequest(interp,addr,&rqst);
  1115.  
  1116.    response->setTclInterp(interp);
  1117.    int returnValue = response->getReturnValue();
  1118.    delete response;
  1119.  
  1120.    return returnValue;
  1121. }
  1122.  
  1123. OtclDeleteObjectRqst::OtclDeleteObjectRqst ()
  1124. {
  1125.    symRef = NULL;
  1126. }
  1127.  
  1128. OtclDeleteObjectRqst::OtclDeleteObjectRqst (char *sr)
  1129. {
  1130.    symRef = strdup(sr);
  1131. }
  1132.  
  1133. OtclDeleteObjectRqst::~OtclDeleteObjectRqst ()
  1134. {
  1135.    if (symRef != NULL)
  1136.    {
  1137.       free(symRef);
  1138.    }
  1139. }
  1140.  
  1141. int OtclDeleteObjectRqst::streamIn (OtclChannel *channel)
  1142. {
  1143.    if (symRef != NULL)
  1144.    {
  1145.       free(symRef);
  1146.    }
  1147.  
  1148.    return channel->streamInNullTerminated(symRef);
  1149. }
  1150.  
  1151. int OtclDeleteObjectRqst::streamOut (OtclChannel *channel)
  1152. {
  1153.    if (channel->streamOut(DELETE_OBJECT_RQST) == -1)
  1154.    {
  1155.       return -1;
  1156.    }
  1157.    return channel->streamOutNullTerminated(symRef);
  1158. }
  1159.  
  1160. int OtclDeleteObjectRqst::perform (Tcl_Interp *interp)
  1161. {
  1162.    return Otcl::otclPtr->discard(interp,symRef,OTCL_FALSE);
  1163. }
  1164.  
  1165.  
  1166.  
  1167.  
  1168. OtclClassMethodRqst::OtclClassMethodRqst ()
  1169. {
  1170.    name = NULL;
  1171.    method = NULL;
  1172.    argc = 0;
  1173.    argv = NULL;
  1174. }
  1175.  
  1176. OtclClassMethodRqst::OtclClassMethodRqst (char *nameParam, char *methodParam,
  1177.                                   long argcParam, char *argvParam[])
  1178. {
  1179.    name = strdup(nameParam);
  1180.    method = strdup(methodParam);
  1181.    argc = argcParam;
  1182.  
  1183.    if (argc != 0)
  1184.    {
  1185.       argv = (char**)malloc((unsigned int)argc * sizeof(char*));
  1186.       for (long l = 0; l < argc; l++)
  1187.       {
  1188.          argv[l] = strdup(argvParam[l]);
  1189.       }
  1190.    }
  1191.    else
  1192.    {
  1193.       argv = NULL;
  1194.    }
  1195. }
  1196.  
  1197. OtclClassMethodRqst::~OtclClassMethodRqst ()
  1198. {
  1199.    clear();
  1200. }
  1201.  
  1202. void OtclClassMethodRqst::clear (void)
  1203. {
  1204.    if (name != NULL)
  1205.    {
  1206.       free(name);
  1207.    }
  1208.    if (name != NULL)
  1209.    {
  1210.       free(method);
  1211.    }
  1212.    if (argv != NULL)
  1213.    {
  1214.       for (long l = 0; l < argc; l++)
  1215.       {
  1216.          free(argv[l]);
  1217.       }
  1218.       free(argv);
  1219.    }
  1220. }
  1221.  
  1222. int OtclClassMethodRqst::streamOut (OtclChannel *channel)
  1223. {
  1224.    if (channel->streamOut(CLASS_METHOD_RQST) == -1)
  1225.    {
  1226.       return -1;
  1227.    }
  1228.    if (channel->streamOutNullTerminated(name) == -1)
  1229.    {
  1230.       return -1;
  1231.    }
  1232.    if (channel->streamOutNullTerminated(method) == -1)
  1233.    {
  1234.      return -1;
  1235.    }
  1236.    if (channel->streamOut(argc) == -1)
  1237.    {
  1238.      return -1;
  1239.    }
  1240.    for (long l = 0; l < argc; l++)
  1241.    {
  1242.       if (channel->streamOutNullTerminated(argv[l]) == -1)
  1243.       {
  1244.          return -1;
  1245.       }
  1246.    }
  1247.  
  1248.    return 0;
  1249. }
  1250.  
  1251. int OtclClassMethodRqst::streamIn (OtclChannel *channel)
  1252. {
  1253.    clear();
  1254.    if (channel->streamInNullTerminated(name) == -1)
  1255.    {
  1256.       return -1;
  1257.    }
  1258.    if (channel->streamInNullTerminated(method) == -1)
  1259.    {
  1260.       return -1;
  1261.    }
  1262.    if (channel->streamIn(argc) == -1)
  1263.    {
  1264.       return -1;
  1265.    }
  1266.    if (argc != 0)
  1267.    {
  1268.       argv = (char**)malloc((unsigned int)argc * sizeof(char*));
  1269.    }
  1270.    else
  1271.    {
  1272.       argv = NULL;
  1273.    }
  1274.    for (long l = 0; l < argc; l++)
  1275.    {
  1276.       if (channel->streamInNullTerminated(argv[l]) == -1)
  1277.       {
  1278.          return -1;
  1279.       }
  1280.    }
  1281.  
  1282.    return 0;
  1283. }
  1284.  
  1285. int OtclClassMethodRqst::perform (Tcl_Interp *interp)
  1286. {
  1287.    // Dont like thus one, come back to it!
  1288.    char command[256];
  1289.  
  1290.    sprintf(command,"%s %s",name,method);
  1291.    for (int l = 0; l < argc; l++)
  1292.    {
  1293.       strcat(command," {");
  1294.       strcat(command,argv[l]);
  1295.       strcat(command,"}");
  1296.    }
  1297.  
  1298.    return Tcl_Eval(interp,command);
  1299. }
  1300.  
  1301.  
  1302.  
  1303.  
  1304.  
  1305. OtclNewObjectRqst::OtclNewObjectRqst ()
  1306. {
  1307.    className = NULL;
  1308.    argc = 0;
  1309.    argv = NULL;
  1310. }
  1311.  
  1312. OtclNewObjectRqst::OtclNewObjectRqst (char *cn, long argcParam,
  1313.                                       char *argvParam[])
  1314. {
  1315.    className = strdup(cn);
  1316.    argc = argcParam;
  1317.    if (argc != 0)
  1318.    {
  1319.       argv = (char**)malloc((unsigned int)argc * sizeof(char*));
  1320.       for (long l = 0; l < argc; l++)
  1321.       {
  1322.          argv[l] = strdup(argvParam[l]);
  1323.       }
  1324.    }
  1325. }
  1326.  
  1327. OtclNewObjectRqst::~OtclNewObjectRqst ()
  1328. {
  1329.    if (className != NULL)
  1330.    {
  1331.       free(className);
  1332.    }
  1333.    if (argc != 0)
  1334.    {
  1335.       for (long l = 0; l < argc; l++)
  1336.       {
  1337.          free(argv[l]);
  1338.       }
  1339.       free(argv);
  1340.    }
  1341. }
  1342.  
  1343. int OtclNewObjectRqst::streamIn (OtclChannel *channel)
  1344. {
  1345.    if (className != NULL)
  1346.    {
  1347.       free(className);
  1348.    }
  1349.    if (argc != 0)
  1350.    {
  1351.       for (long l = 0; l < argc; l++)
  1352.       {
  1353.          free(argv[l]);
  1354.       }
  1355.       free(argv);
  1356.    }
  1357.  
  1358.    if (channel->streamInNullTerminated(className) == -1)
  1359.    {
  1360.       return -1;
  1361.    }
  1362.    if (channel->streamIn(argc) == -1)
  1363.    {
  1364.       return -1;
  1365.    }
  1366.    if (argc != 0)
  1367.    {
  1368.       argv = (char **)malloc((unsigned int)argc * sizeof(char*));
  1369.       for (int l = 0; l < argc; l++)
  1370.       {
  1371.          if (channel->streamInNullTerminated(argv[l]) == -1)
  1372.          {
  1373.             return -1;
  1374.          }
  1375.       }
  1376.    }
  1377.  
  1378.    return 0;
  1379. }
  1380.  
  1381. int OtclNewObjectRqst::streamOut (OtclChannel *channel)
  1382. {
  1383.    if (channel->streamOut(NEW_OBJECT_RQST) == -1)
  1384.    {
  1385.       return -1;
  1386.    }
  1387.    if (channel->streamOutNullTerminated(className) == -1)
  1388.    {
  1389.       return -1;
  1390.    }
  1391.    if (channel->streamOut(argc) == -1)
  1392.    {
  1393.       return -1;
  1394.    }
  1395.    if (argc != 0)
  1396.    {
  1397.       for (long l = 0; l < argc; l++)
  1398.       {
  1399.          if (channel->streamOutNullTerminated(argv[l]) == -1)
  1400.          {
  1401.             return -1;
  1402.          }
  1403.       }
  1404.    }
  1405.  
  1406.    return 0;
  1407. }
  1408.  
  1409. int OtclNewObjectRqst::perform (Tcl_Interp *interp)
  1410. {
  1411.    return Otcl::otclPtr->instantiate(interp,className,(int)argc,argv);
  1412. }
  1413.  
  1414.  
  1415.  
  1416.  
  1417. OtclRemoteClass::OtclRemoteClass (Tcl_Interp *interp, char *n, char *a)
  1418. {
  1419.    name = strdup(n);
  1420.    address = strdup(a);
  1421.  
  1422.    Tcl_CreateCommand(interp,name,OtclRemoteClass::classCmd,
  1423.                      (ClientData)this,(Tcl_CmdDeleteProc*)NULL);
  1424. }
  1425.  
  1426. OtclRemoteClass::~OtclRemoteClass ()
  1427. {
  1428.    // remove the command!
  1429.    // Tcl_DeleteCommand(interp,name); Hummmm where should this be done!
  1430.    // TO DO!
  1431.  
  1432.    free(name);
  1433.    free(address);
  1434. }
  1435.  
  1436. int OtclRemoteClass::instantiate (Tcl_Interp *interp, int argc, char *argv[])
  1437. {
  1438.    OtclNewObjectRqst rqst(name,argc,argv);
  1439.  
  1440.    OtclResponse *response = OtclOserver::sendRequest(interp, address,&rqst);
  1441.  
  1442.    response->setTclInterp(interp);
  1443.    int returnValue = response->getReturnValue();
  1444.    delete response;
  1445.  
  1446.    return returnValue;
  1447. }
  1448.  
  1449. int OtclRemoteClass::classCmd (ClientData cd, Tcl_Interp *interp, int argc,
  1450.                                char *argv[])
  1451. {
  1452.    ARGC_MIN(2)
  1453.    {
  1454.       return Otcl::setTclError(interp,ARGS_CLASS_CMD_ERR);
  1455.    }
  1456.    OtclRemoteClass *otclc = (OtclRemoteClass*)cd;
  1457.    return otclc->classMethod(interp,argc,argv);
  1458. }
  1459.  
  1460. int OtclRemoteClass::classMethod (Tcl_Interp *interp, int argc, char *argv[])
  1461. {
  1462.    ARGC_MIN(2)
  1463.    {
  1464.       return Otcl::setTclError(interp,ARGS_CLASS_METHOD_EXE_ERR);
  1465.    }
  1466.  
  1467.    OtclClassMethodRqst rqst(name,argv[1], argc-2,
  1468.                             (argc == 2? NULL : &argv[2]));
  1469.  
  1470.    OtclResponse *response = OtclOserver::sendRequest(interp, address,&rqst);
  1471.  
  1472.    response->setTclInterp(interp);
  1473.    int returnValue = response->getReturnValue();
  1474.    delete response;
  1475.  
  1476.    return returnValue;
  1477. }
  1478.  
  1479. void OtclRemoteClass::setAddress (char *addr, char *n)
  1480. {
  1481.    if (address != NULL)
  1482.    {
  1483.       free(address);
  1484.    }
  1485.    address = strdup(addr);
  1486.  
  1487.    if (name != NULL)
  1488.    {
  1489.       free(name);
  1490.    }
  1491.    name = strdup(n);
  1492. }
  1493.