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 / os2sock.c < prev    next >
C/C++ Source or Header  |  2001-07-18  |  9KB  |  342 lines

  1. /* -*-C-*-
  2.  
  3. $Id: os2sock.c,v 1.18 2001/07/19 01:45:36 cph Exp $
  4.  
  5. Copyright (c) 1990-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. /* This definition is necessary for compilation with newer versions of
  27.    the Developer's Toolkit for OS/2.  The newer version default to
  28.    using TCP/IP 4.1, but this code was designed for TCP/IP 4.0.  */
  29. #define TCPV40HDRS
  30.  
  31. #include "scheme.h"
  32. #include "prims.h"
  33. #include "osscheme.h"
  34. #include "os2.h"
  35. #include "uxsock.h"
  36.  
  37. #include <types.h>
  38. #include <netinet/in.h>
  39. #include <netdb.h>
  40. #include <sys/un.h>
  41. #include <sys/socket.h>
  42.  
  43. #ifndef INADDR_LOOPBACK
  44. #  define INADDR_LOOPBACK 0x7F000001
  45. #endif
  46.  
  47. static Tchannel initialize_stream_socket (int, enum channel_type);
  48. static msg_t * stream_socket_reader (LHANDLE, qid_t, msg_t *, int *);
  49. static void stream_socket_operator
  50.   (Tchannel, chop_t, choparg_t, choparg_t, choparg_t);
  51.  
  52. #define VOID_SOCKET_CALL(proc, args)                    \
  53. {                                    \
  54.   while ((proc args) < 0)                        \
  55.     {                                    \
  56.       if ((sock_errno ()) != SOCEINTR)                    \
  57.     OS2_error_system_call ((sock_errno ()), syscall_ ## proc);    \
  58.       deliver_pending_interrupts ();                    \
  59.     }                                    \
  60. }
  61.  
  62. #define VALUE_SOCKET_CALL(proc, args, var)                \
  63. {                                    \
  64.   while (1)                                \
  65.     {                                    \
  66.       int rc = (proc args);                        \
  67.       if (rc >= 0)                            \
  68.     {                                \
  69.       var = rc;                            \
  70.       break;                            \
  71.     }                                \
  72.       if ((sock_errno ()) != SOCEINTR)                    \
  73.     OS2_error_system_call ((sock_errno ()), syscall_ ## proc);    \
  74.       deliver_pending_interrupts ();                    \
  75.     }                                    \
  76. }
  77.  
  78. static void
  79. socket_close_on_abort_1 (void * sp)
  80. {
  81.   (void) soclose (* ((int *) sp));
  82. }
  83.  
  84. static void
  85. socket_close_on_abort (int s)
  86. {
  87.   int * sp = (dstack_alloc (sizeof (int)));
  88.   (*sp) = s;
  89.   transaction_record_action (tat_abort, socket_close_on_abort_1, sp);
  90. }
  91.  
  92. Tchannel
  93. OS_open_tcp_stream_socket (void * host, unsigned int port)
  94. {
  95.   int s;
  96.   struct sockaddr_in address;
  97.  
  98.   transaction_begin ();
  99.   VALUE_SOCKET_CALL (socket, (PF_INET, SOCK_STREAM, 0), s);
  100.   socket_close_on_abort (s);
  101.   memset ((&address), 0, (sizeof (address)));
  102.   (address . sin_family) = AF_INET;
  103.   memcpy ((& (address . sin_addr)), host, (sizeof (struct in_addr)));
  104.   (address . sin_port) = port;
  105.   VOID_SOCKET_CALL
  106.     (connect, (s,
  107.            ((struct sockaddr *) (&address)),
  108.            (sizeof (address))));
  109.   return (initialize_stream_socket (s, channel_type_tcp_stream_socket));
  110. }
  111.  
  112. Tchannel
  113. OS_open_unix_stream_socket (const char * filename)
  114. {
  115.   int s;
  116.   struct sockaddr_un address;
  117.  
  118.   transaction_begin ();
  119.   VALUE_SOCKET_CALL (socket, (PF_OS2, SOCK_STREAM, 0), s);
  120.   socket_close_on_abort (s);
  121.   memset ((&address), 0, (sizeof (address)));
  122.   (address . sun_family) = AF_OS2;
  123.   strncpy ((address . sun_path), filename, (sizeof (address . sun_path)));
  124.   VOID_SOCKET_CALL
  125.     (connect, (s,
  126.            ((struct sockaddr *) (&address)),
  127.            (sizeof (address))));
  128.   return (initialize_stream_socket (s, channel_type_unix_stream_socket));
  129. }
  130.  
  131. int
  132. OS_get_service_by_name (const char * service_name, const char * protocol_name)
  133. {
  134.   struct servent * entry
  135.     = (getservbyname (((char *) service_name),
  136.               ((char *) protocol_name)));
  137.   return ((entry == 0) ? (-1) : (entry -> s_port));
  138. }
  139.  
  140. unsigned long
  141. OS_get_service_by_number (const unsigned long port_number)
  142. {
  143.   return ((unsigned long) (htons ((unsigned short) port_number)));
  144. }
  145.  
  146. unsigned int
  147. OS_host_address_length (void)
  148. {
  149.   return (sizeof (struct in_addr));
  150. }
  151.  
  152. char **
  153. OS_get_host_by_name (const char * host_name)
  154. {
  155.   struct hostent * entry = (gethostbyname ((char *) host_name));
  156.   return ((entry == 0) ? 0 : (entry -> h_addr_list));
  157. }
  158.  
  159. #define HOSTNAMESIZE 1024
  160.  
  161. const char *
  162. OS_get_host_name (void)
  163. {
  164.   char host_name [HOSTNAMESIZE];
  165.   if (gethostname (host_name, HOSTNAMESIZE))
  166.     OS2_error_anonymous ();
  167.   {
  168.     char * result = (OS_malloc ((strlen (host_name)) + 1));
  169.     strcpy (result, host_name);
  170.     return (result);
  171.   }
  172. }
  173.  
  174. const char *
  175. OS_canonical_host_name (const char * host_name)
  176. {
  177.   struct hostent * entry = (gethostbyname ((char *) host_name));
  178.   if (entry == 0)
  179.     return (0);
  180.   {
  181.     char * result = (OS_malloc ((strlen (entry -> h_name)) + 1));
  182.     strcpy (result, (entry -> h_name));
  183.     return (result);
  184.   }
  185. }
  186.  
  187. const char *
  188. OS_get_host_by_address (const char * host_addr)
  189. {
  190.   struct hostent * entry
  191.     = (gethostbyaddr (((char *) host_addr),
  192.               (OS_host_address_length ()),
  193.               AF_INET));
  194.   if (entry == 0)
  195.     return (0);
  196.   {
  197.     char * result = (OS_malloc ((strlen (entry -> h_name)) + 1));
  198.     strcpy (result, (entry -> h_name));
  199.     return (result);
  200.   }
  201. }
  202.  
  203. void
  204. OS_host_address_any (void * addr)
  205. {
  206.   (((struct in_addr *) addr) -> s_addr) = (htonl (INADDR_ANY));
  207. }
  208.  
  209. void
  210. OS_host_address_loopback (void * addr)
  211. {
  212.   (((struct in_addr *) addr) -> s_addr) = (htonl (INADDR_LOOPBACK));
  213. }
  214.  
  215. Tchannel
  216. OS_create_tcp_server_socket (void)
  217. {
  218.   int s;
  219.   VALUE_SOCKET_CALL (socket, (PF_INET, SOCK_STREAM, 0), s);
  220.   return (initialize_stream_socket (s, channel_type_tcp_server_socket));
  221. }
  222.  
  223. void
  224. OS_bind_tcp_server_socket (Tchannel channel, void * host, unsigned int port)
  225. {
  226.   struct sockaddr_in address;
  227.   memset ((&address), 0, (sizeof (address)));
  228.   (address . sin_family) = AF_INET;
  229.   memcpy ((& (address . sin_addr)), host, (sizeof (address . sin_addr)));
  230.   (address . sin_port) = port;
  231.   VOID_SOCKET_CALL
  232.     (bind, (((int) (CHANNEL_HANDLE (channel))),
  233.         ((struct sockaddr *) (&address)),
  234.         (sizeof (struct sockaddr_in))));
  235. }
  236.  
  237. #ifndef SOCKET_LISTEN_BACKLOG
  238. #define SOCKET_LISTEN_BACKLOG 5
  239. #endif
  240.  
  241. void
  242. OS_listen_tcp_server_socket (Tchannel channel)
  243. {
  244.   VOID_SOCKET_CALL
  245.     (listen, (((int) (CHANNEL_HANDLE (channel))), SOCKET_LISTEN_BACKLOG));
  246. }
  247.  
  248. Tchannel
  249. OS_server_connection_accept (Tchannel channel,
  250.                  void * peer_host, unsigned int * peer_port)
  251. {
  252.   static struct sockaddr_in address;
  253.   int s;
  254.  
  255.   transaction_begin ();
  256.   while (1)
  257.     {
  258.       int address_length = (sizeof (struct sockaddr_in));
  259.       s = (accept (((int) (CHANNEL_HANDLE (channel))),
  260.            ((struct sockaddr *) (&address)),
  261.            (&address_length)));
  262.       if (s >= 0)
  263.     break;
  264.       if ((sock_errno ()) == SOCEWOULDBLOCK)
  265.     return (NO_CHANNEL);
  266.       if ((sock_errno ()) != SOCEINTR)
  267.     OS2_error_system_call ((sock_errno ()), syscall_accept);
  268.       deliver_pending_interrupts ();
  269.     }
  270.   socket_close_on_abort (s);
  271.   if (peer_host != 0)
  272.     memcpy (peer_host, (& (address . sin_addr)), (sizeof (struct in_addr)));
  273.   if (peer_port != 0)
  274.     (*peer_port) = (address . sin_port);
  275.   return (initialize_stream_socket (s, channel_type_tcp_stream_socket));
  276. }
  277.  
  278. static Tchannel
  279. initialize_stream_socket (int s, enum channel_type type)
  280. {
  281.   Tchannel channel = (OS2_allocate_channel ());
  282.   OS2_initialize_channel (channel, s, (CHANNEL_READ | CHANNEL_WRITE), type);
  283.   OS2_start_channel_thread (channel,
  284.                 stream_socket_reader,
  285.                 stream_socket_operator);
  286.   transaction_commit ();
  287.   return (channel);
  288. }
  289.  
  290. static msg_t *
  291. stream_socket_reader (LHANDLE handle, qid_t qid, msg_t * message, int * eofp)
  292. {
  293.   int nread;
  294.   do
  295.     nread = (recv (((int) handle),
  296.            (SM_READAHEAD_DATA (message)),
  297.            (sizeof (SM_READAHEAD_DATA (message))),
  298.            0));
  299.   while ((nread < 0) && ((sock_errno ()) == SOCEINTR));
  300.   if (nread >= 0)
  301.     {
  302.       (SM_READAHEAD_SIZE (message)) = nread;
  303.       (*eofp) = (nread == 0);
  304.       return (message);
  305.     }
  306.   OS2_destroy_message (message);
  307.   if ((sock_errno ()) == SOCENOTSOCK)
  308.     /* Socket was closed on us -- no need to do anything else.  */
  309.     return (0);
  310.   (*eofp) = 0;
  311.   return (OS2_make_syscall_error ((sock_errno ()), syscall_recv));
  312. }
  313.  
  314. static void
  315. stream_socket_operator (Tchannel channel, chop_t operation,
  316.             choparg_t arg1, choparg_t arg2, choparg_t arg3)
  317. {
  318.   switch (operation)
  319.     {
  320.     case chop_read:
  321.       OS2_channel_thread_read_op (channel, arg1, arg2, arg3);
  322.       break;
  323.     case chop_write:
  324.       VALUE_SOCKET_CALL
  325.     (send, (((int) (CHANNEL_HANDLE (channel))),
  326.         ((char *) arg1),
  327.         ((size_t) arg2),
  328.         0),
  329.      (* ((long *) arg3)));
  330.       break;
  331.     case chop_close:
  332.       OS2_channel_thread_close (channel);
  333.       VOID_SOCKET_CALL (soclose, ((int) (CHANNEL_HANDLE (channel))));
  334.       break;
  335.     default:
  336.       OS2_logic_error ("Unknown operation for stream socket.");
  337.       break;
  338.     }
  339. }
  340.  
  341. #endif /* not DISABLE_SOCKET_SUPPORT */
  342.