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