home *** CD-ROM | disk | FTP | other *** search
/ Borland Programmer's Resource / Borland_Programmers_Resource_CD_1995.iso / ntcode / blat01 / gensock / pwksock.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-19  |  12.6 KB  |  631 lines

  1. // -*- C++ -*-
  2. // generic socket DLL, pathworks version
  3. // disclaimer:  a C programmer wrote this.
  4.  
  5. #include <windows.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8.  
  9. extern "C" {
  10. /* you must define WSOCKETS_DLL before including socket.h */
  11. #define  WSOCKETS_DLL
  12. #include <sys\socket.h>
  13. #include <netinet\in.h>
  14. #include <netdb.h>
  15. #include <sock_err.h>
  16. #include "gensock.h"
  17. }
  18.  
  19. #define SOCKET_BUFFER_SIZE    8192
  20.  
  21. //
  22. typedef int SOCKET;
  23.  
  24. //
  25. //
  26. //
  27.  
  28. #ifdef _DEBUG
  29. void complain (char * message)
  30. {
  31.   OutputDebugString (message);
  32. }
  33. #else
  34. void complain (char * message)
  35. {
  36.   MessageBox (NULL, message, "GENSOCK.DLL Error", MB_OK|MB_ICONHAND);
  37. }
  38. #endif
  39.  
  40. //
  41. // ---------------------------------------------------------------------------
  42. // container for a buffered SOCK_STREAM.
  43.  
  44. class connection 
  45. {
  46.  private:
  47.   SOCKET    the_socket;
  48.   char *    in_buffer;
  49.   char *    out_buffer;
  50.   unsigned int    in_index;
  51.   unsigned int    out_index;
  52.   unsigned int    in_buffer_total;
  53.   unsigned int    out_buffer_total;
  54.   HTASK        owner_task;
  55.   
  56.  public:
  57.  
  58.   connection (void);
  59.   ~connection (void);
  60.  
  61.   int         get_connected (char * hostname, char * service);
  62.   SOCKET     get_socket(void) { return (the_socket); }
  63.   HTASK        get_owner_task(void) { return (owner_task); }
  64.   int        get_buffer(int wait);
  65.   int        close(void);
  66.   int        getchar(int wait, char * ch);
  67.   int        put_data(char * data, unsigned long length);
  68.   int        put_data_buffered (char * data, unsigned long length);
  69.   int        put_data_flush (void);
  70. };
  71.  
  72. connection::connection (void)
  73. {
  74.   the_socket = 0;
  75.   in_index = 0;
  76.   out_index = 0;
  77.   in_buffer_total = 0;
  78.   out_buffer_total = 0;
  79.   in_buffer = 0;
  80.   
  81.   in_buffer = new char[SOCKET_BUFFER_SIZE];
  82.   out_buffer = new char[SOCKET_BUFFER_SIZE];
  83. }
  84.  
  85. connection::~connection (void)
  86. {
  87.   delete [] in_buffer;
  88. }
  89.  
  90. //
  91. // ---------------------------------------------------------------------------
  92. //
  93.  
  94. int
  95. connection::get_connected (char FAR * hostname, char FAR * service)
  96. {
  97.   struct hostent FAR *    hostentry;
  98.   struct servent FAR *    serventry;
  99.   unsigned long     ip_address;
  100.   struct sockaddr_in    sa_in;
  101.   int            our_port;
  102.   int            not = 0;
  103.   long             ioctl_blocking = 1;
  104.   int            retval;
  105.   
  106.   // if the ctor couldn't get a buffer
  107.   if (!in_buffer || !out_buffer)
  108.     return (ERR_CANT_MALLOC);
  109.   
  110.   // --------------------------------------------------
  111.   // resolve the service name
  112.   //
  113.   serventry = getservbyname (service, (LPSTR)"tcp");
  114.   
  115.   if (serventry)
  116.     our_port = serventry->s_port;
  117.   else {
  118.     char * tail;
  119.     our_port = (int) strtol (service, &tail, 10);
  120.     if (tail == service) {
  121.       return (ERR_CANT_RESOLVE_SERVICE);
  122.     }
  123.     else
  124.       our_port = htons (our_port);
  125.   }
  126.  
  127.   // --------------------------------------------------
  128.   // resolve the hostname/ipaddress
  129.   //
  130.  
  131.   if ((ip_address = inet_addr (hostname)) != -1) {
  132.     sa_in.sin_addr.s_addr = ip_address;
  133.   }
  134.   else {
  135.     if ((hostentry = gethostbyname(hostname)) == NULL) {
  136.       return (ERR_CANT_RESOLVE_HOSTNAME);
  137.     }
  138.     sa_in.sin_addr.s_addr = *(long far *)hostentry->h_addr;
  139.   }
  140.   
  141.  
  142.   // --------------------------------------------------
  143.   // get a socket
  144.   //
  145.  
  146.   if ((the_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
  147.     return (ERR_CANT_GET_SOCKET);
  148.   }
  149.   
  150.   sa_in.sin_family = AF_INET;
  151.   sa_in.sin_port = our_port;
  152.   
  153.   // set socket options.  DONTLINGER will give us a more graceful disconnect
  154.   
  155.   setsockopt(the_socket,
  156.          SOL_SOCKET,
  157.          SO_DONTLINGER,
  158.          (char *) ¬, sizeof(not));
  159.   
  160.   if ((retval = connect (the_socket,
  161.              (struct sockaddr *)&sa_in,
  162.              sizeof(struct sockaddr_in)))) {
  163.     return (ERR_CANT_CONNECT);
  164.   }
  165.   
  166.   // Make this a non-blocking socket
  167.   ioctl (the_socket, FIONBIO, (char far *)(&ioctl_blocking)); 
  168.  
  169.   owner_task = GetCurrentTask();
  170.   return (0);
  171. }
  172.  
  173.  
  174. //
  175. //---------------------------------------------------------------------------
  176. //
  177.  
  178. int
  179. connection::get_buffer(int wait)
  180. {
  181.   int retval;
  182.   int bytes_read = 0;
  183.   unsigned long ready_to_read = 0;
  184.  
  185.   while (bytes_read < 1) {
  186.     MSG msg;
  187.  
  188.     // is there anything waiting to be read? 
  189.  
  190.     retval = ioctl(the_socket, FIONREAD, (char far *)(&ready_to_read));
  191.     if (retval == -1) {
  192.       char socket_error[256];
  193.       char message[512];
  194.       sock_strerror (errno, socket_error); 
  195.       wsprintf (message, "connection::get_buffer() error from ioctl() '%s'", socket_error);
  196.       complain(message);
  197.     }
  198.  
  199.     if (!ready_to_read && wait)
  200.       return (WAIT_A_BIT);
  201.     
  202.     bytes_read = recv (the_socket,
  203.                in_buffer,
  204.                SOCKET_BUFFER_SIZE,
  205.                0);
  206.  
  207.     // do something in the meanwhile...
  208.     if (!bytes_read) {
  209.       for (;;) {
  210.     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
  211.       TranslateMessage(&msg);
  212.       DispatchMessage(&msg);
  213.     }
  214.       }
  215.     }
  216.   }
  217.  
  218.   // reset buffer indices.
  219.   in_buffer_total = bytes_read;
  220.   in_index = 0;
  221.   return (0);
  222. }
  223.  
  224. //
  225. //---------------------------------------------------------------------------
  226. // get a character from this connection.
  227. // 
  228.  
  229. int
  230. connection::getchar(int wait, char FAR * ch)
  231. {
  232.   int retval;
  233.  
  234.   if (in_index >= in_buffer_total) {
  235.     if ((retval = get_buffer(wait)))
  236.       return (retval);
  237.   }
  238.   *ch = in_buffer[in_index++];
  239.   return (0);
  240. }
  241.  
  242.  
  243. //
  244. //---------------------------------------------------------------------------
  245. // FIXME: should try to handle the fact that send can only take
  246. // an int, not an unsigned long.
  247.  
  248. int
  249. connection::put_data (char * data, unsigned long length)
  250. {
  251.   char error_string[256];
  252.   int num_sent;
  253.  
  254.   while (length > 0) {
  255.     num_sent = send (the_socket, data, length > 512 ? 512 : (int)length, 0);
  256.     
  257.     if (num_sent < 0 ) {
  258.       switch (errno) {
  259.       case ENOTCONN:
  260.     return (ERR_NOT_CONNECTED);
  261.     break;
  262.       case ENOBUFS:
  263.     complain ("ENOBUFS, waiting...");
  264. //    stupid_pathworks_delay (1,0); 
  265.     break;
  266.       default:
  267.     sock_strerror (errno, error_string);
  268.     complain (error_string);
  269.     break;
  270.       }
  271.     }
  272.     else {
  273.       length -= num_sent;
  274.       data += num_sent;
  275.     }
  276.   }
  277.   return (0);
  278. }
  279.       
  280. //
  281. //
  282. // buffered output
  283. //
  284.  
  285. int
  286. connection::put_data_buffered (char * data, unsigned long length)
  287. {
  288.   unsigned int sorta_sent = 0;
  289.   int retval;
  290.  
  291.   while (length) {
  292.     if ((out_index + length) < SOCKET_BUFFER_SIZE) {
  293.       // we won't overflow, simply copy into the buffer
  294.       memcpy (out_buffer + out_index, data, (size_t) length);
  295.       out_index += (unsigned int) length;
  296.       length = 0;
  297.     }
  298.     else {
  299.       unsigned int orphaned_chunk = SOCKET_BUFFER_SIZE - out_index;
  300.       // we will overflow, handle it
  301.       memcpy (out_buffer + out_index, data, orphaned_chunk);
  302.       // send this buffer...
  303.       if ((retval = put_data (out_buffer, SOCKET_BUFFER_SIZE))) {
  304.     return (retval);
  305.       }
  306.       length -= orphaned_chunk;
  307.       out_index = 0;
  308.       data += orphaned_chunk;
  309.     }
  310.   }
  311.  
  312.   return (0);
  313. }
  314.  
  315. int
  316. connection::put_data_flush (void)
  317. {
  318.   int retval;
  319.  
  320.   if ((retval = put_data (out_buffer, out_index)))
  321.     return (retval);
  322.   else
  323.     out_index = 0;
  324.  
  325.   return(0);
  326. }
  327.  
  328. //
  329. //---------------------------------------------------------------------------
  330. //
  331.  
  332. int
  333. connection::close (void)
  334. {
  335.   if (close_socket(the_socket) == -1)
  336.     return (ERR_CLOSING);
  337.   else
  338.     return (0);
  339. }
  340.  
  341. //
  342. //---------------------------------------------------------------------------
  343. // we keep lists of connections in this class
  344.  
  345. class connection_list
  346. {
  347.  private:
  348.   connection *         data;
  349.   connection_list *     next;
  350.  
  351.  public:
  352.   connection_list     (void);
  353.   ~connection_list    (void);
  354.   void push         (connection & conn);
  355.  
  356.   // should really use pointer-to-memberfun for these
  357.   connection * find    (SOCKET sock);
  358.   int how_many_are_mine    (void);
  359.  
  360.   void remove        (socktag st);
  361. };
  362.  
  363. connection_list::connection_list (void)
  364. {
  365.   next = 0;
  366. }
  367.  
  368. connection_list::~connection_list(void)
  369. {
  370.   delete data;
  371. }
  372.  
  373. // add a new connection to the list
  374.  
  375. void
  376. connection_list::push (connection & conn)
  377. {
  378.   connection_list * new_conn;
  379.  
  380.   new_conn = new connection_list();
  381.  
  382.   new_conn->data = data;
  383.   new_conn->next = next;
  384.  
  385.   data = &conn;
  386.   next = new_conn;
  387.  
  388. }
  389.  
  390. int
  391. connection_list::how_many_are_mine(void)
  392. {
  393.   HTASK    current_task = GetCurrentTask();
  394.   connection_list * iter = this;
  395.   int num = 0;
  396.  
  397.   while (iter->data) {
  398.     if (iter->data->get_owner_task() == current_task)
  399.       num++;
  400.     iter = iter->next;
  401.   }
  402.   return (num);
  403. }
  404.  
  405. // find a particular socket's connection object.
  406.  
  407. connection *
  408. connection_list::find (SOCKET sock)
  409. {
  410.   connection_list * iter = this;
  411.  
  412.   while (iter->data) {
  413.     if (iter->data->get_socket() == sock)
  414.       return (iter->data);
  415.     iter = iter->next;
  416.   }
  417.   return (0);
  418. }
  419.       
  420. void
  421. connection_list::remove (socktag st)
  422. {
  423.   // at the end
  424.   if (!data)
  425.     return;
  426.   
  427.   // we can assume next is valid because
  428.   // the last node is always {0,0}
  429.   if (data == st) {
  430.     delete data;
  431.     data = next->data;
  432.     next = next->next; // 8^)
  433.     return;
  434.   }
  435.  
  436.   // recurse
  437.   next->remove(st);
  438. }
  439.   
  440. //
  441. // ---------------------------------------------------------------------------
  442. // global variables (shared by all DLL users)
  443.  
  444. connection_list global_socket_list;
  445. HINSTANCE dll_module_handle;
  446.  
  447. // the DLL entry routine
  448. int FAR PASCAL LibMain (HINSTANCE hinstance,
  449.             WPARAM data_seg,
  450.             LPARAM heap_size,
  451.             LPSTR command_line)
  452.   dll_module_handle = hinstance;
  453.   return (1);
  454. }
  455.             
  456. // ---------------------------------------------------------------------------
  457. // C/DLL interface
  458. //
  459.  
  460. int FAR PASCAL _export
  461. gensock_connect (char FAR * hostname,
  462.          char FAR * service,
  463.          socktag FAR * pst)
  464. {
  465.   int retval;
  466.   connection * conn = new connection;
  467.   
  468.   if (!conn)
  469.     return (ERR_INITIALIZING);
  470.  
  471.   if ((retval = conn->get_connected (hostname, service))) {
  472.     delete conn;
  473.     *pst = 0;
  474.     return (retval);
  475.   }
  476.  
  477.   global_socket_list.push(*conn);
  478.  
  479.   // *pst = conn->get_socket();
  480.   *pst = (socktag) conn;
  481.   
  482.   return (0);
  483. }
  484.  
  485. //
  486. //
  487. //
  488.  
  489. int FAR PASCAL _export
  490. gensock_getchar (socktag st, int wait, char FAR * ch)
  491. {
  492.   connection * conn;
  493.   int retval = 0;
  494.   
  495.   conn = (connection *) st;
  496.   // conn = global_socket_list.find((SOCKET)st);
  497.   if (!conn)
  498.     return (ERR_NOT_A_SOCKET);
  499.  
  500.   if ((retval = conn->getchar(wait, ch)))
  501.     return (retval);
  502.   else
  503.     return (0);
  504. }
  505.  
  506.  
  507. //---------------------------------------------------------------------------
  508. //
  509. //
  510.  
  511. int FAR PASCAL _export
  512. gensock_put_data (socktag st, char FAR * data, unsigned long length)
  513. {
  514.   connection * conn;
  515.   int retval = 0;
  516.  
  517.   conn = (connection *) st;
  518.   // conn = global_socket_list.find((SOCKET)st);
  519.   
  520.   if (!conn)
  521.     return (ERR_NOT_A_SOCKET);
  522.  
  523.   if ((retval = conn->put_data(data, length)))
  524.     return (retval);
  525.  
  526.   return (0);
  527. }
  528.  
  529.  
  530. //---------------------------------------------------------------------------
  531. //
  532. //
  533.  
  534. int FAR PASCAL _export
  535. gensock_put_data_buffered (socktag st, char FAR * data, unsigned long length)
  536. {
  537.   connection * conn;
  538.   int retval = 0;
  539.  
  540.   conn = (connection *) st;
  541.  
  542.   if (!conn)
  543.     return (ERR_NOT_A_SOCKET);
  544.  
  545.   if ((retval = conn->put_data_buffered (data, length)))
  546.     return (retval);
  547.  
  548.   return (0);
  549. }
  550.  
  551. //---------------------------------------------------------------------------
  552. //
  553. //
  554.  
  555. int FAR PASCAL _export
  556. gensock_put_data_flush (socktag st)
  557. {
  558.   connection * conn;
  559.   int retval = 0;
  560.  
  561.   conn = (connection *) st;
  562.  
  563.   if (!conn)
  564.     return (ERR_NOT_A_SOCKET);
  565.  
  566.   if ((retval = conn->put_data_flush() ))
  567.     return (retval);
  568.  
  569.   return (0);
  570. }
  571.  
  572. //---------------------------------------------------------------------------
  573. //
  574. //
  575.  
  576. int FAR PASCAL _export
  577. gensock_close (socktag st)
  578. {
  579.   connection * conn;
  580.   int retval;
  581.   
  582.   conn = (connection *) st;
  583.   // conn = global_socket_list.find((SOCKET)st);
  584.   if (!conn)
  585.     return (ERR_NOT_A_SOCKET);
  586.   
  587.   if ((retval = conn->close()))
  588.     return (retval);
  589.  
  590.   global_socket_list.remove(st);
  591.   
  592.   return (0);
  593. }
  594.  
  595. //---------------------------------------------------------------------------
  596. //
  597. //
  598.  
  599. int FAR PASCAL _export
  600. gensock_gethostname (char FAR * name, int namelen)
  601. {
  602.   return (gethostname (name, namelen));
  603. }
  604.  
  605. #if 0 
  606. void
  607. stupid_pathworks_delay(int secs, int usecs)
  608. {
  609.   struct timeval to;
  610.   int retval;
  611.  
  612.   to.tv_sec = secs;
  613.   to.tv_usec = usecs;
  614.  
  615.   /* Now we use select to delay */
  616.   retval = select (1, NULL, NULL, NULL, &to);
  617.   switch (retval) {
  618.   case -1:
  619.     complain ("error in select");
  620.     break;
  621.   case 1:
  622.     complain("Delaying select returned true on NULL socket set");
  623.     break;
  624.   case 0:
  625.     break;
  626.   }
  627. }
  628.  
  629. #endif
  630.