home *** CD-ROM | disk | FTP | other *** search
/ CD Shareware Magazine 1999 April / CD_Shareware_Magazine_31.iso / Free / Internet / blat180.exe / GENSOCK / gensock.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-10-29  |  16.7 KB  |  864 lines

  1. // -*- C++ -*-
  2. // generic socket DLL, winsock version
  3. // disclaimer:  a C programmer wrote this.
  4.  
  5. // $Id: gensock.cpp 1.15 1994/11/23 22:38:10 rushing Exp $
  6.  
  7. #include <windows.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <ctype.h>
  11.  
  12. extern "C" {
  13. #include <winsock.h>
  14. #include "gensock.h"
  15. }
  16.  
  17. #define SOCKET_BUFFER_SIZE    512
  18.  
  19. /* This is for NT */
  20. #ifdef WIN32
  21.  
  22. #ifdef GENSOCK_STATIC_LINK
  23. extern HANDLE    dll_module_handle;
  24. #else
  25. HANDLE    dll_module_handle;
  26. #endif
  27. #define    GET_CURRENT_TASK    dll_module_handle
  28. #define    TASK_HANDLE_TYPE    HANDLE
  29. #define GENSOCK_EXPORT
  30.  
  31. /* This is for WIN16 */
  32. #else
  33. HINSTANCE dll_module_handle;
  34. #define    GET_CURRENT_TASK    GetCurrentTask()
  35. #define    TASK_HANDLE_TYPE    HTASK
  36. #define GENSOCK_EXPORT        _export
  37. #endif
  38.  
  39. int  init_winsock (void);
  40. void deinit_winsock (void);
  41.  
  42. //
  43. //
  44. //
  45.  
  46. #ifdef _DEBUG
  47. void complain (char * message)
  48. {
  49.   OutputDebugString (message);
  50. }
  51. #else
  52. void complain (char * message)
  53. {
  54.   MessageBox (NULL, message, "GENSOCK.DLL Error", MB_OK|MB_ICONHAND);
  55. }
  56. #endif
  57.  
  58. //
  59. // ---------------------------------------------------------------------------
  60. // container for a buffered SOCK_STREAM.
  61.  
  62. class connection
  63. {
  64.  private:
  65.   SOCKET    the_socket;
  66.   char *    in_buffer;
  67.   char *    out_buffer;
  68.   unsigned int    in_index;
  69.   unsigned int    out_index;
  70.   unsigned int    in_buffer_total;
  71.   unsigned int    out_buffer_total;
  72.   unsigned int    last_winsock_error;
  73.   TASK_HANDLE_TYPE        owner_task;
  74.   fd_set    fds;
  75.   struct timeval    timeout;
  76.  
  77.  public:
  78.  
  79.   connection (void);
  80.   ~connection (void);
  81.  
  82.   int         get_connected (char * hostname, char * service);
  83.   SOCKET     get_socket(void) { return (the_socket); }
  84.   TASK_HANDLE_TYPE        get_owner_task(void) { return (owner_task); }
  85.   int        get_buffer(int wait);
  86.   int        close (void);
  87.   int        getchar (int wait, char * ch);
  88.   int        put_data (char * data, unsigned long length);
  89.   int        put_data_buffered (char * data, unsigned long length);
  90.   int        put_data_flush (void);
  91. };
  92.  
  93. connection::connection (void)
  94. {
  95.   the_socket = 0;
  96.   in_index = 0;
  97.   out_index = 0;
  98.   in_buffer_total = 0;
  99.   out_buffer_total = 0;
  100.   in_buffer = 0;
  101.  
  102.   in_buffer = new char[SOCKET_BUFFER_SIZE];
  103.   out_buffer = new char[SOCKET_BUFFER_SIZE];
  104.  
  105.   last_winsock_error = 0;
  106. }
  107.  
  108. connection::~connection (void)
  109. {
  110.   delete [] in_buffer;
  111. }
  112.  
  113. int
  114. gensock_is_a_number (char * string)
  115. {
  116.   while (*string) {
  117.     if (!isdigit (*string)) {
  118.       return (0);
  119.     }
  120.     string++;
  121.   }
  122.   return (1);
  123. }
  124.  
  125. //
  126. // ---------------------------------------------------------------------------
  127. //
  128.  
  129. int
  130. connection::get_connected (char FAR * hostname, char FAR * service)
  131. {
  132.   struct hostent FAR *    hostentry;
  133.   struct servent FAR *    serventry;
  134.   unsigned long     ip_address;
  135.   struct sockaddr_in    sa_in;
  136.   int            our_port;
  137.   int            not = 0;
  138.   int            retval, err_code;
  139.   unsigned long        ioctl_blocking = 1;
  140.   char            message[512];
  141.  
  142.   // if the ctor couldn't get a buffer
  143.   if (!in_buffer || !out_buffer)
  144.     return (ERR_CANT_MALLOC);
  145.  
  146.   // --------------------------------------------------
  147.   // resolve the service name
  148.   //
  149.  
  150.   // If they've specified a number, just use it.
  151.   if (gensock_is_a_number (service)) {
  152.     char * tail;
  153.     our_port = (int) strtol (service, &tail, 10);
  154.     if (tail == service) {
  155.       return (ERR_CANT_RESOLVE_SERVICE);
  156.     } else {
  157.       our_port = htons (our_port);
  158.     }
  159.   } else {
  160.     // we have a name, we must resolve it.
  161.     serventry = getservbyname (service, (LPSTR)"tcp");
  162.  
  163.     if (serventry)
  164.       our_port = serventry->s_port;
  165.     else {
  166.       retval = WSAGetLastError();
  167.       // Chicago beta is throwing a WSANO_RECOVERY here...
  168.       if ((retval == WSANO_DATA) || (retval == WSANO_RECOVERY)) {
  169.     return (ERR_CANT_RESOLVE_SERVICE);
  170.       } else {
  171.     return (retval - 5000);
  172.       }
  173.     }
  174.   }
  175.  
  176.   // --------------------------------------------------
  177.   // resolve the hostname/ipaddress
  178.   //
  179.  
  180.   if ((ip_address = inet_addr (hostname)) != INADDR_NONE) {
  181.     sa_in.sin_addr.s_addr = ip_address;
  182.   }
  183.   else {
  184.     if ((hostentry = gethostbyname(hostname)) == NULL) {
  185.       return (ERR_CANT_RESOLVE_HOSTNAME);
  186.     }
  187.     sa_in.sin_addr.s_addr = *(long far *)hostentry->h_addr;
  188.   }
  189.  
  190.  
  191.   // --------------------------------------------------
  192.   // get a socket
  193.   //
  194.  
  195.   if ((the_socket = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
  196.     return (ERR_CANT_GET_SOCKET);
  197.   }
  198.  
  199.   sa_in.sin_family = AF_INET;
  200.   sa_in.sin_port = our_port;
  201.  
  202.   // set socket options.  DONTLINGER will give us a more graceful disconnect
  203.  
  204.   setsockopt(the_socket,
  205.          SOL_SOCKET,
  206.          SO_DONTLINGER,
  207.          (char *) ¬, sizeof(not));
  208.  
  209.   // get a connection
  210.  
  211.   if ((retval = connect (the_socket,
  212.              (struct sockaddr *)&sa_in,
  213.              sizeof(struct sockaddr_in))==SOCKET_ERROR)) {
  214.     switch ((err_code = WSAGetLastError())) {
  215.       /* twiddle our thumbs until the connect succeeds */
  216.     case WSAEWOULDBLOCK:
  217.       break;
  218.     case WSAECONNREFUSED:
  219.       return (ERR_CONNECTION_REFUSED);
  220.       break;
  221.     default:
  222.       wsprintf(message, "unexpected error %d from winsock\n", err_code);
  223.       complain(message);
  224.       return (ERR_CANT_CONNECT);
  225.       break;
  226.     }
  227.   }
  228.  
  229.   owner_task = GET_CURRENT_TASK;
  230.  
  231.   // Make this a non-blocking socket
  232.   ioctlsocket (the_socket, FIONBIO, &ioctl_blocking);
  233.  
  234.   // make the FD_SET and timeout structures for later operations...
  235.  
  236.   FD_ZERO (&fds);
  237.   FD_SET  (the_socket, &fds);
  238.  
  239.   // normal timeout, can be changed by the wait option.
  240.   timeout.tv_sec = 30;
  241.   timeout.tv_usec = 0;
  242.  
  243.   return (0);
  244. }
  245.  
  246.  
  247. //
  248. //---------------------------------------------------------------------------
  249. //
  250. // The 'wait' parameter, if set, says to return WAIT_A_BIT
  251. // if there's no data waiting to be read.
  252.  
  253. int
  254. connection::get_buffer(int wait)
  255. {
  256.   int retval;
  257.   int bytes_read = 0;
  258.   unsigned long ready_to_read = 0;
  259.  
  260.   // Use select to see if data is waiting...
  261.  
  262.   FD_ZERO (&fds);
  263.   FD_SET  (the_socket, &fds);
  264.  
  265.   // if wait is set, we are polling, return immediately
  266.   if (wait) {
  267.     timeout.tv_sec = 0;
  268.   }
  269.   else {
  270.     timeout.tv_sec = 30;
  271.   }
  272.  
  273.   if ((retval = select (0, &fds, NULL, NULL, &timeout))
  274.       == SOCKET_ERROR) {
  275.     char what_error[256];
  276.     int error_code = WSAGetLastError();
  277.  
  278.     if (error_code == WSAEINPROGRESS && wait) {
  279.       return (WAIT_A_BIT);
  280.     }
  281.  
  282.     wsprintf (what_error,
  283.           "connection::get_buffer() unexpected error from select: %d",
  284.           error_code);
  285.     complain (what_error);
  286.   }
  287.  
  288.   // if we don't want to wait
  289.   if (!retval && wait) {
  290.     return (WAIT_A_BIT);
  291.   }
  292.  
  293.   // we have data waiting...
  294.   bytes_read = recv (the_socket,
  295.              in_buffer,
  296.              SOCKET_BUFFER_SIZE,
  297.              0);
  298.  
  299.   // just in case.
  300.  
  301.   if (bytes_read == 0) {
  302.     // connection terminated (semi-) gracefully by the other side
  303.     return (ERR_NOT_CONNECTED);
  304.   }
  305.  
  306.   if (bytes_read == SOCKET_ERROR) {
  307.     char what_error[256];
  308.     int ws_error = WSAGetLastError();
  309.     switch (ws_error) {
  310.       // all these indicate loss of connection (are there more?)
  311.     case WSAENOTCONN:
  312.     case WSAENETDOWN:
  313.     case WSAENETUNREACH:
  314.     case WSAENETRESET:
  315.     case WSAECONNABORTED:
  316.     case WSAECONNRESET:
  317.       return (ERR_NOT_CONNECTED);
  318.       break;
  319.  
  320.     case WSAEWOULDBLOCK:
  321.       return (WAIT_A_BIT);
  322.       break;
  323.  
  324.     default:
  325.       wsprintf (what_error,
  326.         "connection::get_buffer() unexpected error: %d",
  327.         ws_error);
  328.       complain (what_error);
  329.     }
  330.   }
  331.  
  332.   // reset buffer indices.
  333.   in_buffer_total = bytes_read;
  334.   in_index = 0;
  335.   return (0);
  336.  
  337. }
  338.  
  339. //
  340. //---------------------------------------------------------------------------
  341. // get a character from this connection.
  342. //
  343.  
  344. int
  345. connection::getchar(int wait, char FAR * ch)
  346. {
  347.   int retval;
  348.  
  349.   if (in_index >= in_buffer_total) {
  350.     if ((retval = get_buffer(wait)))
  351.       return (retval);
  352.   }
  353.   *ch = in_buffer[in_index++];
  354.   return (0);
  355. }
  356.  
  357.  
  358. //
  359. //---------------------------------------------------------------------------
  360. // FIXME: should try to handle the fact that send can only take
  361. // an int, not an unsigned long.
  362.  
  363. int
  364. connection::put_data (char * data, unsigned long length)
  365. {
  366.   int num_sent;
  367.   int retval;
  368.  
  369.   FD_ZERO (&fds);
  370.   FD_SET  (the_socket, &fds);
  371.  
  372.   timeout.tv_sec = 30;
  373.  
  374.   while (length > 0) {
  375.     if ((retval = select (0, NULL, &fds, NULL, &timeout)) == SOCKET_ERROR) {
  376.       char what_error[256];
  377.       int error_code = WSAGetLastError();
  378.  
  379.       wsprintf (what_error,
  380.         "connection::put_data() unexpected error from select: %d",
  381.         error_code);
  382.       complain (what_error);
  383.     }
  384.  
  385.     num_sent = send (the_socket,
  386.              data,
  387.              length > 1024 ? 1024 : (int)length,
  388.              0);
  389.  
  390.     if (num_sent == SOCKET_ERROR) {
  391.       char what_error[256];
  392.       int ws_error = WSAGetLastError();
  393.       switch (ws_error) {
  394.     // this is the only error we really expect to see.
  395.       case WSAENOTCONN:
  396.     return (ERR_NOT_CONNECTED);
  397.     break;
  398.  
  399.     // seems that we can still get a block
  400.       case WSAEWOULDBLOCK:
  401.       case WSAEINPROGRESS:
  402.     break;
  403.  
  404.       default:
  405.     wsprintf (what_error,
  406.           "connection::put_data() unexpected error from send(): %d",
  407.           ws_error);
  408.     complain (what_error);
  409.     return (ERR_SENDING_DATA);
  410.       }
  411.     }
  412.     else {
  413.       length -= num_sent;
  414.       data += num_sent;
  415.     }
  416.   }
  417.  
  418.   return (0);
  419. }
  420.  
  421. //
  422. //
  423. // buffered output
  424. //
  425.  
  426. int
  427. connection::put_data_buffered (char * data, unsigned long length)
  428. {
  429.   unsigned int sorta_sent = 0;
  430.   int retval;
  431.  
  432.   while (length) {
  433.     if ((out_index + length) < SOCKET_BUFFER_SIZE) {
  434.       // we won't overflow, simply copy into the buffer
  435.       memcpy (out_buffer + out_index, data, (size_t) length);
  436.       out_index += (unsigned int) length;
  437.       length = 0;
  438.     }
  439.     else {
  440.       unsigned int orphaned_chunk = SOCKET_BUFFER_SIZE - out_index;
  441.       // we will overflow, handle it
  442.       memcpy (out_buffer + out_index, data, orphaned_chunk);
  443.       // send this buffer...
  444.       if ((retval = put_data (out_buffer, SOCKET_BUFFER_SIZE))) {
  445.     return (retval);
  446.       }
  447.       length -= orphaned_chunk;
  448.       out_index = 0;
  449.       data += orphaned_chunk;
  450.     }
  451.   }
  452.  
  453.   return (0);
  454. }
  455.  
  456. int
  457. connection::put_data_flush (void)
  458. {
  459.   int retval;
  460.  
  461.   if ((retval = put_data (out_buffer, out_index)))
  462.     return (retval);
  463.   else
  464.     out_index = 0;
  465.  
  466.   return(0);
  467. }
  468.  
  469. //
  470. //---------------------------------------------------------------------------
  471. //
  472.  
  473. int
  474. connection::close (void)
  475. {
  476.   if (closesocket(the_socket) == SOCKET_ERROR)
  477.     return (ERR_CLOSING);
  478.   else
  479.     return (0);
  480. }
  481.  
  482.  
  483. //
  484. //---------------------------------------------------------------------------
  485. // we keep lists of connections in this class
  486.  
  487. class connection_list
  488. {
  489. private:
  490.   connection *         data;
  491.   connection_list *     next;
  492.  
  493. public:
  494.   connection_list     (void);
  495.   ~connection_list    (void);
  496.   void push         (connection & conn);
  497.  
  498.   // should really use pointer-to-memberfun for these
  499.   connection * find    (SOCKET sock);
  500.   int how_many_are_mine    (void);
  501.  
  502.   void remove        (socktag sock);
  503. };
  504.  
  505. connection_list::connection_list (void)
  506. {
  507.   next = 0;
  508. }
  509.  
  510. connection_list::~connection_list(void)
  511. {
  512.   delete data;
  513. }
  514.  
  515. // add a new connection to the list
  516.  
  517. void
  518. connection_list::push (connection & conn)
  519. {
  520.   connection_list * new_conn;
  521.  
  522.   new_conn = new connection_list();
  523.  
  524.   new_conn->data = data;
  525.   new_conn->next = next;
  526.  
  527.   data = &conn;
  528.   next = new_conn;
  529.  
  530. }
  531.  
  532. int
  533. connection_list::how_many_are_mine(void)
  534. {
  535.   TASK_HANDLE_TYPE    current_task = GET_CURRENT_TASK;
  536.   connection_list * iter = this;
  537.   int num = 0;
  538.  
  539.   while (iter->data) {
  540.     if (iter->data->get_owner_task() == current_task)
  541.       num++;
  542.     iter = iter->next;
  543.   }
  544.   return (num);
  545. }
  546.  
  547. // find a particular socket's connection object.
  548.  
  549. connection *
  550. connection_list::find (SOCKET sock)
  551. {
  552.   connection_list * iter = this;
  553.  
  554.   while (iter->data) {
  555.     if (iter->data->get_socket() == sock)
  556.       return (iter->data);
  557.     iter = iter->next;
  558.   }
  559.   return (0);
  560. }
  561.  
  562. void
  563. connection_list::remove (socktag sock)
  564. {
  565.   // at the end
  566.   if (!data)
  567.     return;
  568.  
  569.   // we can assume next is valid because
  570.   // the last node is always {0,0}
  571.   if (data == sock) {
  572.     delete data;
  573.     data = next->data;
  574.     next = next->next;    // 8^)
  575.     return;
  576.   }
  577.  
  578.   // recurse
  579.   next->remove(sock);
  580. }
  581.  
  582. //
  583. // ---------------------------------------------------------------------------
  584. // global variables (shared by all DLL users)
  585.  
  586. connection_list global_socket_list;
  587. int    network_initialized;
  588.  
  589. //
  590. //---------------------------------------------------------------------------
  591. //
  592.  
  593. #ifndef GENSOCK_STATIC_LINK
  594. #ifndef WIN32
  595.  
  596. // the DLL entry routine
  597. int FAR PASCAL LibMain (HINSTANCE hinstance,
  598.             WPARAM data_seg,
  599.             LPARAM heap_size,
  600.             LPSTR command_line)
  601. {
  602.   network_initialized = 0;
  603.   dll_module_handle = hinstance;
  604.   return (1);
  605. }
  606.  
  607. #else
  608.  
  609. extern "C" {
  610.   INT APIENTRY
  611.     LibMain (HANDLE     hInst,
  612.          ULONG        reason_called,
  613.          LPVOID        reserved)
  614.       {
  615.  
  616.     switch (reason_called) {
  617.     case DLL_PROCESS_ATTACH:
  618.       /* init */
  619.       dll_module_handle = hInst;
  620.       break;
  621.     case DLL_THREAD_ATTACH:
  622.       break;
  623.     case DLL_THREAD_DETACH:
  624.       break;
  625.     case DLL_PROCESS_DETACH:
  626.       break;
  627.  
  628.     default:
  629.       break;
  630.     }
  631.     return (1);
  632.       }
  633.  
  634.   /*
  635.    * This wrapper is the actual entry point for the DLL.  It ensures
  636.    * that the C RTL is correctly [de]initialized.
  637.    */
  638.  
  639. BOOL WINAPI _CRT_INIT (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved);
  640.  
  641. BOOL WINAPI
  642. dll_entry_point (HINSTANCE hinstDLL,
  643.          DWORD fdwReason,
  644.          LPVOID lpReserved)
  645. {
  646.   /* Init the C run-time before calling any of your code */
  647.  
  648.   switch (fdwReason) {
  649.   case DLL_PROCESS_ATTACH:
  650.   case DLL_THREAD_ATTACH:
  651.     if (!_CRT_INIT (hinstDLL, fdwReason, lpReserved))
  652.       return (FALSE);
  653.     else
  654.       LibMain (hinstDLL, fdwReason, lpReserved);
  655.     break;
  656.  
  657.   case DLL_PROCESS_DETACH:
  658.   case DLL_THREAD_DETACH:
  659.     if (!_CRT_INIT(hinstDLL, fdwReason, lpReserved))
  660.       return(FALSE);
  661.     break;
  662.   }
  663.   return (TRUE);
  664. }
  665.  
  666. }
  667. #endif
  668. #endif
  669.  
  670. // ---------------------------------------------------------------------------
  671. // C/DLL interface
  672. //
  673.  
  674. int FAR PASCAL GENSOCK_EXPORT
  675. gensock_connect (char FAR * hostname,
  676.          char FAR * service,
  677.          socktag FAR * pst)
  678. {
  679.   int retval;
  680.   connection * conn = new connection;
  681.  
  682.   if (!conn)
  683.     return (ERR_INITIALIZING);
  684.  
  685.   // if this task hasn't opened any sockets yet, then
  686.   // call WSAStartup()
  687.  
  688.   if (global_socket_list.how_many_are_mine() < 1)
  689.     init_winsock();
  690.  
  691.   global_socket_list.push(*conn);
  692.  
  693.   if ((retval = conn->get_connected (hostname, service))) {
  694.     gensock_close(conn);
  695.     *pst = 0;
  696.     return (retval);
  697.   }
  698.   *pst = (void FAR *) conn;
  699.  
  700.   return (0);
  701. }
  702.  
  703. //
  704. //
  705. //
  706.  
  707. int FAR PASCAL GENSOCK_EXPORT
  708. gensock_getchar (socktag st, int wait, char FAR * ch)
  709. {
  710.   connection * conn;
  711.   int retval = 0;
  712.  
  713.   conn = (connection *) st;
  714.   if (!conn)
  715.     return (ERR_NOT_A_SOCKET);
  716.  
  717.   if ((retval = conn->getchar(wait, ch)))
  718.     return (retval);
  719.   else
  720.     return (0);
  721. }
  722.  
  723.  
  724. //---------------------------------------------------------------------------
  725. //
  726. //
  727.  
  728. int FAR PASCAL GENSOCK_EXPORT
  729. gensock_put_data (socktag st, char FAR * data, unsigned long length)
  730. {
  731.   connection * conn;
  732.   int retval = 0;
  733.  
  734.   conn = (connection *) st;
  735.  
  736.   if (!conn)
  737.     return (ERR_NOT_A_SOCKET);
  738.  
  739.   if ((retval = conn->put_data(data, length)))
  740.     return (retval);
  741.  
  742.   return (0);
  743. }
  744.  
  745. //---------------------------------------------------------------------------
  746. //
  747. //
  748.  
  749. int FAR PASCAL GENSOCK_EXPORT
  750. gensock_put_data_buffered (socktag st, char FAR * data, unsigned long length)
  751. {
  752.   connection * conn;
  753.   int retval = 0;
  754.  
  755.   conn = (connection *) st;
  756.  
  757.   if (!conn)
  758.     return (ERR_NOT_A_SOCKET);
  759.  
  760.   if ((retval = conn->put_data_buffered (data, length)))
  761.     return (retval);
  762.  
  763.   return (0);
  764. }
  765.  
  766. //---------------------------------------------------------------------------
  767. //
  768. //
  769.  
  770. int FAR PASCAL GENSOCK_EXPORT
  771. gensock_put_data_flush (socktag st)
  772. {
  773.   connection * conn;
  774.   int retval = 0;
  775.  
  776.   conn = (connection *) st;
  777.  
  778.   if (!conn)
  779.     return (ERR_NOT_A_SOCKET);
  780.  
  781.   if ((retval = conn->put_data_flush() ))
  782.     return (retval);
  783.  
  784.   return (0);
  785. }
  786.  
  787. //---------------------------------------------------------------------------
  788. //
  789. //
  790. int FAR PASCAL GENSOCK_EXPORT
  791. gensock_gethostname (char FAR * name, int namelen)
  792. {
  793.   int retval;
  794.   if ((retval = gethostname(name, namelen))) {
  795.     return (retval - 5000);
  796.   }
  797.   else return (0);
  798. }
  799.  
  800. //---------------------------------------------------------------------------
  801. //
  802. //
  803.  
  804. int FAR PASCAL GENSOCK_EXPORT
  805. gensock_close (socktag st)
  806. {
  807.   connection * conn;
  808.   int retval;
  809.  
  810.   conn = (connection *) st;
  811.  
  812.   if (!conn)
  813.     return (ERR_NOT_A_SOCKET);
  814.  
  815.   if ((retval = conn->close()))
  816.     return (retval);
  817.  
  818.   global_socket_list.remove((connection *)st);
  819.  
  820.   if (global_socket_list.how_many_are_mine() < 1) {
  821.     deinit_winsock();
  822.   }
  823.  
  824.   return (0);
  825. }
  826.  
  827. //---------------------------------------------------------------------------
  828. //
  829. //
  830.  
  831. int
  832. init_winsock(void)
  833. {
  834.   int retval;
  835.   WSADATA winsock_data;
  836.   WORD version_required = 0x0101; /* Version 1.1 */
  837.  
  838.   retval = WSAStartup (version_required, &winsock_data);
  839.  
  840.   switch (retval) {
  841.   case 0:
  842.     /* successful */
  843.     break;
  844.   case WSASYSNOTREADY:
  845.     return (ERR_SYS_NOT_READY);
  846.     break;
  847.   case WSAEINVAL:
  848.     return (ERR_EINVAL);
  849.     break;
  850.   case WSAVERNOTSUPPORTED:
  851.     return (ERR_VER_NOT_SUPPORTED);
  852.     break;
  853.   }
  854.   network_initialized = 1;
  855.   return (0);
  856. }
  857.  
  858. void
  859. deinit_winsock(void)
  860. {
  861.   network_initialized = 0;
  862.   WSACleanup();
  863. }
  864.