home *** CD-ROM | disk | FTP | other *** search
/ Borland Programmer's Resource / Borland_Programmers_Resource_CD_1995.iso / code / wxwin140 / src / wx_ipc.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-19  |  30.8 KB  |  1,422 lines

  1. /*
  2.  * File:     wx_ipc.cc
  3.  * Purpose:  Interprocess communication implementation
  4.  *
  5.  *                       wxWindows 1.40
  6.  * Copyright (c) 1993 Artificial Intelligence Applications Institute,
  7.  *                   The University of Edinburgh
  8.  *
  9.  *                     Author: Julian Smart
  10.  *                       Date: 18-4-93
  11.  *
  12.  * Permission to use, copy, modify, and distribute this software and its
  13.  * documentation for any purpose is hereby granted without fee, provided
  14.  * that the above copyright notice, author statement and this permission
  15.  * notice appear in all copies of this software and related documentation.
  16.  *
  17.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, EXPRESS,
  18.  * IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF
  19.  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
  20.  *
  21.  * IN NO EVENT SHALL THE ARTIFICIAL INTELLIGENCE APPLICATIONS INSTITUTE OR THE
  22.  * UNIVERSITY OF EDINBURGH BE LIABLE FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR
  23.  * CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM
  24.  * LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF
  25.  * DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH
  26.  * THE USE OR PERFORMANCE OF THIS SOFTWARE.
  27.  */
  28.  
  29. #include <windows.h>
  30. #include <iostream.h>
  31. #include <stdio.h>
  32. #include <math.h>
  33.  
  34. #include "common.h"
  35. #include "wx_main.h"
  36. #include "wx_frame.h"
  37. #include "wx_event.h"
  38. #include "wx_utils.h"
  39. #include "wx_ipc.h"
  40.  
  41. #ifdef wx_x
  42. #include <sys/types.h>
  43. #include <sys/socket.h>
  44. #include <netinet/in.h>
  45. #include <unistd.h>
  46. #include <signal.h>
  47. #include <sys/wait.h>
  48. #include <sys/un.h>
  49. #include <netdb.h>
  50.  
  51. #define wxFAMILY(s) s.addr.sa_family
  52. #define wxNAMELEN(s) (wxFAMILY(s) == AF_INET \
  53.             ? sizeof(s.inaddr) \
  54.             : strlen(s.unaddr.sun_path) + sizeof(s.unaddr) - sizeof(s.unaddr.sun_path))
  55.  
  56. extern errno;
  57. int wx_socket_create(int port);
  58. // Add NULL-terminated string to buffer, returning next start point
  59. int wxAddString(int start, char *info, char *buffer, int size = -1);
  60.  
  61. // Get next NULL-terminated string from buffer
  62. char *wxGetNextString(char *buffer);
  63. #endif
  64.  
  65. #ifdef wx_xview
  66. #include <xview/xview.h>
  67. #include <xview/panel.h>
  68. Notify_value wx_input_ready(Notify_client client, int fd);
  69. Notify_value wx_accept_connection(Notify_client client, int fd);
  70. #endif
  71.  
  72. #ifdef wx_motif
  73. Bool wx_input_ready(XtPointer client, int *fid, XtInputId *id);
  74. Bool wx_accept_connection(XtPointer client, int *fid, XtInputId *id);
  75. #endif
  76.  
  77. #ifdef wx_msw
  78. #include <ddeml.h>
  79. wxConnection *wxFindConnection(HCONV hConv);
  80. void wxDeleteConnection(HCONV hConv);
  81. wxServer *wxFindServer(char *s);
  82.  
  83. extern "C" HDDEDATA EXPENTRY _export wxDdeCallback(
  84. WORD wType,
  85. WORD wFmt,
  86. HCONV hConv,
  87. HSZ hsz1,
  88. HSZ hsz2,
  89. HDDEDATA hData,
  90. DWORD lData1,
  91. DWORD lData2);
  92. #endif
  93.  
  94. // Add topic name to atom table before using in conversations
  95. void wxAddAtom(char *string);
  96.  
  97. #ifdef wx_msw
  98. HSZ wxGetAtom(char *string);
  99. #endif
  100.  
  101. #ifdef wx_msw
  102. #include <ddeml.h>
  103. DWORD wxIdInst = 0L;
  104. wxConnection *wxCurrentlyConnecting = NULL;
  105. #endif
  106.  
  107. #ifdef wx_msw
  108. wxList wxAtomTable(wxKEY_STRING);
  109. wxList wxIPCObjects;
  110. #endif
  111.  
  112. char *wxDefaultIPCBuffer = NULL;
  113. int wxDefaultIPCBufferSize = 4000;
  114.  
  115. /*
  116.  * Initialization
  117.  *
  118.  */
  119.  
  120. static Bool wxIPCInitialized;
  121.  
  122. void wxIPCInitialize(void)
  123. {
  124.   if (wxIPCInitialized)
  125.     return;
  126.   wxIPCInitialized = TRUE;
  127. #ifdef wx_msw
  128.   // Should insert filter flags
  129.   DdeInitialize(&wxIdInst, (PFNCALLBACK)MakeProcInstance(
  130.                (FARPROC)wxDdeCallback, wxTheApp->hInstance),
  131.                APPCLASS_STANDARD,
  132.                0L);
  133. #endif
  134. }
  135.  
  136. wxIPCObject::wxIPCObject(void)
  137. {
  138.   service_name = NULL;
  139. #ifdef wx_msw
  140.   wxIPCObjects.Append(this);
  141. #endif
  142. }
  143.  
  144. wxIPCObject::~wxIPCObject(void)
  145. {
  146.   if (service_name)
  147.     delete service_name;
  148.  
  149.   wxNode *node = connections.First();
  150.   while (node)
  151.   {
  152.     wxConnection *connection = (wxConnection *)node->Data();
  153.     wxNode *next = node->Next();
  154.     connection->OnDisconnect(); // May delete the node implicitly
  155.     node = next;
  156.   }
  157.  
  158.   // If any left after this, delete them
  159.   node = connections.First();
  160.   while (node)
  161.   {
  162.     wxConnection *connection = (wxConnection *)node->Data();
  163.     delete connection;
  164.     node = connections.First();
  165.   }
  166. #ifdef wx_msw
  167.   wxIPCObjects.DeleteObject(this);
  168. #endif
  169. }
  170.  
  171. #ifdef wx_msw
  172. // Global find connection
  173. wxConnection *wxFindConnection(HCONV hConv)
  174. {
  175.   wxNode *node = wxIPCObjects.First();
  176.   wxConnection *found = NULL;
  177.   while (node && !found)
  178.   {
  179.     wxIPCObject *object = (wxIPCObject *)node->Data();
  180.     found = object->FindConnection(hConv);
  181.     node = node->Next();
  182.   }
  183.   return found;
  184. }
  185.  
  186. // Global delete connection
  187. void wxDeleteConnection(HCONV hConv)
  188. {
  189.   wxNode *node = wxIPCObjects.First();
  190.   Bool found = FALSE;
  191.   while (node && !found)
  192.   {
  193.     wxIPCObject *object = (wxIPCObject *)node->Data();
  194.     found = object->DeleteConnection(hConv);
  195.     node = node->Next();
  196.   }
  197. }
  198.  
  199. wxConnection *wxIPCObject::FindConnection(HCONV conv)
  200. {
  201.   wxNode *node = connections.First();
  202.   wxConnection *found = NULL;
  203.   while (node && !found)
  204.   {
  205.     wxConnection *connection = (wxConnection *)node->Data();
  206.     if (connection->hConv == conv)
  207.       found = connection;
  208.     else node = node->Next();
  209.   }
  210.   return found;
  211. }
  212.  
  213. Bool wxIPCObject::DeleteConnection(HCONV conv)
  214. {
  215.   wxNode *node = connections.First();
  216.   Bool found = FALSE;
  217.   while (node && !found)
  218.   {
  219.     wxConnection *connection = (wxConnection *)node->Data();
  220.     if (connection->hConv == conv)
  221.     {
  222.       found = TRUE;
  223.       delete node;
  224.     }
  225.     else node = node->Next();
  226.   }
  227.   return found;
  228. }
  229.  
  230. // Find a server from a service name
  231. wxServer *wxFindServer(char *s)
  232. {
  233.   wxNode *node = wxIPCObjects.First();
  234.   wxServer *found = NULL;
  235.   while (node && !found)
  236.   {
  237.     wxIPCObject *object = (wxIPCObject *)node->Data();
  238.     if (object->service_name && strcmp(object->service_name, s) == 0)
  239.       found = (wxServer *)object;
  240.     else node = node->Next();
  241.   }
  242.   return found;
  243. }
  244. #endif
  245.  
  246. /*
  247.  * Server
  248.  *
  249.  */
  250.  
  251. wxServer::wxServer(void)
  252. {
  253. }
  254.  
  255. Bool wxServer::Create(char *server_name)
  256. {
  257.   service_name = copystring(server_name);
  258. #ifdef wx_x
  259.   // Under UNIX, server should be an integer inside a string!
  260.   int the_port = 0;
  261.   sscanf(server_name, "%d", &the_port);
  262.  
  263.   /* Create a socket listening on specified port */
  264.   server_socket = wx_socket_create(the_port);
  265.   if (server_socket < 0)
  266.     return FALSE;
  267.  
  268.   Bool notify_toplevel = FALSE;
  269.   wxConnection *toplevel = this->OnAcceptConnection("STDIO");
  270.   if (toplevel)
  271.   {
  272.     toplevel->input_fd = 0;
  273.     toplevel->output_fd = 1;
  274.     notify_toplevel = TRUE;
  275.     toplevel->topic_name = copystring("STDIO");
  276.   }
  277.   else toplevel = new wxConnection(NULL, 0); // Create a dummy connection
  278.  
  279.   toplevel->server = this;
  280.   connections.Append(toplevel);
  281.  
  282.   /* Register stdin (IF APP ALLOWS IT) and the socket with the notifier */
  283.  
  284. #ifdef wx_xview
  285.   // stdin
  286.   if (notify_toplevel)
  287.     notify_set_input_func((Notify_client)toplevel, &wx_input_ready, 0);
  288.  
  289.   // Top level port
  290.   notify_set_input_func((Notify_client)toplevel, &wx_accept_connection, server_socket);
  291. #endif
  292. #ifdef wx_motif
  293.   XtAppAddInput(wxTheApp->appContext, server_socket, XtInputReadMask, wx_accept_connection, toplevel);
  294. #endif
  295.   return TRUE;
  296. #endif
  297. #ifdef wx_msw
  298.   HSZ wxServiceName = DdeCreateStringHandle(wxIdInst, server_name, CP_WINANSI);
  299.  
  300.   DdeNameService(wxIdInst, wxServiceName, NULL, DNS_REGISTER);
  301.   return TRUE;
  302. #endif
  303. }
  304.  
  305. wxServer::~wxServer(void)
  306. {
  307. #ifdef wx_motif
  308. #endif
  309. #ifdef wx_xview
  310.   close(server_socket);
  311. #endif
  312. }
  313.  
  314. // Default behaviour for accepting a connection
  315. wxConnection *wxServer::OnAcceptConnection(char *topic)
  316. {
  317.   return new wxConnection;
  318. }
  319.  
  320.  
  321. /*
  322.  * Client
  323.  *
  324.  */
  325.  
  326.  
  327. wxClient::wxClient(void)
  328. {
  329. #ifdef wx_msw
  330. #endif
  331. }
  332.  
  333. wxClient::~wxClient(void)
  334. {
  335.   wxNode *node = connections.First();
  336.   while (node)
  337.   {
  338.     wxConnection *connection = (wxConnection *)node->Data();
  339.     delete connection;  // Deletes the node implicitly (see ~wxConnection)
  340.     node = connections.First();
  341.   }
  342. }
  343.  
  344. Bool wxClient::ValidHost(char *host)
  345. {
  346. #ifdef wx_x
  347.   if (gethostbyname(host))
  348.     return TRUE;
  349.   else
  350.     return FALSE;
  351. #endif
  352. #ifdef wx_msw
  353.   return TRUE;
  354. #endif
  355. }
  356.  
  357. wxConnection *wxClient::MakeConnection(char *host, char *server_name, char *topic)
  358. {
  359. #ifdef wx_x
  360.     int port;
  361.     sscanf(server_name, "%d", &port);
  362.  
  363.     union {struct sockaddr addr;
  364.        struct sockaddr_un unaddr;
  365.        struct sockaddr_in inaddr;} s;
  366.  
  367.     struct hostent *server;
  368.  
  369.     int fd;
  370.  
  371.     bzero(&s.inaddr, sizeof(s.inaddr));
  372.     server = gethostbyname(host);
  373.     if(server == (struct hostent *)0)
  374.     {
  375.       perror("sockio: gethostbyname failed");
  376.       return NULL;
  377.     }
  378.     bcopy(server->h_addr, &s.inaddr.sin_addr, server->h_length);
  379.     s.inaddr.sin_family = AF_INET;
  380.     s.inaddr.sin_port = htons(port);
  381.  
  382.     fd = socket(wxFAMILY(s), SOCK_STREAM, 0);
  383.     if(fd < 0)
  384.     {
  385.     perror("sockio: socket failed");
  386.         return NULL;
  387.     }
  388.  
  389.     if (connect(fd, &s.addr, wxNAMELEN(s)) == 0)
  390.     {
  391.       // Send topic name, and enquire whether this has succeeded
  392.       char buf[200];
  393.       buf[0] = wxCONNECT;
  394.       strcpy(buf+1, topic);
  395.       write(fd, buf, strlen(topic)+2);
  396.       read(fd, buf, 200);
  397.       // OK! Confirmation.
  398.       if (buf[0] == wxCONNECT)
  399.       {
  400.         wxConnection *connection = OnMakeConnection();
  401.         if (connection)
  402.         {
  403.           connections.Append(connection);
  404.           connection->input_fd = fd;
  405.           connection->output_fd = fd;
  406.           connection->client = this;
  407.  
  408.           // Register with the notifier
  409.           connection->Notify(TRUE);
  410.           return connection;
  411.         }
  412.         else { close(fd); return NULL; }
  413.       }
  414.       else
  415.       {
  416.         close(fd);
  417.         return NULL;
  418.       }
  419.     }
  420.     else
  421.     {
  422.       close(fd);
  423.       return NULL;
  424.     }
  425. /*
  426.     if(errno == ENOENT)
  427.     {
  428.         fprintf(stderr, "socket doesn't exist, retrying after 5 secs\n");
  429.         sleep(5);
  430.     }
  431.     else
  432.     {
  433.         perror("sockio: connect failed");
  434.         exit(1);
  435.     }
  436. */
  437. #endif
  438. #ifdef wx_msw
  439.   HSZ wxServiceName = DdeCreateStringHandle(wxIdInst, server_name, CP_WINANSI);
  440.   HSZ topic_atom = DdeCreateStringHandle(wxIdInst, topic, CP_WINANSI);
  441.  
  442.   HCONV hConv = DdeConnect(wxIdInst, wxServiceName, topic_atom, (PCONVCONTEXT)NULL);
  443.   if (hConv == NULL)
  444.     return NULL;
  445.   else
  446.   {
  447.     wxConnection *connection = OnMakeConnection();
  448.     if (connection)
  449.     {
  450.       connection->hConv = hConv;
  451.       connection->topic_name = copystring(topic);
  452.       connections.Append(connection);
  453.       return connection;
  454.     }
  455.     else return NULL;
  456.   }
  457. #endif
  458. }
  459.  
  460. wxConnection *wxClient::OnMakeConnection(void)
  461. {
  462.   return new wxConnection;
  463. }
  464.  
  465. /*
  466.  * Connection
  467.  */
  468.  
  469. wxConnection::wxConnection(char *buffer, int size)
  470. {
  471.   if (buffer == NULL)
  472.   {
  473.     if (wxDefaultIPCBuffer == NULL)
  474.       wxDefaultIPCBuffer = new char[wxDefaultIPCBufferSize];
  475.     buf_ptr = wxDefaultIPCBuffer;
  476.     buf_size = wxDefaultIPCBufferSize;
  477.   }
  478.   else
  479.   {
  480.     buf_ptr = buffer;
  481.     buf_size = size;
  482.   }
  483.  
  484.   topic_name = NULL;
  485.  
  486.   client = NULL;
  487.   server = NULL;
  488. #ifdef wx_x
  489.   input_fd = 0;
  490.   output_fd = 0;
  491. #endif
  492. #ifdef wx_msw
  493.   hConv = NULL;
  494.   sending_data = NULL;
  495. #endif
  496. }
  497.  
  498. wxConnection::wxConnection(void)
  499. {
  500.   if (wxDefaultIPCBuffer == NULL)
  501.     wxDefaultIPCBuffer = new char[wxDefaultIPCBufferSize];
  502.  
  503.   buf_ptr = wxDefaultIPCBuffer;
  504.   buf_size = wxDefaultIPCBufferSize;
  505.  
  506.   topic_name = NULL;
  507.   client = NULL;
  508.   server = NULL;
  509. #ifdef wx_x
  510.   input_fd = 0;
  511.   output_fd = 0;
  512. #endif
  513. #ifdef wx_motif
  514.   xtInputId = 0;
  515. #endif
  516. #ifdef wx_msw
  517.   hConv = NULL;
  518.   sending_data = NULL;
  519. #endif
  520. }
  521.  
  522. wxConnection::~wxConnection(void)
  523. {
  524. #ifdef wx_motif
  525.   if (xtInputId > 0)
  526.    XtRemoveInput(xtInputId);
  527. #endif
  528. #ifdef wx_xview
  529.   notify_set_input_func((Notify_client)this, (Notify_func)0, input_fd);
  530. #endif
  531. #ifdef wx_x
  532.   if (input_fd != 0)
  533.     close(input_fd);
  534.   if (output_fd != 0)
  535.     close(output_fd);
  536.  
  537.   if (server)
  538.     server->connections.DeleteObject(this);
  539.   if (client)
  540.     client->connections.DeleteObject(this);
  541.   if (topic_name)
  542.     delete topic_name;
  543. #endif
  544. }
  545.  
  546. Bool wxConnection::OnDisconnect(void)
  547. {
  548.   // Default action is to delete itself
  549.   delete this;
  550.   return TRUE;
  551. }
  552.  
  553. // Callbacks to SERVER - override at will
  554. Bool wxConnection::OnExecute(char *topic, char *data, int size, int format)
  555. {
  556.   return FALSE;
  557. }
  558.  
  559. char *wxConnection::OnRequest(char *topic, char *item, int *size, int format)
  560. {
  561.   return NULL;
  562. }
  563.  
  564. Bool wxConnection::OnPoke(char *topic, char *item, char *data, int size, int format)
  565. {
  566.   return FALSE;
  567. }
  568.  
  569. Bool wxConnection::OnStartAdvise(char *topic, char *item)
  570. {
  571.   return TRUE;
  572. }
  573.  
  574. Bool wxConnection::OnStopAdvise(char *topic, char *item)
  575. {
  576.   return TRUE;
  577. }
  578.  
  579.  
  580. // Callbacks to CLIENT - override at will
  581. Bool wxConnection::OnAdvise(char *topic, char *item, char *data, int size, int format)
  582. {
  583.   return FALSE;
  584. }
  585.  
  586. // Calls that CLIENT can make
  587. Bool wxConnection::Disconnect(void)
  588. {
  589. #ifdef wx_x
  590.   buf_ptr[0] = wxDISCONNECT;
  591.   write(output_fd, buf_ptr, 1);
  592. #endif
  593. #ifdef wx_motif
  594.   if (xtInputId)
  595.     XtRemoveInput(xtInputId);
  596.   xtInputId = 0;
  597. #endif
  598. #ifdef wx_xview
  599.   notify_set_input_func((Notify_client)this, (Notify_func)0, input_fd);
  600. #endif
  601. #ifdef wx_x
  602.   if (input_fd != 0)
  603.     close(input_fd);
  604.   if (output_fd != 0)
  605.     close(output_fd);
  606.   input_fd = 0;
  607.   output_fd = 0;
  608.  
  609.   return TRUE;
  610. #endif
  611. #ifdef wx_msw
  612.   wxDeleteConnection(hConv);
  613.   return DdeDisconnect(hConv);
  614. #endif
  615. }
  616.  
  617. Bool wxConnection::Execute(char *data, int size, int format)
  618. {
  619. #ifdef wx_x
  620.   if (size < 0)
  621.     size = strlen(data);
  622.  
  623.   char format_buf[10];
  624.   sprintf(format_buf, "%d", format);
  625.  
  626.   buf_ptr[0] = wxEXECUTE;
  627.   int pos = wxAddString(1, format_buf, buf_ptr);
  628.   pos = wxAddString(pos, data, buf_ptr, size);
  629.  
  630.   write(output_fd, buf_ptr, pos);
  631.   return TRUE;
  632. #endif
  633. #ifdef wx_msw
  634.   DWORD result;
  635.   if (size < 0)
  636.     size = strlen(data);
  637.  
  638.   size ++;
  639.  
  640.   DdeClientTransaction((void FAR *)data, size, hConv,
  641.     NULL, format, XTYP_EXECUTE, 5000, &result);
  642.  
  643.   return TRUE;
  644. #endif
  645. }
  646.  
  647. char *wxConnection::Request(char *item, int *size, int format)
  648. {
  649. #ifdef wx_x
  650.   char format_buf[10];
  651.   sprintf(format_buf, "%d", format);
  652.  
  653.   buf_ptr[0] = wxREQUEST;
  654.   int pos = wxAddString(1, item, buf_ptr);
  655.   pos = wxAddString(pos, format_buf, buf_ptr);
  656.  
  657. #ifdef wx_xview
  658.   Notify(FALSE);
  659. #endif
  660.   write(output_fd, buf_ptr, pos);
  661.   read(input_fd, buf_ptr, buf_size);
  662. #ifdef wx_xview
  663.   Notify(TRUE);
  664. #endif
  665.  
  666.   if (buf_ptr[0] == wxFAIL)
  667.     return NULL;
  668.   else
  669.   {
  670.     char *new_item = buf_ptr + 1;
  671.     char *data = wxGetNextString(new_item);
  672.     if (size) *size = data-new_item;
  673.     return data;
  674.   }
  675. #endif
  676. #ifdef wx_msw
  677.   DWORD result;
  678.   HSZ atom = wxGetAtom(item);
  679.  
  680.   HDDEDATA returned_data = DdeClientTransaction(NULL, 0, hConv,
  681.     atom, format, XTYP_REQUEST, 5000, &result);
  682.  
  683.   DWORD len = DdeGetData(returned_data, (LPBYTE)(buf_ptr), buf_size, 0);
  684.  
  685.   DdeFreeDataHandle(returned_data);
  686.  
  687.   if (size) *size = (int)len;
  688.   if (len > 0)
  689.   {
  690.     return buf_ptr;
  691.   }
  692.   else return NULL;
  693. #endif
  694. }
  695.  
  696. Bool wxConnection::Poke(char *item, char *data, int size, int format)
  697. {
  698. #ifdef wx_x
  699.   char format_buf[10];
  700.   sprintf(format_buf, "%d", format);
  701.  
  702.   if (size < 0)
  703.     size = strlen(data);
  704.  
  705.   buf_ptr[0] = wxPOKE;
  706.   int pos = wxAddString(1, item, buf_ptr);
  707.   pos = wxAddString(pos, format_buf, buf_ptr);
  708.   pos = wxAddString(pos, data, buf_ptr, size);
  709.  
  710.   write(output_fd, buf_ptr, pos);
  711.   return TRUE;
  712. #endif
  713. #ifdef wx_msw
  714.   DWORD result;
  715.   if (size < 0)
  716.     size = strlen(data);
  717.  
  718.   size ++;
  719.  
  720.   HSZ item_atom = wxGetAtom(item);
  721.   DdeClientTransaction((void FAR *)data, size, hConv,
  722.     item_atom, format, XTYP_POKE, 5000, &result);
  723.  
  724.   return TRUE;
  725. #endif
  726. }
  727.  
  728. Bool wxConnection::StartAdvise(char *item)
  729. {
  730. #ifdef wx_x
  731.   buf_ptr[0] = wxADVISE_START;
  732.   int pos = wxAddString(1, item, buf_ptr);
  733.  
  734. #ifdef wx_xview
  735.   Notify(FALSE);
  736. #endif
  737.  
  738.   write(output_fd, buf_ptr, pos);
  739.   read(input_fd, buf_ptr, buf_size);
  740.  
  741. #ifdef wx_xview
  742.   Notify(TRUE);
  743. #endif
  744.  
  745.   if (buf_ptr[0] != wxFAIL)
  746.     return TRUE;
  747.   else
  748.     return FALSE;
  749. #endif
  750. #ifdef wx_msw
  751.   DWORD result;
  752.   HSZ atom = wxGetAtom(item);
  753.  
  754.   DdeClientTransaction(NULL, 0, hConv,
  755.     atom, CF_TEXT, XTYP_ADVSTART, 5000, &result);
  756.  
  757.   return (Bool)result;
  758. #endif
  759. }
  760.  
  761. Bool wxConnection::StopAdvise(char *item)
  762. {
  763. #ifdef wx_x
  764.   buf_ptr[0] = wxADVISE_STOP;
  765.   int pos = wxAddString(1, item, buf_ptr);
  766.  
  767. #ifdef wx_xview
  768.   Notify(FALSE);
  769. #endif
  770.  
  771.   write(output_fd, buf_ptr, pos);
  772.   read(input_fd, buf_ptr, buf_size);
  773.  
  774. #ifdef wx_xview
  775.   Notify(TRUE);
  776. #endif
  777.  
  778.   if (buf_ptr[0] != wxFAIL)
  779.     return TRUE;
  780.   else
  781.     return FALSE;
  782. #endif
  783. #ifdef wx_msw
  784.   DWORD result;
  785.   HSZ atom = wxGetAtom(item);
  786.  
  787.   DdeClientTransaction(NULL, 0, hConv,
  788.     atom, CF_TEXT, XTYP_ADVSTOP, 5000, &result);
  789.  
  790.   return (Bool)result;
  791. #endif
  792. }
  793.  
  794. // Calls that SERVER can make
  795. Bool wxConnection::Advise(char *item, char *data, int size, int format)
  796. {
  797. #ifdef wx_x
  798.   char format_buf[10];
  799.   sprintf(format_buf, "%d", format);
  800.  
  801.   buf_ptr[0] = wxADVISE;
  802.   int pos = wxAddString(1, item, buf_ptr);
  803.   pos = wxAddString(pos, format_buf, buf_ptr);
  804.   pos = wxAddString(pos, data, buf_ptr, size);
  805.  
  806.   write(output_fd, buf_ptr, pos);
  807.   return TRUE;
  808. #endif
  809. #ifdef wx_msw
  810.   if (size < 0)
  811.     size = strlen(data);
  812.  
  813.   size ++;
  814.  
  815.   HSZ item_atom = wxGetAtom(item);
  816.   HSZ topic_atom = wxGetAtom(topic_name);
  817.   sending_data = data;
  818.   data_size = size;
  819.   data_type = format;
  820.   return DdePostAdvise(wxIdInst, topic_atom, item_atom);
  821. #endif
  822. }
  823.  
  824. void wxConnection::Notify(Bool notify)
  825. {
  826. #ifdef wx_motif
  827.   if (!notify)
  828.   {
  829.     if (xtInputId > 0)
  830.       XtRemoveInput(xtInputId);
  831.   }
  832.   else
  833.     xtInputId = XtAppAddInput(wxTheApp->appContext, input_fd, XtInputReadMask, wx_input_ready, this);
  834. #endif
  835. #ifdef wx_xview
  836.   if (notify)
  837.     notify_set_input_func((Notify_client)this, (Notify_func)wx_input_ready, input_fd);
  838.   else
  839.     notify_set_input_func((Notify_client)this, NOTIFY_FUNC_NULL, input_fd);
  840. #endif
  841. }
  842.  
  843. #ifdef wx_x
  844.  
  845. #ifdef wx_xview
  846. Notify_value wx_input_ready(Notify_client client, int fd)
  847. #endif
  848. #ifdef wx_motif
  849. Bool wx_input_ready(XtPointer client, int *fid, XtInputId *id)
  850. #endif
  851. {
  852. #ifdef wx_motif
  853. //  int fd = *fid;
  854. #endif
  855.     wxConnection *connection = (wxConnection *)client;
  856.     int nread = read(connection->input_fd, connection->buf_ptr, connection->buf_size);
  857.  
  858.     if ((nread >= 0) && (nread < connection->buf_size))
  859.       connection->buf_ptr[nread] = 0;
  860.  
  861.     switch(nread)
  862.     { 
  863.       case -1:            /* Error - give up */
  864.         connection->OnDisconnect();
  865.         return FALSE;
  866.         break;
  867.  
  868.       case 0:            /* EOF - de-register descriptor */
  869.       {
  870.         connection->OnDisconnect();
  871.         return FALSE;
  872.         break;
  873.       }
  874.       default:
  875.         break;
  876.    }
  877.    switch (connection->buf_ptr[0])
  878.    {
  879.      case wxEXECUTE:
  880.      {
  881.        char *format_buf = connection->buf_ptr + 1;
  882.        char *data = wxGetNextString(format_buf);
  883.  
  884.        int format = wxCF_TEXT;
  885.        sscanf(format_buf, "%d", &format);
  886.  
  887.        int size = nread - (data - connection->buf_ptr);
  888.        connection->OnExecute(connection->topic_name, data, size, format);
  889.        break;
  890.      }
  891.      case wxADVISE:
  892.      {
  893.        char *item = connection->buf_ptr + 1;
  894.        char *format_buf = wxGetNextString(item);;
  895.        char *data = wxGetNextString(format_buf);
  896.  
  897.        int format = wxCF_TEXT;
  898.        sscanf(format_buf, "%d", &format);
  899.  
  900.        int size = nread - (data - connection->buf_ptr);
  901.        connection->OnAdvise(connection->topic_name, item, data, size, format);
  902.        break;
  903.      }
  904.      case wxADVISE_START:
  905.      {
  906.        char *item = connection->buf_ptr + 1;
  907.        Bool ok = connection->OnStartAdvise(connection->topic_name, item);
  908.        if (ok)
  909.        {
  910.          connection->buf_ptr[0] = wxADVISE_START;
  911.          connection->buf_ptr[1] = 0;
  912.          write(connection->output_fd, connection->buf_ptr, 2);
  913.        }
  914.        else
  915.        {
  916.          connection->buf_ptr[0] = wxFAIL;
  917.          connection->buf_ptr[1] = 0;
  918.          write(connection->output_fd, connection->buf_ptr, 2);
  919.        }
  920.  
  921.        break;
  922.      }
  923.      case wxADVISE_STOP:
  924.      {
  925.        char *item = connection->buf_ptr + 1;
  926.        Bool ok = connection->OnStopAdvise(connection->topic_name, item);
  927.        if (ok)
  928.        {
  929.          connection->buf_ptr[0] = wxADVISE_STOP;
  930.          connection->buf_ptr[1] = 0;
  931.          write(connection->output_fd, connection->buf_ptr, 2);
  932.        }
  933.        else
  934.        {
  935.          connection->buf_ptr[0] = wxFAIL;
  936.          connection->buf_ptr[1] = 0;
  937.          write(connection->output_fd, connection->buf_ptr, 2);
  938.        }
  939.  
  940.        break;
  941.      }
  942.      case wxPOKE:
  943.      {
  944.        char *item = connection->buf_ptr + 1;
  945.        char *format_buf = wxGetNextString(item);;
  946.        char *data = wxGetNextString(format_buf);
  947.  
  948.        int format = wxCF_TEXT;
  949.        sscanf(format_buf, "%d", &format);
  950.  
  951.        int size = nread - (data - connection->buf_ptr);
  952.        connection->OnPoke(connection->topic_name, item, data, size, format);
  953.        break;
  954.      }
  955.      case wxREQUEST:
  956.      {
  957.        char *item = connection->buf_ptr + 1;
  958.        char *format_buf = wxGetNextString(item);;
  959.  
  960.        int format = wxCF_TEXT;
  961.        sscanf(format_buf, "%d", &format);
  962.  
  963.        int user_size = -1;
  964.        char *user_data = connection->OnRequest(connection->topic_name, item, &user_size, format);
  965.        if (user_data)
  966.        {
  967.          connection->buf_ptr[0] = wxREQUEST_REPLY;
  968.          int pos = wxAddString(1, item, connection->buf_ptr);
  969.          pos = wxAddString(pos, user_data, connection->buf_ptr, user_size);
  970.  
  971.          write(connection->output_fd, connection->buf_ptr, pos);
  972.        }
  973.        else
  974.        {
  975.          connection->buf_ptr[0] = wxFAIL;
  976.          connection->buf_ptr[1] = 0;
  977.          write(connection->output_fd, connection->buf_ptr, 2);
  978.        }
  979.  
  980.        break;
  981.      }
  982.      default:
  983.        break;
  984.    }
  985.    return 0;
  986. }
  987.  
  988. #ifdef wx_xview
  989. Notify_value wx_accept_connection(Notify_client client, int fd)
  990. #endif
  991. #ifdef wx_motif
  992. Bool wx_accept_connection(XtPointer client, int *fid, XtInputId *id)
  993. #endif
  994. {
  995. #ifdef wx_motif
  996.   int fd = *fid;
  997. #endif
  998.  
  999.   struct sockaddr_in addr;
  1000.   int newsock, addrlen = sizeof(addr);
  1001.   wxConnection *top_connection = (wxConnection *)client;
  1002.  
  1003.   /* Accept the connection, getting a new socket */
  1004.  
  1005.   newsock = accept(fd, (struct sockaddr *)&addr, &addrlen);
  1006.   if(newsock == -1)
  1007.      printf("Error in accept\n");
  1008.   char buf[300];
  1009.  
  1010.   read(newsock, buf, 300);
  1011.  
  1012.   if (buf[0] == wxCONNECT)
  1013.   {
  1014.     char *topic_name = copystring(buf + 1);
  1015.  
  1016.     /* Register new socket with the notifier */
  1017.     wxConnection *new_connection = top_connection->server->OnAcceptConnection(topic_name);
  1018.     if (new_connection)
  1019.     {
  1020.       // Acknowledge success
  1021.       buf[0] = wxCONNECT;
  1022.       buf[1] = 0;
  1023.       write(newsock, buf, 2);
  1024.  
  1025.       new_connection->input_fd = newsock;
  1026.       new_connection->output_fd = newsock;
  1027.       new_connection->server = top_connection->server;
  1028.       new_connection->topic_name = topic_name;
  1029.       top_connection->server->connections.Append(new_connection);
  1030.  
  1031. #ifdef wx_xview
  1032.       notify_set_input_func((Notify_client)new_connection, &wx_input_ready, newsock);
  1033. #endif
  1034. #ifdef wx_motif
  1035.       new_connection->xtInputId = XtAppAddInput(wxTheApp->appContext, newsock, XtInputReadMask, wx_input_ready, new_connection);
  1036. #endif
  1037.     }
  1038.     else
  1039.     {
  1040.       // Send failure message
  1041.       buf[0] = wxFAIL;
  1042.       buf[1] = 0;
  1043.       write(newsock, buf, 2);
  1044.     }
  1045.   }
  1046.   return 0;
  1047. }
  1048.  
  1049. #endif
  1050.  
  1051. /*
  1052.  * Create an internet socket listening on the specified port.
  1053.  */
  1054.  
  1055. #ifdef wx_x
  1056. int wx_socket_create(int port)
  1057. {
  1058.   struct sockaddr_in addr; int sock;
  1059.  
  1060.   addr.sin_family = AF_INET; 
  1061.   addr.sin_addr.s_addr = htonl(INADDR_ANY); 
  1062.   addr.sin_port = htons(port);
  1063.  
  1064.   sock = socket(AF_INET, SOCK_STREAM, 0);
  1065.   if(bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1)
  1066.   {
  1067.     printf("Error in bind\n");
  1068.     return -1;
  1069.   }
  1070.  
  1071.   listen(sock, 5);
  1072.  
  1073.   return sock;
  1074. }
  1075. #endif
  1076.  
  1077. #ifdef wx_xview
  1078. static Notify_value
  1079. wx_child_died(Notify_client me, int pid, union wait *status, struct rusage *rusage)
  1080. {
  1081.   if (WIFEXITED(*status))
  1082.   {
  1083.     wxChild *child = (wxChild *)me;
  1084.     child->OnDeath();
  1085.     delete child;
  1086.     return NOTIFY_DONE;
  1087.   } else
  1088.     return NOTIFY_IGNORED;
  1089. }
  1090. #endif
  1091.  
  1092. // Pipes
  1093. wxChild::wxChild(void)
  1094. {
  1095.   the_pid = -1;
  1096. }
  1097.  
  1098. Bool wxChild::Create(char *command, char *argv[])
  1099. {
  1100. #ifdef wx_motif
  1101.   return FALSE;
  1102. #endif
  1103. #ifdef wx_xview
  1104.   int to_subprocess[2], from_subprocess[2];
  1105.  
  1106.   pipe(to_subprocess); pipe(from_subprocess);
  1107.  
  1108.   int pid = fork();
  1109.  
  1110.   the_pid = pid;
  1111.   switch(pid)
  1112.   {
  1113.     case -1:
  1114.     return FALSE;
  1115.  
  1116.     case 0:            // child
  1117.  
  1118.     // Copy pipe descriptors to stdin and stdout
  1119.     dup2(to_subprocess[0], 0);     dup2(from_subprocess[1], 1);
  1120.  
  1121.     // Close unwanted descriptors
  1122.  
  1123.     close(to_subprocess[0]);     close(to_subprocess[1]);
  1124.     close(from_subprocess[0]);     close(from_subprocess[1]);
  1125.  
  1126.     // Exec new process
  1127.  
  1128. //    execlp("prolog", "prolog", (char *)0); execvp(command, argv);
  1129.  
  1130.   // If we get here it failed; give up
  1131.  
  1132.     perror("exec");
  1133.     _exit(1);        // Use _exit() not exit() after failed exec
  1134.  
  1135.     default:            // parent
  1136.  
  1137.     break;
  1138.   }
  1139.  
  1140.   // Close unneeded descriptors
  1141.  
  1142.   close(to_subprocess[0]); close(from_subprocess[1]);
  1143.  
  1144.   (void)notify_set_wait3_func((Notify_client)this, (Notify_func)wx_child_died, pid);
  1145.  
  1146.   wxConnection *connection = this->OnSpawn(pid);
  1147.   connection->input_fd = from_subprocess[0];
  1148.   connection->output_fd = to_subprocess[1];
  1149.  
  1150.   if (connection)
  1151.   {
  1152.     connection->Notify(TRUE);
  1153.     return TRUE;
  1154.   }
  1155.   else
  1156.   { close(to_subprocess[1]); 
  1157.     close(from_subprocess[0]);
  1158.     return FALSE;
  1159.   }
  1160. #endif
  1161. #ifdef wx_msw
  1162.   return FALSE;
  1163. #endif
  1164.   }
  1165.  
  1166. void wxChild::OnDeath(void)
  1167. {
  1168. }
  1169.  
  1170. // Default behaviour
  1171. wxConnection *wxChild::OnSpawn(int pid)
  1172. {
  1173.   return new wxConnection;
  1174. }
  1175.  
  1176. #ifdef wx_msw
  1177. HDDEDATA EXPENTRY _export wxDdeCallback(
  1178. WORD wType,
  1179. WORD wFmt,
  1180. HCONV hConv,
  1181. HSZ hsz1,
  1182. HSZ hsz2,
  1183. HDDEDATA hData,
  1184. DWORD lData1,
  1185. DWORD lData2)
  1186. {
  1187.   switch (wType)
  1188.   {
  1189.     case XTYP_CONNECT:
  1190.     {
  1191.       char topic_buf[100];
  1192.       char server_buf[100];
  1193.       DdeQueryString(wxIdInst, hsz1, (LPSTR)topic_buf, sizeof(topic_buf),
  1194.                      CP_WINANSI);
  1195.       DdeQueryString(wxIdInst, hsz2, (LPSTR)server_buf, sizeof(topic_buf),
  1196.                      CP_WINANSI);
  1197.       wxServer *server = wxFindServer(server_buf);
  1198.       if (server)
  1199.       {
  1200.         wxConnection *connection =
  1201.           server->OnAcceptConnection(topic_buf);
  1202.         if (connection)
  1203.         {
  1204.           connection->server = server;
  1205.           server->connections.Append(connection);
  1206.           connection->hConv = 0;
  1207.           connection->topic_name = copystring(topic_buf);
  1208.           wxCurrentlyConnecting = connection;
  1209.           return TRUE;
  1210.         }
  1211.       }
  1212.       else return 0;
  1213.       break;
  1214.     }
  1215.  
  1216.     case XTYP_CONNECT_CONFIRM:
  1217.     {
  1218.       if (wxCurrentlyConnecting)
  1219.       {
  1220.         wxCurrentlyConnecting->hConv = hConv;
  1221.         wxCurrentlyConnecting = NULL;
  1222.         return TRUE;
  1223.       }
  1224.       else return 0;
  1225.       break;
  1226.     }
  1227.  
  1228.     case XTYP_DISCONNECT:
  1229.     {
  1230.       wxConnection *connection = wxFindConnection(hConv);
  1231.       if (connection && connection->OnDisconnect())
  1232.       {
  1233.         wxDeleteConnection(hConv);  // Delete mapping: hConv => connection
  1234.         return TRUE;
  1235.       }
  1236.       else return 0;
  1237.       break;
  1238.     }
  1239.  
  1240.     case XTYP_EXECUTE:
  1241.     {
  1242.       wxConnection *connection = wxFindConnection(hConv);
  1243.  
  1244.       if (connection)
  1245.       {
  1246.         DWORD len = DdeGetData(hData, (LPBYTE)(connection->buf_ptr), connection->buf_size, 0);
  1247.         DdeFreeDataHandle(hData);
  1248.         if (connection->OnExecute(connection->topic_name, connection->buf_ptr, (int)len, wFmt))
  1249.           return DDE_FACK;
  1250.         else
  1251.           return DDE_FNOTPROCESSED;
  1252.       } else return DDE_FNOTPROCESSED;
  1253.       break;
  1254.     }
  1255.  
  1256.     case XTYP_REQUEST:
  1257.     {
  1258.       wxConnection *connection = wxFindConnection(hConv);
  1259.  
  1260.       if (connection)
  1261.       {
  1262.         char item_name[200];
  1263.         DdeQueryString(wxIdInst, hsz2, (LPSTR)item_name, sizeof(item_name),
  1264.                      CP_WINANSI);
  1265.  
  1266.         int user_size = -1;
  1267.         char *data = connection->OnRequest(connection->topic_name, item_name, &user_size, wFmt);
  1268.         if (data)
  1269.         {
  1270.           if (user_size < 0) user_size = strlen(data);
  1271.  
  1272.           HDDEDATA handle = DdeCreateDataHandle(wxIdInst,
  1273.                  data, user_size + 1, 0, hsz2, wFmt, 0);
  1274.           return handle;
  1275.         } else return 0;
  1276.       } else return 0;
  1277.       break;
  1278.     }
  1279.  
  1280.     case XTYP_POKE:
  1281.     {
  1282.       wxConnection *connection = wxFindConnection(hConv);
  1283.  
  1284.       if (connection)
  1285.       {
  1286.         char item_name[200];
  1287.         DdeQueryString(wxIdInst, hsz2, (LPSTR)item_name, sizeof(item_name),
  1288.                      CP_WINANSI);
  1289.         DWORD len = DdeGetData(hData, (LPBYTE)(connection->buf_ptr), connection->buf_size, 0);
  1290.         DdeFreeDataHandle(hData);
  1291.         connection->OnPoke(connection->topic_name, item_name, connection->buf_ptr, (int)len, wFmt);
  1292.         return DDE_FACK;
  1293.       } else return DDE_FNOTPROCESSED;
  1294.       break;
  1295.     }
  1296.  
  1297.     case XTYP_ADVSTART:
  1298.     {
  1299.       wxConnection *connection = wxFindConnection(hConv);
  1300.  
  1301.       if (connection)
  1302.       {
  1303.         char item_name[200];
  1304.         DdeQueryString(wxIdInst, hsz2, (LPSTR)item_name, sizeof(item_name),
  1305.                      CP_WINANSI);
  1306.  
  1307.         return connection->OnStartAdvise(connection->topic_name, item_name);
  1308.       } else return 0;
  1309.       break;
  1310.     }
  1311.  
  1312.     case XTYP_ADVSTOP:
  1313.     {
  1314.       wxConnection *connection = wxFindConnection(hConv);
  1315.  
  1316.       if (connection)
  1317.       {
  1318.         char item_name[200];
  1319.         DdeQueryString(wxIdInst, hsz2, (LPSTR)item_name, sizeof(item_name),
  1320.                      CP_WINANSI);
  1321.         return connection->OnStopAdvise(connection->topic_name, item_name);
  1322.       } else return 0;
  1323.       break;
  1324.     }
  1325.  
  1326.     case XTYP_ADVREQ:
  1327.     {
  1328.       wxConnection *connection = wxFindConnection(hConv);
  1329.  
  1330.       if (connection && connection->sending_data)
  1331.       {
  1332.         HDDEDATA data = DdeCreateDataHandle(wxIdInst, connection->sending_data,
  1333.                           connection->data_size, 0, hsz2, connection->data_type, 0);
  1334.         connection->sending_data = NULL;
  1335.         return data;
  1336.       } else return NULL;
  1337.       break;
  1338.     }
  1339.  
  1340.     case XTYP_ADVDATA:
  1341.     {
  1342.       wxConnection *connection = wxFindConnection(hConv);
  1343.  
  1344.       if (connection)
  1345.       {
  1346.         char item_name[200];
  1347.         DdeQueryString(wxIdInst, hsz2, (LPSTR)item_name, sizeof(item_name),
  1348.                      CP_WINANSI);
  1349.  
  1350.         DWORD len = DdeGetData(hData, (LPBYTE)(connection->buf_ptr), connection->buf_size, 0);
  1351.         DdeFreeDataHandle(hData);
  1352.         if (connection->OnAdvise(connection->topic_name, item_name, connection->buf_ptr, (int)len, wFmt))
  1353.           return DDE_FACK;
  1354.         else
  1355.           return DDE_FNOTPROCESSED;
  1356.       } else return DDE_FNOTPROCESSED;
  1357.       break;
  1358.     }
  1359.   }
  1360.   return 0;
  1361. }
  1362.  
  1363. #endif
  1364.  
  1365. // Add NULL-terminated string to buffer, returning next start point
  1366. int wxAddString(int start, char *info, char *buffer, int size)
  1367. {
  1368.   if (size < 0)
  1369.     size = strlen(info);
  1370.  
  1371.   int i;
  1372.   for (i = start; i < (start + size); i++)
  1373.     buffer[i] = info[i-start];
  1374.   buffer[i] = 0;
  1375.   return i+1;
  1376. }
  1377.  
  1378. // Get next position of NULL-terminated string from buffer
  1379. char *wxGetNextString(char *buffer)
  1380. {
  1381.   int i = 0;
  1382.   int ch = -1;
  1383.   Bool flag = FALSE;
  1384.   while (!flag)
  1385.   {
  1386.     ch = (int)buffer[i];
  1387.     if (ch == 0)
  1388.     {
  1389.       flag = TRUE;
  1390.     }
  1391.     else
  1392.     {
  1393.       i ++;
  1394.     }
  1395.   }
  1396.   return buffer + i + 1;
  1397. }
  1398.  
  1399. // Atom table stuff
  1400. void wxAddAtom(char *string)
  1401. {
  1402. #ifdef wx_msw
  1403.   HSZ atom = DdeCreateStringHandle(wxIdInst, string, CP_WINANSI);
  1404.   wxAtomTable.Append(string, (wxObject *)atom);
  1405. #endif
  1406. }
  1407.  
  1408. #ifdef wx_msw
  1409. HSZ wxGetAtom(char *string)
  1410. {
  1411.   wxNode *node = wxAtomTable.Find(string);
  1412.   if (node)
  1413.     return (HSZ)node->Data();
  1414.   else
  1415.   {
  1416.     wxAddAtom(string);
  1417.     return (HSZ)(wxAtomTable.Find(string)->Data());
  1418.   }
  1419. }
  1420. #endif
  1421.  
  1422.