home *** CD-ROM | disk | FTP | other *** search
/ The Pier Shareware 6 / The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso / 036 / emxfix02.zip / emx / src / os2 / tcpip.c < prev    next >
C/C++ Source or Header  |  1994-12-21  |  32KB  |  1,240 lines

  1. /* tcpip.c -- TCP/IP
  2.    Copyright (c) 1994 by Eberhard Mattes
  3.  
  4. This file is part of emx.
  5.  
  6. emx is free software; you can redistribute it and/or modify it
  7. under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2, or (at your option)
  9. any later version.
  10.  
  11. emx is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with emx; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. /* TODO:
  21.  
  22.   - inheritance of socket handles, maintain global reference count
  23.   - inheritance for fork()
  24.   - add IBM TCP/IP for OS/2 layer (sock_errno() etc.) */
  25.  
  26. #include <sys/emx.h>
  27. #define INCL_DOSDEVIOCTL
  28. #define INCL_DOSEXCEPTIONS
  29. #define INCL_DOSMODULEMGR
  30. #define INCL_DOSSEMAPHORES
  31. #include <os2emx.h>
  32. #include <sys/errno.h>
  33. #include <sys/types.h>
  34. #include <sys/stat.h>
  35. #include <sys/fcntl.h>
  36. #include <sys/ioctl.h>
  37. #include <sys/socket.h>
  38. #include <sys/so_ioctl.h>
  39. #include <net/route.h>
  40. #include <net/if.h>
  41. #include <net/if_arp.h>
  42. #include <netdb.h>
  43. #include "emxdll.h"
  44. #include "files.h"
  45. #include "tcpip.h"
  46. #include "select.h"
  47. #include "clib.h"
  48.  
  49. /* Error codes of IBM TCP/IP for OS/2 start at this number. */
  50.  
  51. #define SOCK_ERRNO_BASE 10000
  52.  
  53. /* This variable is zero while tcpip_init() has not been called.  A
  54.    positive value means that initialization of TCP/IP was successful,
  55.    a negative value means that initialization of TCP/IP failed. */
  56.  
  57. static int tcpip_initialized;
  58.  
  59. /* This variable holds the value returned by the most recent call to
  60.    sock_errno().  In the future, it will be used for providing a
  61.    sock_errno() system call. */
  62.  
  63. static int last_sock_errno;
  64.  
  65. /* Module handles of the two IBM TCP/IP for OS/2 DLLs. */
  66.  
  67. static HMODULE hmod_so32dll;
  68. static HMODULE hmod_tcp32dll;
  69.  
  70. struct sockaddr;
  71.  
  72. /* Pointers to entrypoints of the IBM TCP/IP for OS/2 DLLs. */
  73.  
  74. static int (*tip_accept)(int, struct sockaddr *, int *);
  75. static int (*tip_bind)(int, struct sockaddr *, int);
  76. static int (*tip_connect)(int, struct sockaddr *, int);
  77. static void * (*tip_gethostbyaddr) (const char *, int, int);
  78. static void * (*tip_gethostbyname) (const char *);
  79. static int (*tip_gethostid) (void);
  80. static int (*tip_gethostname) (char *, int len);
  81. static void * (*tip_getnetbyaddr) (long);
  82. static void * (*tip_getnetbyname) (const char *);
  83. static int (*tip_getpeername) (int, void *, int *);
  84. static void * (*tip_getprotobyname) (const char *);
  85. static void * (*tip_getprotobynumber) (int);
  86. static void * (*tip_getservbyname) (const char *, const char *);
  87. static void * (*tip_getservbyport) (int, const char *);
  88. static int (*tip_getsockname) (int, void *, int *);
  89. static int (*tip_getsockopt) (int, int, int, void *, int *);
  90. static int (*tip_ioctl)(int, int, void *, int);
  91. static int (*tip_listen)(int, int);
  92. static int (*tip_recv)(int, void *, int, int);
  93. static int (*tip_recvfrom)(int, void *, int, int, struct sockaddr *, int *);
  94. static int (*tip_select)(int *, int, int, int, long);
  95. static int (*tip_send)(int, const void *, int, int);
  96. static int (*tip_sendto)(int, const void *, int, int, const struct sockaddr *,
  97.     int);
  98. static int (*tip_setsockopt) (int, int, int, const void *, int);
  99. static int (*tip_shutdown) (int, int);
  100. static int (*tip_socket) (int domain, int type, int protocol);
  101. static int (*tip_sock_errno)(void);
  102. static int (*tip_sock_init)(void);
  103. static int (*tip_soclose)(int handle);
  104. static int *tip_h_errno;
  105.  
  106. /* These macros are used for getting the addresses of DLL entrypoints. */
  107.  
  108. #define LOAD(hmod,name,var) (DosQueryProcAddr (hmod, 0, name, (PPFN)var) != 0)
  109. #define LOAD_SO(name,var)   LOAD (hmod_so32dll, name, var)
  110. #define LOAD_TCP(name,var)  LOAD (hmod_tcp32dll, name, var)
  111.  
  112. /* Initialize TCP/IP.  Return FALSE on failure, return TRUE on
  113.    success.  This function must be called before using any of the
  114.    above `tip_*' pointers.  Functions which check HF_SOCKET don't have
  115.    to call tcpip_init() as the HF_SOCKET bit can only be set by a
  116.    function which calls tcpip_init(). */
  117.  
  118. static int tcpip_init (void)
  119. {
  120.   char obj[9];
  121.  
  122.   /* If tcpip_init() has already been called, use the result of the
  123.      first call. */
  124.  
  125.   if (tcpip_initialized < 0)
  126.     return (FALSE);
  127.   if (tcpip_initialized > 0)
  128.     return (TRUE);
  129.  
  130.   /* Indicate failure unless everything works well. */
  131.  
  132.   tcpip_initialized = -1;
  133.  
  134.   /* Load the two IBM TCP/IP for SO/2 DLLs. */
  135.  
  136.   if (DosLoadModule (obj, sizeof (obj), "SO32DLL", &hmod_so32dll) != 0
  137.       ||DosLoadModule (obj, sizeof (obj), "TCP32DLL", &hmod_tcp32dll) != 0)
  138.     return (FALSE);
  139.  
  140.   /* Initialize the pointers to the DLL entrypoints and call
  141.      sock_init(). */
  142.  
  143.   if (LOAD_SO ("SOCK_INIT", &tip_sock_init)
  144.       || LOAD_SO ("SOCK_ERRNO", &tip_sock_errno)
  145.       || LOAD_SO ("ACCEPT", &tip_accept)
  146.       || LOAD_SO ("BIND", &tip_bind)
  147.       || LOAD_SO ("CONNECT", &tip_connect)
  148.       || LOAD_SO ("GETHOSTID", &tip_gethostid)
  149.       || LOAD_SO ("GETPEERNAME", &tip_getpeername)
  150.       || LOAD_SO ("GETSOCKNAME", &tip_getsockname)
  151.       || LOAD_SO ("GETSOCKOPT", &tip_getsockopt)
  152.       || LOAD_SO ("IOCTL", &tip_ioctl)
  153.       || LOAD_SO ("LISTEN", &tip_listen)
  154.       || LOAD_SO ("RECV", &tip_recv)
  155.       || LOAD_SO ("RECVFROM", &tip_recvfrom)
  156.       || LOAD_SO ("SELECT", &tip_select)
  157.       || LOAD_SO ("SEND", &tip_send)
  158.       || LOAD_SO ("SENDTO", &tip_sendto)
  159.       || LOAD_SO ("SETSOCKOPT", &tip_setsockopt)
  160.       || LOAD_SO ("SHUTDOWN", &tip_shutdown)
  161.       || LOAD_SO ("SOCKET", &tip_socket)
  162.       || LOAD_SO ("SOCLOSE", &tip_soclose)
  163.       || LOAD_TCP ("GETHOSTBYADDR", &tip_gethostbyaddr)
  164.       || LOAD_TCP ("GETHOSTBYNAME", &tip_gethostbyname)
  165.       || LOAD_TCP ("GETHOSTNAME", &tip_gethostname)
  166.       || LOAD_TCP ("GETNETBYADDR", &tip_getnetbyaddr)
  167.       || LOAD_TCP ("GETNETBYNAME", &tip_getnetbyname)
  168.       || LOAD_TCP ("GETPROTOBYNAME", &tip_getprotobyname)
  169.       || LOAD_TCP ("GETPROTOBYNUMBER", &tip_getprotobynumber)
  170.       || LOAD_TCP ("GETSERVBYNAME", &tip_getservbyname)
  171.       || LOAD_TCP ("GETSERVBYPORT", &tip_getservbyport)
  172.       || LOAD_TCP ("H_ERRNO", &tip_h_errno)
  173.       || tip_sock_init () != 0)
  174.     {
  175.       DosFreeModule (hmod_so32dll);
  176.       DosFreeModule (hmod_tcp32dll);
  177.       return (FALSE);
  178.     }
  179.  
  180.   /* Sucess! */
  181.  
  182.   tcpip_initialized = 1;
  183.   return (TRUE);
  184. }
  185.  
  186. /* Use UNDEF for error codes which are supposed to not being
  187.    returned by IBM TCP/IP for OS/2. */
  188.  
  189. #define UNDEF   EINVAL
  190.  
  191. /* This table maps error codes of IBM TCP/IP for OS/2 (offset by
  192.    SOCK_ERRNO_BASE) to emx errno numbers.  */
  193.  
  194. static unsigned char const sock_errno_tab[] =
  195. {
  196.   UNDEF,                        /* +0 */
  197.   EPERM,                        /* +1 */
  198.   UNDEF,                        /* +2 */
  199.   ESRCH,                        /* +3 */
  200.   EINTR,                        /* +4 */
  201.   UNDEF,                        /* +5 */
  202.   ENXIO,                        /* +6 */
  203.   UNDEF,                        /* +7 */
  204.   UNDEF,                        /* +8 */
  205.   EBADF,                        /* +9 */
  206.   UNDEF,                        /* +10 */
  207.   UNDEF,                        /* +11 */
  208.   UNDEF,                        /* +12 */
  209.   EACCES,                       /* +13 */
  210.   EFAULT,                       /* +14 */
  211.   UNDEF,                        /* +15 */
  212.   UNDEF,                        /* +16 */
  213.   UNDEF,                        /* +17 */
  214.   UNDEF,                        /* +18 */
  215.   UNDEF,                        /* +19 */
  216.   UNDEF,                        /* +20 */
  217.   UNDEF,                        /* +21 */
  218.   EINVAL,                       /* +22 */
  219.   UNDEF,                        /* +23 */
  220.   EMFILE,                       /* +24 */
  221.   UNDEF,                        /* +25 */
  222.   UNDEF,                        /* +26 */
  223.   UNDEF,                        /* +27 */
  224.   UNDEF,                        /* +28 */
  225.   UNDEF,                        /* +29 */
  226.   UNDEF,                        /* +30 */
  227.   UNDEF,                        /* +31 */
  228.   EPIPE,                        /* +32 */
  229.   UNDEF,                        /* +33 */
  230.   UNDEF,                        /* +34 */
  231.   EWOULDBLOCK,                  /* +35 */
  232.   EINPROGRESS,                  /* +36 */
  233.   EALREADY,                     /* +37 */
  234.   ENOTSOCK,                     /* +38 */
  235.   EDESTADDRREQ,                 /* +39 */
  236.   EMSGSIZE,                     /* +40 */
  237.   EPROTOTYPE,                   /* +41 */
  238.   ENOPROTOOPT,                  /* +42 */
  239.   EPROTONOSUPPORT,              /* +43 */
  240.   ESOCKTNOSUPPORT,              /* +44 */
  241.   EOPNOTSUPP,                   /* +45 */
  242.   EPFNOSUPPORT,                 /* +46 */
  243.   EAFNOSUPPORT,                 /* +47 */
  244.   EADDRINUSE,                   /* +48 */
  245.   EADDRNOTAVAIL,                /* +49 */
  246.   ENETDOWN,                     /* +50 */
  247.   ENETUNREACH,                  /* +51 */
  248.   ENETRESET,                    /* +52 */
  249.   ECONNABORTED,                 /* +53 */
  250.   ECONNRESET,                   /* +54 */
  251.   ENOBUFS,                      /* +55 */
  252.   EISCONN,                      /* +56 */
  253.   ENOTCONN,                     /* +57 */
  254.   ESHUTDOWN,                    /* +58 */
  255.   ETOOMANYREFS,                 /* +59 */
  256.   ETIMEDOUT,                    /* +60 */
  257.   ECONNREFUSED,                 /* +61 */
  258.   ELOOP,                        /* +62 */
  259.   ENAMETOOLONG,                 /* +63 */
  260.   EHOSTDOWN,                    /* +64 */
  261.   EHOSTUNREACH,                 /* +65 */
  262.   ENOTEMPTY,                    /* +66 */
  263.   UNDEF,                        /* +67 */
  264.   UNDEF,                        /* +68 */
  265.   UNDEF,                        /* +69 */
  266.   UNDEF,                        /* +70 */
  267.   UNDEF,                        /* +71 */
  268.   UNDEF,                        /* +72 */
  269.   UNDEF,                        /* +73 */
  270.   UNDEF,                        /* +74 */
  271.   UNDEF,                        /* +75 */
  272.   UNDEF,                        /* +76 */
  273.   UNDEF,                        /* +77 */
  274.   UNDEF,                        /* +78 */
  275.   UNDEF,                        /* +79 */
  276.   UNDEF,                        /* +80 */
  277.   UNDEF,                        /* +81 */
  278.   UNDEF,                        /* +82 */
  279.   UNDEF,                        /* +83 */
  280.   UNDEF,                        /* +84 */
  281.   UNDEF,                        /* +85 */
  282.   UNDEF,                        /* +86 */
  283.   UNDEF,                        /* +87 */
  284.   UNDEF,                        /* +88 */
  285.   UNDEF,                        /* +89 */
  286.   UNDEF,                        /* +90 */
  287.   UNDEF,                        /* +91 */
  288.   UNDEF,                        /* +92 */
  289.   UNDEF,                        /* +93 */
  290.   UNDEF,                        /* +94 */
  291.   UNDEF,                        /* +95 */
  292.   UNDEF,                        /* +96 */
  293.   UNDEF,                        /* +97 */
  294.   UNDEF,                        /* +98 */
  295.   UNDEF,                        /* +99 */
  296.   EIO                           /* +100: SOCEOS2ERR */
  297. };
  298.  
  299.  
  300. /* Obtain, translate, and return the error code of the most recent
  301.    TCP/IP call. */
  302.  
  303. static int tcpip_errno (void)
  304. {
  305.   int e;
  306.  
  307.   e = tip_sock_errno ();
  308.   last_sock_errno = e;
  309.   if (e < SOCK_ERRNO_BASE || e >= SOCK_ERRNO_BASE + sizeof (sock_errno_tab))
  310.     return (EINVAL);
  311.   return (sock_errno_tab[e - SOCK_ERRNO_BASE]);
  312. }
  313.  
  314.  
  315. /* Fake a low-level file I/O handle for a socket.  Instead of (or in
  316.    addition to) relocating OS/2 file handles, we might open the "NUL"
  317.    device to fill the slot used for the faked handle. */
  318.  
  319. static int tcpip_new_handle (int s, int *errnop)
  320. {
  321.   int i;
  322.  
  323.   /* We might want to prefer handles with high numbers to minimize
  324.      relocation of file handles; however, we don't know the value of
  325.      the application's `_nfiles' variable. */
  326.  
  327.   LOCK_FILES;
  328.   for (i = 0; i < handle_count; ++i)
  329.     if (!(handle_flags[i] & HF_OPEN))
  330.       {
  331.         alloc_file_description (i);
  332.         if (!IS_VALID_FILE (i))
  333.           break;
  334.         set_handle_flags (i, HF_OPEN | HF_SOCKET);
  335.         GET_FILE (i)->x.socket.handle = s;
  336.         UNLOCK_FILES;
  337.         *errnop = 0;
  338.         return (i);
  339.       }
  340.   UNLOCK_FILES;
  341.   tip_soclose (s);
  342.   *errnop = EMFILE;
  343.   return (-1);
  344. }
  345.  
  346.  
  347. /* __socket() */
  348.  
  349. int tcpip_socket (int domain, int type, int protocol, int *errnop)
  350. {
  351.   int s;
  352.  
  353.   if (!tcpip_init ())
  354.     {
  355.       *errnop = ENETDOWN;       /* TODO: last_sock_errno */
  356.       return (-1);
  357.     }
  358.  
  359.   s = tip_socket (domain, type, protocol);
  360.   if (s == -1)
  361.     {
  362.       *errnop = tcpip_errno ();
  363.       return (-1);
  364.     }
  365.  
  366.   return (tcpip_new_handle (s, errnop));
  367. }
  368.  
  369.  
  370. /* __getsockhandle() */
  371.  
  372. int tcpip_getsockhandle (ULONG handle, int *errnop)
  373. {
  374.   if (!IS_SOCKET (handle) || !IS_VALID_FILE (handle))
  375.     {
  376.       *errnop = EBADF;
  377.       return (-1);
  378.     }
  379.   *errnop = 0;
  380.   return (GET_FILE (handle)->x.socket.handle);
  381. }
  382.  
  383.  
  384. /* __accept() */
  385.  
  386. int tcpip_accept (ULONG handle, void *addr, int *paddrlen, int *errnop)
  387. {
  388.   int s;
  389.  
  390.   if (!IS_SOCKET (handle) || !IS_VALID_FILE (handle))
  391.     {
  392.       *errnop = EBADF;          /* TODO: last_sock_errno */
  393.       return (-1);
  394.     }
  395.  
  396.   s = tip_accept (GET_FILE (handle)->x.socket.handle, addr, paddrlen);
  397.   if (s == -1)
  398.     {
  399.       *errnop = tcpip_errno ();
  400.       return (-1);
  401.     }
  402.  
  403.   return (tcpip_new_handle (s, errnop));
  404. }
  405.  
  406.  
  407. /* __bind() */
  408.  
  409. int tcpip_bind (ULONG handle, void *addr, int addrlen)
  410. {
  411.   int rc;
  412.  
  413.   if (!IS_SOCKET (handle) || !IS_VALID_FILE (handle))
  414.     return (EBADF);             /* TODO: last_sock_errno */
  415.  
  416.   rc = tip_bind (GET_FILE (handle)->x.socket.handle, addr, addrlen);
  417.   if (rc != 0)
  418.     return (tcpip_errno ());
  419.   last_sock_errno = 0;
  420.   return (0);
  421. }
  422.  
  423.  
  424. /* __connect() */
  425.  
  426. int tcpip_connect (ULONG handle, void *addr, int addrlen)
  427. {
  428.   int rc;
  429.  
  430.   if (!IS_SOCKET (handle) || !IS_VALID_FILE (handle))
  431.     return (EBADF);             /* TODO: last_sock_errno */
  432.  
  433.   rc = tip_connect (GET_FILE (handle)->x.socket.handle, addr, addrlen);
  434.   if (rc != 0)
  435.     return (tcpip_errno ());
  436.   last_sock_errno = 0;
  437.   return (0);
  438. }
  439.  
  440.  
  441. /* __listen() */
  442.  
  443. int tcpip_listen (ULONG handle, int backlog)
  444. {
  445.   int rc;
  446.  
  447.   if (!IS_SOCKET (handle) || !IS_VALID_FILE (handle))
  448.     return (EBADF);             /* TODO: last_sock_errno */
  449.  
  450.   rc = tip_listen (GET_FILE (handle)->x.socket.handle, backlog);
  451.   if (rc != 0)
  452.     return (tcpip_errno ());
  453.   last_sock_errno = 0;
  454.   return (0);
  455. }
  456.  
  457.  
  458. /* __recv() */
  459.  
  460. int tcpip_recv (ULONG handle, void *buf, int len, unsigned flags, int *errnop)
  461. {
  462.   int rc;
  463.  
  464.   if (!IS_SOCKET (handle) || !IS_VALID_FILE (handle))
  465.     {
  466.       *errnop = EBADF;          /* TODO: last_sock_errno */
  467.       return (-1);
  468.     }
  469.  
  470.   if (len > 0x7fff) len = 0x7ffc;
  471.   rc = tip_recv (GET_FILE (handle)->x.socket.handle, buf, len, flags);
  472.   if (rc == -1)
  473.     {
  474.       *errnop = tcpip_errno ();
  475.       return (-1);
  476.     }
  477.   *errnop = 0;
  478.   last_sock_errno = 0;
  479.   return (rc);
  480. }
  481.  
  482.  
  483. /* __recvfrom() */
  484.  
  485. int tcpip_recvfrom (const struct _recvfrom *args, int *errnop)
  486. {
  487.   ULONG handle;
  488.   int rc, len;
  489.  
  490.   handle = args->handle;
  491.   if (!IS_SOCKET (handle) || !IS_VALID_FILE (handle))
  492.     {
  493.       *errnop = EBADF;          /* TODO: last_sock_errno */
  494.       return (-1);
  495.     }
  496.  
  497.   len = args->len;
  498.   if (len > 0x7fff) len = 0x7ffc;
  499.   rc = tip_recvfrom (GET_FILE (handle)->x.socket.handle, args->buf, len,
  500.                      args->flags, args->from, args->pfromlen);
  501.   if (rc == -1)
  502.     {
  503.       *errnop = tcpip_errno ();
  504.       return (-1);
  505.     }
  506.   *errnop = 0;
  507.   last_sock_errno = 0;
  508.   return (rc);
  509. }
  510.  
  511.  
  512. /* __send() */
  513.  
  514. int tcpip_send (ULONG handle, const void *buf, int len, unsigned flags,
  515.                 int *errnop)
  516. {
  517.   int rc, n, result, e;
  518.   const char *p;
  519.  
  520.   if (!IS_SOCKET (handle) || !IS_VALID_FILE (handle))
  521.     {
  522.       *errnop = EBADF;          /* TODO: last_sock_errno */
  523.       return (-1);
  524.     }
  525.  
  526.   /* TODO: Return EMSGSIZE if appropriate. */
  527.  
  528.   p = buf; result = 0;
  529.   while (len > 0)
  530.     {
  531.       n = (len > 0x7fff ? 0x7ffc : len);
  532.       rc = tip_send (GET_FILE (handle)->x.socket.handle, p, n, flags);
  533.       if (rc == -1)
  534.         {
  535.           e = tcpip_errno ();
  536.           if (e == EWOULDBLOCK && result != 0)
  537.             break;
  538.           *errnop = e;
  539.           return (-1);
  540.         }
  541.       result += rc;
  542.       if (rc != n) break;
  543.       p += rc; len -= rc;
  544.     }
  545.  
  546.   *errnop = 0;
  547.   last_sock_errno = 0;
  548.   return (result);
  549. }
  550.  
  551.  
  552. /* __sendto() */
  553.  
  554. int tcpip_sendto (const struct _sendto *args, int *errnop)
  555. {
  556.   ULONG handle;
  557.   int rc, len, n, result, e;
  558.   const char *p;
  559.  
  560.   handle = args->handle;
  561.   if (!IS_SOCKET (handle) || !IS_VALID_FILE (handle))
  562.     {
  563.       *errnop = EBADF;          /* TODO: last_sock_errno */
  564.       return (-1);
  565.     }
  566.  
  567.   /* TODO: Return EMSGSIZE if appropriate. */
  568.  
  569.   p = args->buf; result = 0; len = args->len;
  570.   while (len > 0)
  571.     {
  572.       n = (len > 0x7fff ? 0x7ffc : len);
  573.       rc = tip_sendto (GET_FILE (handle)->x.socket.handle, p, n, args->flags,
  574.                        args->to, args->tolen);
  575.       if (rc == -1)
  576.         {
  577.           e = tcpip_errno ();
  578.           if (e == EWOULDBLOCK && result != 0)
  579.             break;
  580.           *errnop = e;
  581.           return (-1);
  582.         }
  583.       result += rc;
  584.       if (rc != n) break;
  585.       p += rc; len -= rc;
  586.     }
  587.  
  588.   *errnop = 0;
  589.   last_sock_errno = 0;
  590.   return (result);
  591. }
  592.  
  593.  
  594. /* __close()
  595.  
  596.    TODO: Maintain shared table of TCP/IP handles with reference
  597.    counts, for inherited socket handles.  Use a process-local table
  598.    for now. */
  599.  
  600. int tcpip_close (ULONG handle)
  601. {
  602.   if (!IS_VALID_FILE (handle))
  603.     return (EBADF);
  604.   if (GET_FILE (handle)->ref_count == 1)
  605.     {
  606.       if (tip_soclose (GET_FILE (handle)->x.socket.handle) != 0)
  607.         return (tcpip_errno ());
  608.     }
  609.   close_handle (handle);
  610.   last_sock_errno = 0;
  611.   return (0);
  612. }
  613.  
  614.  
  615. /* __dup() for a socket handle.  The target handle has already been
  616.    closed unless both HANDLE and TARGET are equal. */
  617.  
  618. int tcpip_dup (ULONG handle, ULONG target, int *errnop)
  619. {
  620.   int i;
  621.  
  622.   if (!IS_VALID_FILE (handle))
  623.     {
  624.       *errnop = EBADF;
  625.       return (-1);
  626.     }
  627.   if (target == (ULONG)(-1))
  628.     {
  629.       LOCK_FILES;
  630.       for (i = 0; i < handle_count; ++i)
  631.         if (!(handle_flags[i] & HF_OPEN))
  632.           {
  633.             handle_flags[i] = handle_flags[handle];
  634.             handle_file[i] = handle_file[handle];
  635.             GET_FILE(handle)->ref_count += 1;
  636.             UNLOCK_FILES;
  637.             *errnop = 0;
  638.             return (i);
  639.           }
  640.       UNLOCK_FILES;
  641.       *errnop = EMFILE;
  642.       return (-1);
  643.     }
  644.   else if (handle == target)
  645.     {
  646.       *errnop = 0;
  647.       return (target);
  648.     }
  649.   else if (target >= handle_count)
  650.     {
  651.       *errnop = EBADF;
  652.       return (-1);
  653.     }
  654.   else
  655.     {
  656.       handle_flags[target] = handle_flags[handle];
  657.       handle_file[target] = handle_file[handle];
  658.       GET_FILE(handle)->ref_count += 1;
  659.       *errnop = 0;
  660.       return (target);
  661.     }
  662. }
  663.  
  664.  
  665. /* __read() for a socket handle. */
  666.  
  667. int tcpip_read (ULONG handle, void *buf, ULONG len, int *errnop)
  668. {
  669.   int rc;
  670.  
  671.   if (len > 0x7fff) len = 0x7ffc;
  672.   rc = tip_recv (GET_FILE (handle)->x.socket.handle, buf, len, 0);
  673.   if (rc == -1)
  674.     {
  675.       *errnop = tcpip_errno ();
  676.       return (-1);
  677.     }
  678.   *errnop = 0;
  679.   last_sock_errno = 0;
  680.   return (rc);
  681. }
  682.  
  683.  
  684. /* __write() for a socket handle. */
  685.  
  686. int tcpip_write (ULONG handle, const void *buf, ULONG len, int *errnop)
  687. {
  688.   int rc, n, result, e;
  689.   const char *p;
  690.  
  691.   p = buf; result = 0;
  692.   while (len > 0)
  693.     {
  694.       n = (len > 0x7fff ? 0x7ffc : len);
  695.       rc = tip_send (GET_FILE (handle)->x.socket.handle, p, n, 0);
  696.       if (rc == -1)
  697.         {
  698.           e = tcpip_errno ();
  699.           if (e == EWOULDBLOCK && result != 0)
  700.             break;
  701.           *errnop = e;
  702.           return (-1);
  703.         }
  704.       result += rc;
  705.       if (rc != n) break;
  706.       p += rc; len -= rc;
  707.     }
  708.   *errnop = 0;
  709.   last_sock_errno = 0;
  710.   return (result);
  711. }
  712.  
  713.  
  714. /* __fstat() for a socket handle. */
  715.  
  716. int tcpip_fstat (ULONG handle, struct stat *dst, int *errnop)
  717. {
  718.   memset (dst, 0, sizeof (struct stat));
  719.   dst->st_mode = MAKEPERM (S_IREAD|S_IWRITE);
  720.   dst->st_mode |= S_IFSOCK;
  721.   dst->st_size = 0;
  722.   dst->st_dev = 0;
  723.   dst->st_uid = 0;              /* root */
  724.   dst->st_gid = 0;              /* root */
  725.   dst->st_ino = ino_number;
  726.   if (++ino_number == 0)
  727.    ino_number = 1;
  728.   dst->st_rdev = dst->st_dev;
  729.   dst->st_nlink = 1;
  730.   *errnop = 0;
  731.   return (0);
  732. }
  733.  
  734.  
  735. /* Call ioctl() of IBM TCP/IP for OS/2. */
  736.  
  737. static int map_ioctl (ULONG handle, ULONG request, ULONG arg, ULONG datalen,
  738.                       int *errnop)
  739. {
  740.   int rc;
  741.  
  742.   rc = tip_ioctl (GET_FILE (handle)->x.socket.handle,
  743.                   _TCPIP_FIONREAD, (void *)arg, datalen);
  744.   if (rc == -1)
  745.     {
  746.       *errnop = tcpip_errno ();
  747.       return (-1);
  748.     }
  749.   *errnop = 0;
  750.   return (rc);
  751. }
  752.  
  753.  
  754. /* __ioctl() for a socket handle. */
  755.  
  756. int tcpip_ioctl (ULONG handle, ULONG request, ULONG arg, int *errnop)
  757. {
  758.   int rc;
  759.  
  760.   if (!IS_VALID_FILE (handle))
  761.     {
  762.       *errnop = EBADF;
  763.       return (-1);
  764.     }
  765.  
  766.   switch (request)
  767.     {
  768.     case TCGETA:
  769.     case TCSETA:
  770.     case TCSETAF:
  771.     case TCSETAW:
  772.     case TCFLSH:
  773.     case TCSBRK:
  774.     case TCXONC:
  775.     case _TCGA:
  776.     case _TCSANOW:
  777.     case _TCSADRAIN:
  778.     case _TCSAFLUSH:
  779.  
  780.       /* These requests are not yet implemented. */
  781.  
  782.       *errnop = EINVAL;
  783.       return (-1);
  784.  
  785.     case FGETHTYPE:
  786.  
  787.       *(int *)arg = HT_SOCKET;
  788.       *errnop = 0;
  789.       return (0);
  790.  
  791.     case FIONREAD:
  792.  
  793.       return (map_ioctl (handle, _TCPIP_FIONREAD, arg, sizeof (int), errnop));
  794.  
  795.     case FIOASYNC:
  796.     case SIOCATMARK:
  797.  
  798.       return (map_ioctl (handle, request, arg, sizeof (int), errnop));
  799.  
  800.     case SIOCADDRT:
  801.     case SIOCDELRT:
  802.  
  803.       return (map_ioctl (handle, request, arg, sizeof (struct rtentry),
  804.                          errnop));
  805.  
  806.     case SIOCDARP:
  807.     case SIOCGARP:
  808.     case SIOCSARP:
  809.  
  810.       return (map_ioctl (handle, request, arg, sizeof (struct arpreq),
  811.                          errnop));
  812.  
  813.     case SIOCGIFADDR:
  814.     case SIOCGIFBRDADDR:
  815.     case SIOCGIFDSTADDR:
  816.     case SIOCGIFFLAGS:
  817.     case SIOCGIFMETRIC:
  818.     case SIOCGIFNETMASK:
  819.     case SIOCSIFADDR:
  820.     case SIOCSIFBRDADDR:
  821.     case SIOCSIFDSTADDR:
  822.     case SIOCSIFFLAGS:
  823.     case SIOCSIFMETRIC:
  824.     case SIOCSIFNETMASK:
  825.  
  826.       return (map_ioctl (handle, request, arg, sizeof (struct ifreq),
  827.                          errnop));
  828.  
  829.     case SIOCGIFCONF:
  830.  
  831.       return (map_ioctl (handle, request, arg, sizeof (struct ifconf),
  832.                          errnop));
  833.  
  834.     case FIONBIO:
  835.       rc = map_ioctl (handle, request, arg, sizeof (int), errnop);
  836.       if (rc == 0)
  837.         {
  838.           if (*(int *)arg)
  839.             handle_flags[handle] |= HF_NDELAY;
  840.           else
  841.             handle_flags[handle] &= ~HF_NDELAY;
  842.         }
  843.       return (rc);
  844.  
  845.     default:
  846.       *errnop = EINVAL;
  847.       return (-1);
  848.     }
  849. }
  850.  
  851.  
  852. /* __fcntl() for a socket handle.  This function is called for F_SETFL
  853.    only, and only if O_NDELAY was changed. */
  854.  
  855. int tcpip_fcntl (ULONG handle, ULONG request, ULONG arg, int *errnop)
  856. {
  857.   int on;
  858.  
  859.   on = arg & O_NDELAY;
  860.   return (tcpip_ioctl (handle, FIONBIO, (ULONG)&arg, errnop));
  861. }
  862.  
  863.  
  864. /* __getsockopt() */
  865.  
  866. int tcpip_getsockopt (ULONG handle, int level, int optname, void *optval,
  867.                       int *poptlen)
  868. {
  869.   int rc;
  870.  
  871.   if (!IS_SOCKET (handle) || !IS_VALID_FILE (handle))
  872.     return (ENOTSOCK);          /* TODO: last_sock_errno */
  873.  
  874.   rc = tip_getsockopt (GET_FILE (handle)->x.socket.handle, level, optname,
  875.                        optval, poptlen);
  876.   if (rc == -1)
  877.     return (tcpip_errno ());
  878.   last_sock_errno = 0;
  879.   return (0);
  880. }
  881.  
  882.  
  883. /* __setsockopt() */
  884.  
  885. int tcpip_setsockopt (ULONG handle, int level, int optname, const void *optval,
  886.                       int optlen)
  887. {
  888.   int rc;
  889.  
  890.   if (!IS_SOCKET (handle) || !IS_VALID_FILE (handle))
  891.     return (ENOTSOCK);          /* TODO: last_sock_errno */
  892.  
  893.   rc = tip_setsockopt (GET_FILE (handle)->x.socket.handle, level, optname,
  894.                        optval, optlen);
  895.   if (rc == -1)
  896.     return (tcpip_errno ());
  897.   last_sock_errno = 0;
  898.   return (0);
  899. }
  900.  
  901.  
  902. /* __getsockname() */
  903.  
  904. int tcpip_getsockname (ULONG handle, void *addr, int *paddrlen)
  905. {
  906.   int rc;
  907.  
  908.   if (!IS_SOCKET (handle) || !IS_VALID_FILE (handle))
  909.     return (ENOTSOCK);          /* TODO: last_sock_errno */
  910.  
  911.   rc = tip_getsockname (GET_FILE (handle)->x.socket.handle, addr, paddrlen);
  912.   if (rc == -1)
  913.     return (tcpip_errno ());
  914.   last_sock_errno = 0;
  915.   return (0);
  916. }
  917.  
  918.  
  919. /* __shutdown() */
  920.  
  921. int tcpip_shutdown (ULONG handle, int how)
  922. {
  923.   int rc;
  924.  
  925.   if (!IS_SOCKET (handle) || !IS_VALID_FILE (handle))
  926.     return (ENOTSOCK);          /* TODO: last_sock_errno */
  927.  
  928.   rc = tip_shutdown (GET_FILE (handle)->x.socket.handle, how);
  929.   if (rc != 0)
  930.     return (tcpip_errno ());
  931.   last_sock_errno = 0;
  932.   return (0);
  933. }
  934.  
  935.  
  936. /* __getpeername() */
  937.  
  938. int tcpip_getpeername (ULONG handle, void *addr, int *paddrlen)
  939. {
  940.   int rc;
  941.  
  942.   if (!IS_SOCKET (handle) || !IS_VALID_FILE (handle))
  943.     return (ENOTSOCK);          /* TODO: last_sock_errno */
  944.  
  945.   rc = tip_getpeername (GET_FILE (handle)->x.socket.handle, addr, paddrlen);
  946.   if (rc == -1)
  947.     return (tcpip_errno ());
  948.   last_sock_errno = 0;
  949.   return (0);
  950. }
  951.  
  952.  
  953. /* __gethostbyname() */
  954.  
  955. int tcpip_gethostbyname (const char *name, void **dst)
  956. {
  957.   void *p;
  958.  
  959.   if (!tcpip_init ())
  960.     return (NO_RECOVERY);
  961.  
  962.   p = tip_gethostbyname (name);
  963.   *dst = p;
  964.   if (p == NULL)
  965.     {
  966.       /* h_errno seems to be always zero.  Bug? */
  967.  
  968.       if (*tip_h_errno == 0)
  969.         return (NO_RECOVERY);
  970.       else
  971.         return (*tip_h_errno);
  972.     }
  973.   else
  974.     return (0);
  975. }
  976.  
  977.  
  978. /* __gethostbyaddr() */
  979.  
  980. int tcpip_gethostbyaddr (const char *addr, int len, int type, void **dst)
  981. {
  982.   void *p;
  983.  
  984.   if (!tcpip_init ())
  985.     return (NO_RECOVERY);
  986.  
  987.   p = tip_gethostbyaddr (addr, len, type);
  988.   *dst = p;
  989.   if (p == NULL)
  990.     {
  991.       /* h_errno seems to be always zero.  Bug? */
  992.  
  993.       if (*tip_h_errno == 0)
  994.         return (NO_RECOVERY);
  995.       else
  996.         return (*tip_h_errno);
  997.     }
  998.   else
  999.     return (0);
  1000. }
  1001.  
  1002.  
  1003. /* __getservbyname() */
  1004.  
  1005. int tcpip_getservbyname (const char *name, const char *proto, void **dst)
  1006. {
  1007.   void *p;
  1008.  
  1009.   if (!tcpip_init ())
  1010.     return (-1);
  1011.  
  1012.   p = tip_getservbyname (name, proto);
  1013.   *dst = p;
  1014.   return (p != NULL ? 0 : -1);
  1015. }
  1016.  
  1017.  
  1018. /* __getservbyport() */
  1019.  
  1020. int tcpip_getservbyport (int port, const char *proto, void **dst)
  1021. {
  1022.   void *p;
  1023.  
  1024.   if (!tcpip_init ())
  1025.     return (-1);
  1026.  
  1027.   p = tip_getservbyport (port, proto);
  1028.   *dst = p;
  1029.   return (p != NULL ? 0 : -1);
  1030. }
  1031.  
  1032.  
  1033. /* __gethostid() */
  1034.  
  1035. int tcpip_gethostid (int *dst)
  1036. {
  1037.   if (!tcpip_init ())
  1038.     return (ENETDOWN);
  1039.  
  1040.   *dst = tip_gethostid ();
  1041.   last_sock_errno = 0;
  1042.   return (0);
  1043. }
  1044.  
  1045.  
  1046. /* __gethostname() */
  1047.  
  1048. int tcpip_gethostname (char *name, int len)
  1049. {
  1050.   int rc;
  1051.  
  1052.   /* TODO: Get hostname from environment variable if the net is
  1053.      down. */
  1054.  
  1055.   if (!tcpip_init ())
  1056.     return (ENETDOWN);
  1057.  
  1058.   /* If HOSTNAME is not set, IBM's gethostname() simply leaves the
  1059.      buffer alone! */
  1060.  
  1061.   *name = 0;
  1062.  
  1063.   rc = tip_gethostname (name, len);
  1064.   if (rc != 0)
  1065.     return (tcpip_errno ());
  1066.   last_sock_errno = 0;
  1067.   return (0);
  1068. }
  1069.  
  1070.  
  1071. /* __getprotobyname() */
  1072.  
  1073. int tcpip_getprotobyname (const char *name, void **dst)
  1074. {
  1075.   void *p;
  1076.  
  1077.   if (!tcpip_init ())
  1078.     return (-1);
  1079.  
  1080.   p = tip_getprotobyname (name);
  1081.   *dst = p;
  1082.   return (p != NULL ? 0 : -1);
  1083. }
  1084.  
  1085.  
  1086. /* __getprotobynumber() */
  1087.  
  1088. int tcpip_getprotobynumber (int proto, void **dst)
  1089. {
  1090.   void *p;
  1091.  
  1092.   if (!tcpip_init ())
  1093.     return (-1);
  1094.  
  1095.   p = tip_getprotobynumber (proto);
  1096.   *dst = p;
  1097.   return (p != NULL ? 0 : -1);
  1098. }
  1099.  
  1100.  
  1101. /* __getnetbyname() */
  1102.  
  1103. int tcpip_getnetbyname (const char *name, void **dst)
  1104. {
  1105.   void *p;
  1106.  
  1107.   if (!tcpip_init ())
  1108.     return (-1);
  1109.  
  1110.   p = tip_getnetbyname (name);
  1111.   *dst = p;
  1112.   return (p != NULL ? 0 : -1);
  1113. }
  1114.  
  1115.  
  1116. /* __getnetbyaddr() */
  1117.  
  1118. int tcpip_getnetbyaddr (long net, void **dst)
  1119. {
  1120.   void *p;
  1121.  
  1122.   if (!tcpip_init ())
  1123.     return (-1);
  1124.  
  1125.   p = tip_getnetbyaddr (net);
  1126.   *dst = p;
  1127.   return (p != NULL ? 0 : -1);
  1128. }
  1129.  
  1130.  
  1131. /* Poll socket handles for __select().  Update the bitstrings if a
  1132.    handle is ready. */
  1133.  
  1134. int tcpip_select_poll (struct select_data *d, int *errnop)
  1135. {
  1136.   int i, j, n;
  1137.   int sockets[SELECT_MAX_SOCKETS];
  1138.  
  1139.   memcpy (sockets, d->sockets, d->socket_count * sizeof (sockets[0]));
  1140.   n = tip_select (sockets, d->socket_nread, d->socket_nwrite,
  1141.                   d->socket_nexcept, 0);
  1142.   if (n < 0)
  1143.     {
  1144.       *errnop = tcpip_errno ();
  1145.       return (-1);
  1146.     }
  1147.   if (n == 0)
  1148.     return (0);
  1149.   j = 0; n = 0;
  1150.   for (i = 0; i < d->socket_nread; ++i, ++j)
  1151.     if (sockets[j] != -1)
  1152.       {
  1153.         FD_SET (d->socketh[i], &d->rbits);
  1154.         ++n;
  1155.       }
  1156.   for (i = 0; i < d->socket_nwrite; ++i, ++j)
  1157.     if (sockets[j] != -1)
  1158.       {
  1159.         FD_SET (d->socketh[i], &d->wbits);
  1160.         ++n;
  1161.       }
  1162.   for (i = 0; i < d->socket_nexcept; ++i, ++j)
  1163.     if (sockets[j] != -1)
  1164.       {
  1165.         FD_SET (d->socketh[i], &d->ebits);
  1166.         ++n;
  1167.       }
  1168.   *errnop = 0;
  1169.   d->ready_count += n;
  1170.   return (n);
  1171. }
  1172.  
  1173.  
  1174. /* Notify select_wait() of termination of tcpip_select_thread(). */
  1175.  
  1176. static ULONG select_exception (EXCEPTIONREPORTRECORD *report,
  1177.                                EXCEPTIONREGISTRATIONRECORD *registration,
  1178.                                CONTEXTRECORD *context,
  1179.                                void *dummy)
  1180. {
  1181.   if (report->fHandlerFlags & (EH_EXIT_UNWIND|EH_UNWINDING))
  1182.     return (XCPT_CONTINUE_SEARCH);
  1183.   switch (report->ExceptionNum)
  1184.     {
  1185.     case XCPT_ASYNC_PROCESS_TERMINATE: /* This is the correct one */
  1186.     case XCPT_PROCESS_TERMINATE:       /* OS/2 bug */
  1187.       DosPostEventSem (socket_done_sem);
  1188.       break;
  1189.     }
  1190.   return (XCPT_CONTINUE_SEARCH);
  1191. }
  1192.  
  1193.  
  1194. #define POLL_SLEEP 64
  1195.  
  1196. /* Wait until a socket handle becomes ready, for __select().  This
  1197.    function is run in a separate thread.  Post `socket_sem' if and
  1198.    when a socket is ready or the time-out expires.  Post
  1199.    `socket_done_sem' when the thread terminates. */
  1200.  
  1201. void tcpip_select_thread (ULONG arg)
  1202. {
  1203.   EXCEPTIONREGISTRATIONRECORD registration;
  1204.   const struct select_data *d;
  1205.   int n;
  1206.   int sockets[SELECT_MAX_SOCKETS];
  1207.   long timeout;
  1208.  
  1209.   registration.prev_structure = NULL;
  1210.   registration.ExceptionHandler = select_exception;
  1211.   DosSetExceptionHandler (®istration);
  1212.  
  1213.   /* Exception handler has been installed -- killing this thread is
  1214.      now allowed. */
  1215.   DosPostEventSem (socket_start_sem);
  1216.  
  1217.   d = (const struct select_data *)arg;
  1218.   memcpy (sockets, d->sockets, d->socket_count * sizeof (sockets[0]));
  1219.   timeout = (d->timeout == SEM_INDEFINITE_WAIT ? -1 : d->timeout);
  1220.  
  1221.   if (dont_doskillthread)
  1222.     while (!select_socket_done)
  1223.       {
  1224.         n = tip_select (sockets, d->socket_nread, d->socket_nwrite,
  1225.                         d->socket_nexcept, POLL_SLEEP);
  1226.         if (n != 0)
  1227.           break;
  1228.       }
  1229.   else
  1230.     {
  1231.       n = tip_select (sockets, d->socket_nread, d->socket_nwrite,
  1232.                       d->socket_nexcept, d->timeout);
  1233.     }
  1234.  
  1235.   DosPostEventSem (socket_done_sem);
  1236.   DosUnsetExceptionHandler (®istration);
  1237.   DosPostEventSem (socket_sem);
  1238.   DosExit (EXIT_THREAD, 0);
  1239. }
  1240.