home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / mitsch75.zip / scheme-7_5_17-src.zip / scheme-7.5.17 / src / microcode / ntsock.c < prev    next >
C/C++ Source or Header  |  2001-07-18  |  9KB  |  348 lines

  1. /* -*-C-*-
  2.  
  3. $Id: ntsock.c,v 1.11 2001/07/19 00:44:37 cph Exp $
  4.  
  5. Copyright (c) 1997-2001 Massachusetts Institute of Technology
  6.  
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or (at
  10. your option) any later version.
  11.  
  12. This program is distributed in the hope that it will be useful, but
  13. WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15. General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with this program; if not, write to the Free Software
  19. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  20. USA.
  21. */
  22.  
  23. /* This conditional encompasses the entire file.  */
  24. #ifndef DISABLE_SOCKET_SUPPORT
  25.  
  26. #include "scheme.h"
  27. #include "prims.h"
  28. #include "nt.h"
  29. #include "ntio.h"
  30. #include "uxsock.h"
  31.  
  32. #include <winsock.h>
  33.  
  34. channel_class_t * NT_channel_class_tcp_stream_socket;
  35. channel_class_t * NT_channel_class_tcp_server_socket;
  36.  
  37. #define VOID_SOCKET_CALL(proc, args)                    \
  38. {                                    \
  39.   if ((proc args) == SOCKET_ERROR)                    \
  40.     NT_error_api_call ((WSAGetLastError ()), apicall_ ## proc);        \
  41. }
  42.  
  43. #define SOCKET_SOCKET_CALL(proc, args, var)                \
  44. {                                    \
  45.   var = (proc args);                            \
  46.   if (var == INVALID_SOCKET)                        \
  47.     NT_error_api_call ((WSAGetLastError ()), apicall_ ## proc);        \
  48. }
  49.  
  50. #define VALUE_SOCKET_CALL(proc, args, var)                \
  51. {                                    \
  52.   var = (proc args);                            \
  53.   if (var == SOCKET_ERROR)                        \
  54.     NT_error_api_call ((WSAGetLastError ()), apicall_ ## proc);        \
  55. }
  56.  
  57. #define CHANNEL_SOCKET(c) ((SOCKET) (CHANNEL_HANDLE (c)))
  58.  
  59. #define RETURN_SOCKET(s, class)                        \
  60. {                                    \
  61.   Tchannel channel = (NT_make_channel (((HANDLE) (s)), (class)));    \
  62.   transaction_commit ();                        \
  63.   return (channel);                            \
  64. }
  65.  
  66. static void
  67. socket_close_on_abort_1 (void * sp)
  68. {
  69.   (void) closesocket (* ((SOCKET *) sp));
  70. }
  71.  
  72. static void
  73. socket_close_on_abort (SOCKET s)
  74. {
  75.   SOCKET * sp = (dstack_alloc (sizeof (SOCKET)));
  76.   (*sp) = s;
  77.   transaction_record_action (tat_abort, socket_close_on_abort_1, sp);
  78. }
  79.  
  80. Tchannel
  81. OS_open_tcp_stream_socket (void * host, unsigned int port)
  82. {
  83.   SOCKET s;
  84.   struct sockaddr_in address;
  85.  
  86.   SOCKET_SOCKET_CALL (socket, (PF_INET, SOCK_STREAM, 0), s);
  87.   transaction_begin ();
  88.   socket_close_on_abort (s);
  89.   memset ((&address), 0, (sizeof (address)));
  90.   (address . sin_family) = AF_INET;
  91.   memcpy ((& (address . sin_addr)), host, (sizeof (address . sin_addr)));
  92.   (address . sin_port) = port;
  93.   VOID_SOCKET_CALL
  94.     (connect, (s,
  95.            ((struct sockaddr *) (&address)),
  96.            (sizeof (address))));
  97.   RETURN_SOCKET (s, NT_channel_class_tcp_stream_socket);
  98. }
  99.  
  100. int
  101. OS_get_service_by_name (const char * service_name, const char * protocol_name)
  102. {
  103.   struct servent * entry = (getservbyname (service_name, protocol_name));
  104.   return ((entry == 0) ? (-1) : (entry -> s_port));
  105. }
  106.  
  107. unsigned long
  108. OS_get_service_by_number (const unsigned long port_number)
  109. {
  110.   return ((unsigned long) (htons ((unsigned short) port_number)));
  111. }
  112.  
  113. unsigned int
  114. OS_host_address_length (void)
  115. {
  116.   return (sizeof (struct in_addr));
  117. }
  118.  
  119. char **
  120. OS_get_host_by_name (const char * host_name)
  121. {
  122.   struct hostent * entry = (gethostbyname (host_name));
  123.   return ((entry == 0) ? 0 : (entry -> h_addr_list));
  124. }
  125.  
  126. const char *
  127. OS_get_host_name (void)
  128. {
  129.   unsigned int name_length = 128;
  130.   char * name = (OS_malloc (name_length));
  131.   while (1)
  132.     {
  133.       if ((gethostname (name, name_length)) != SOCKET_ERROR)
  134.     break;
  135.       {
  136.     DWORD code = (WSAGetLastError ());
  137.     if (code != WSAEFAULT)
  138.       {
  139.         OS_free (name);
  140.         NT_error_api_call (code, apicall_gethostname);
  141.       }
  142.       }
  143.       name_length *= 2;
  144.       name = (OS_realloc (name, name_length));
  145.     }
  146.   return (OS_realloc (name, ((strlen (name)) + 1)));
  147. }
  148.  
  149. const char *
  150. OS_canonical_host_name (const char * host_name)
  151. {
  152.   struct hostent * entry = (gethostbyname (host_name));
  153.   if (entry == 0)
  154.     return (0);
  155.   {
  156.     char * result = (OS_malloc ((strlen (entry -> h_name)) + 1));
  157.     strcpy (result, (entry -> h_name));
  158.     return (result);
  159.   }
  160. }
  161.  
  162. const char *
  163. OS_get_host_by_address (const char * host_addr)
  164. {
  165.   struct hostent * entry
  166.     = (gethostbyaddr (host_addr, (OS_host_address_length ()), AF_INET));
  167.   if (entry == 0)
  168.     return (0);
  169.   {
  170.     char * result = (OS_malloc ((strlen (entry -> h_name)) + 1));
  171.     strcpy (result, (entry -> h_name));
  172.     return (result);
  173.   }
  174. }
  175.  
  176. void
  177. OS_host_address_any (void * addr)
  178. {
  179.   (((struct in_addr *) addr) -> s_addr) = (htonl (INADDR_ANY));
  180. }
  181.  
  182. void
  183. OS_host_address_loopback (void * addr)
  184. {
  185.   (((struct in_addr *) addr) -> s_addr) = (htonl (INADDR_LOOPBACK));
  186. }
  187.  
  188. Tchannel
  189. OS_create_tcp_server_socket (void)
  190. {
  191.   SOCKET s;
  192.   SOCKET_SOCKET_CALL (socket, (PF_INET, SOCK_STREAM, 0), s);
  193.   RETURN_SOCKET (s, NT_channel_class_tcp_server_socket);
  194. }
  195.  
  196. void
  197. OS_bind_tcp_server_socket (Tchannel channel, void * host, unsigned int port)
  198. {
  199.   struct sockaddr_in address;
  200.   memset ((&address), 0, (sizeof (address)));
  201.   (address . sin_family) = AF_INET;
  202.   memcpy ((& (address . sin_addr)), host, (sizeof (address . sin_addr)));
  203.   (address . sin_port) = port;
  204.   VOID_SOCKET_CALL
  205.     (bind, ((CHANNEL_SOCKET (channel)),
  206.         ((struct sockaddr *) (&address)),
  207.         (sizeof (struct sockaddr_in))));
  208. }
  209.  
  210. #ifndef SOCKET_LISTEN_BACKLOG
  211. #define SOCKET_LISTEN_BACKLOG 5
  212. #endif
  213.  
  214. void
  215. OS_listen_tcp_server_socket (Tchannel channel)
  216. {
  217.   VOID_SOCKET_CALL
  218.     (listen, ((CHANNEL_SOCKET (channel)), SOCKET_LISTEN_BACKLOG));
  219. }
  220.  
  221. Tchannel
  222. OS_server_connection_accept (Tchannel channel,
  223.                  char * peer_host, unsigned int * peer_port)
  224. {
  225.   static struct sockaddr_in address;
  226.   SOCKET s;
  227.  
  228.   {
  229.     unsigned long nonblockp = (CHANNEL_NONBLOCKING (channel));
  230.     VOID_SOCKET_CALL
  231.       (ioctlsocket, ((CHANNEL_SOCKET (channel)), FIONBIO, (&nonblockp)));
  232.   }
  233.   {
  234.     int address_length = (sizeof (struct sockaddr_in));
  235.     s = (accept ((CHANNEL_SOCKET (channel)),
  236.          ((struct sockaddr *) (&address)),
  237.          (&address_length)));
  238.   }
  239.   if (s == INVALID_SOCKET)
  240.     {
  241.       DWORD code = (WSAGetLastError ());
  242.       if (code == WSAEWOULDBLOCK)
  243.     return (NO_CHANNEL);
  244.       NT_error_api_call (code, apicall_accept);
  245.     }
  246.   transaction_begin ();
  247.   socket_close_on_abort (s);
  248.   if (peer_host != 0)
  249.     memcpy (peer_host,
  250.         (& (address . sin_addr)),
  251.         (sizeof (address . sin_addr)));
  252.   if (peer_port != 0)
  253.     (*peer_port) = (address . sin_port);
  254.   RETURN_SOCKET (s, NT_channel_class_tcp_stream_socket);
  255. }
  256.  
  257. static long
  258. socket_channel_read (Tchannel channel, void * buffer, unsigned long n_bytes)
  259. {
  260.   int n_read;
  261.   if (CHANNEL_NONBLOCKING (channel))
  262.     {
  263.       long n = (NT_channel_n_read (channel));
  264.       if (n <= 0)
  265.     return (n);
  266.     }
  267.   VALUE_SOCKET_CALL
  268.     (recv, ((CHANNEL_SOCKET (channel)), buffer, n_bytes, 0), n_read);
  269.   return (n_read);
  270. }
  271.  
  272. static long
  273. socket_channel_write (Tchannel channel, const void * buffer,
  274.               unsigned long n_bytes)
  275. {
  276.   int n_written;
  277.   VALUE_SOCKET_CALL
  278.     (send, ((CHANNEL_SOCKET (channel)), buffer, n_bytes, 0), n_written);
  279.   return (n_written);
  280. }
  281.  
  282. static void
  283. socket_channel_close (Tchannel channel, int errorp)
  284. {
  285.   if (((closesocket (CHANNEL_SOCKET (channel))) == SOCKET_ERROR) && errorp)
  286.     NT_error_api_call ((GetLastError ()), apicall_closesocket);
  287. }
  288.  
  289. static long
  290. socket_channel_n_read (Tchannel channel)
  291. {
  292.   unsigned long n;
  293.   VOID_SOCKET_CALL (ioctlsocket, ((CHANNEL_SOCKET (channel)), FIONREAD, (&n)));
  294.   /* Zero bytes available means "read would block", so return -1.  */
  295.   return ((n == 0) ? (-1) : n);
  296. }
  297.  
  298. static long
  299. server_channel_read (Tchannel channel, void * buffer, unsigned long n_bytes)
  300. {
  301.   error_external_return ();
  302.   return (0);
  303. }
  304.  
  305. static long
  306. server_channel_write (Tchannel channel, const void * buffer,
  307.               unsigned long n_bytes)
  308. {
  309.   error_external_return ();
  310.   return (0);
  311. }
  312.  
  313. static long
  314. server_channel_n_read (Tchannel channel)
  315. {
  316.   error_external_return ();
  317.   return (0);
  318. }
  319.  
  320. void
  321. NT_initialize_sockets (void)
  322. {
  323.   {
  324.     channel_class_t * class = (OS_malloc (sizeof (channel_class_t)));
  325.     (CHANNEL_CLASS_TYPE (class)) = channel_type_tcp_stream_socket;
  326.     (CHANNEL_CLASS_OP_READ (class)) = socket_channel_read;
  327.     (CHANNEL_CLASS_OP_WRITE (class)) = socket_channel_write;
  328.     (CHANNEL_CLASS_OP_CLOSE (class)) = socket_channel_close;
  329.     (CHANNEL_CLASS_OP_N_READ (class)) = socket_channel_n_read;
  330.     NT_channel_class_tcp_stream_socket = class;
  331.   }
  332.   {
  333.     channel_class_t * class = (OS_malloc (sizeof (channel_class_t)));
  334.     (CHANNEL_CLASS_TYPE (class)) = channel_type_tcp_server_socket;
  335.     (CHANNEL_CLASS_OP_READ (class)) = server_channel_read;
  336.     (CHANNEL_CLASS_OP_WRITE (class)) = server_channel_write;
  337.     (CHANNEL_CLASS_OP_CLOSE (class)) = socket_channel_close;
  338.     (CHANNEL_CLASS_OP_N_READ (class)) = server_channel_n_read;
  339.     NT_channel_class_tcp_server_socket = class;
  340.   }
  341.   {
  342.     WSADATA wsa_data;
  343.     WSAStartup ((MAKEWORD (2, 0)), (&wsa_data));
  344.   }
  345. }
  346.  
  347. #endif /* not DISABLE_SOCKET_SUPPORT */
  348.