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 >
Wrap
C/C++ Source or Header
|
1994-12-21
|
32KB
|
1,240 lines
/* tcpip.c -- TCP/IP
Copyright (c) 1994 by Eberhard Mattes
This file is part of emx.
emx is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
emx is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with emx; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* TODO:
- inheritance of socket handles, maintain global reference count
- inheritance for fork()
- add IBM TCP/IP for OS/2 layer (sock_errno() etc.) */
#include <sys/emx.h>
#define INCL_DOSDEVIOCTL
#define INCL_DOSEXCEPTIONS
#define INCL_DOSMODULEMGR
#define INCL_DOSSEMAPHORES
#include <os2emx.h>
#include <sys/errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/so_ioctl.h>
#include <net/route.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <netdb.h>
#include "emxdll.h"
#include "files.h"
#include "tcpip.h"
#include "select.h"
#include "clib.h"
/* Error codes of IBM TCP/IP for OS/2 start at this number. */
#define SOCK_ERRNO_BASE 10000
/* This variable is zero while tcpip_init() has not been called. A
positive value means that initialization of TCP/IP was successful,
a negative value means that initialization of TCP/IP failed. */
static int tcpip_initialized;
/* This variable holds the value returned by the most recent call to
sock_errno(). In the future, it will be used for providing a
sock_errno() system call. */
static int last_sock_errno;
/* Module handles of the two IBM TCP/IP for OS/2 DLLs. */
static HMODULE hmod_so32dll;
static HMODULE hmod_tcp32dll;
struct sockaddr;
/* Pointers to entrypoints of the IBM TCP/IP for OS/2 DLLs. */
static int (*tip_accept)(int, struct sockaddr *, int *);
static int (*tip_bind)(int, struct sockaddr *, int);
static int (*tip_connect)(int, struct sockaddr *, int);
static void * (*tip_gethostbyaddr) (const char *, int, int);
static void * (*tip_gethostbyname) (const char *);
static int (*tip_gethostid) (void);
static int (*tip_gethostname) (char *, int len);
static void * (*tip_getnetbyaddr) (long);
static void * (*tip_getnetbyname) (const char *);
static int (*tip_getpeername) (int, void *, int *);
static void * (*tip_getprotobyname) (const char *);
static void * (*tip_getprotobynumber) (int);
static void * (*tip_getservbyname) (const char *, const char *);
static void * (*tip_getservbyport) (int, const char *);
static int (*tip_getsockname) (int, void *, int *);
static int (*tip_getsockopt) (int, int, int, void *, int *);
static int (*tip_ioctl)(int, int, void *, int);
static int (*tip_listen)(int, int);
static int (*tip_recv)(int, void *, int, int);
static int (*tip_recvfrom)(int, void *, int, int, struct sockaddr *, int *);
static int (*tip_select)(int *, int, int, int, long);
static int (*tip_send)(int, const void *, int, int);
static int (*tip_sendto)(int, const void *, int, int, const struct sockaddr *,
int);
static int (*tip_setsockopt) (int, int, int, const void *, int);
static int (*tip_shutdown) (int, int);
static int (*tip_socket) (int domain, int type, int protocol);
static int (*tip_sock_errno)(void);
static int (*tip_sock_init)(void);
static int (*tip_soclose)(int handle);
static int *tip_h_errno;
/* These macros are used for getting the addresses of DLL entrypoints. */
#define LOAD(hmod,name,var) (DosQueryProcAddr (hmod, 0, name, (PPFN)var) != 0)
#define LOAD_SO(name,var) LOAD (hmod_so32dll, name, var)
#define LOAD_TCP(name,var) LOAD (hmod_tcp32dll, name, var)
/* Initialize TCP/IP. Return FALSE on failure, return TRUE on
success. This function must be called before using any of the
above `tip_*' pointers. Functions which check HF_SOCKET don't have
to call tcpip_init() as the HF_SOCKET bit can only be set by a
function which calls tcpip_init(). */
static int tcpip_init (void)
{
char obj[9];
/* If tcpip_init() has already been called, use the result of the
first call. */
if (tcpip_initialized < 0)
return (FALSE);
if (tcpip_initialized > 0)
return (TRUE);
/* Indicate failure unless everything works well. */
tcpip_initialized = -1;
/* Load the two IBM TCP/IP for SO/2 DLLs. */
if (DosLoadModule (obj, sizeof (obj), "SO32DLL", &hmod_so32dll) != 0
||DosLoadModule (obj, sizeof (obj), "TCP32DLL", &hmod_tcp32dll) != 0)
return (FALSE);
/* Initialize the pointers to the DLL entrypoints and call
sock_init(). */
if (LOAD_SO ("SOCK_INIT", &tip_sock_init)
|| LOAD_SO ("SOCK_ERRNO", &tip_sock_errno)
|| LOAD_SO ("ACCEPT", &tip_accept)
|| LOAD_SO ("BIND", &tip_bind)
|| LOAD_SO ("CONNECT", &tip_connect)
|| LOAD_SO ("GETHOSTID", &tip_gethostid)
|| LOAD_SO ("GETPEERNAME", &tip_getpeername)
|| LOAD_SO ("GETSOCKNAME", &tip_getsockname)
|| LOAD_SO ("GETSOCKOPT", &tip_getsockopt)
|| LOAD_SO ("IOCTL", &tip_ioctl)
|| LOAD_SO ("LISTEN", &tip_listen)
|| LOAD_SO ("RECV", &tip_recv)
|| LOAD_SO ("RECVFROM", &tip_recvfrom)
|| LOAD_SO ("SELECT", &tip_select)
|| LOAD_SO ("SEND", &tip_send)
|| LOAD_SO ("SENDTO", &tip_sendto)
|| LOAD_SO ("SETSOCKOPT", &tip_setsockopt)
|| LOAD_SO ("SHUTDOWN", &tip_shutdown)
|| LOAD_SO ("SOCKET", &tip_socket)
|| LOAD_SO ("SOCLOSE", &tip_soclose)
|| LOAD_TCP ("GETHOSTBYADDR", &tip_gethostbyaddr)
|| LOAD_TCP ("GETHOSTBYNAME", &tip_gethostbyname)
|| LOAD_TCP ("GETHOSTNAME", &tip_gethostname)
|| LOAD_TCP ("GETNETBYADDR", &tip_getnetbyaddr)
|| LOAD_TCP ("GETNETBYNAME", &tip_getnetbyname)
|| LOAD_TCP ("GETPROTOBYNAME", &tip_getprotobyname)
|| LOAD_TCP ("GETPROTOBYNUMBER", &tip_getprotobynumber)
|| LOAD_TCP ("GETSERVBYNAME", &tip_getservbyname)
|| LOAD_TCP ("GETSERVBYPORT", &tip_getservbyport)
|| LOAD_TCP ("H_ERRNO", &tip_h_errno)
|| tip_sock_init () != 0)
{
DosFreeModule (hmod_so32dll);
DosFreeModule (hmod_tcp32dll);
return (FALSE);
}
/* Sucess! */
tcpip_initialized = 1;
return (TRUE);
}
/* Use UNDEF for error codes which are supposed to not being
returned by IBM TCP/IP for OS/2. */
#define UNDEF EINVAL
/* This table maps error codes of IBM TCP/IP for OS/2 (offset by
SOCK_ERRNO_BASE) to emx errno numbers. */
static unsigned char const sock_errno_tab[] =
{
UNDEF, /* +0 */
EPERM, /* +1 */
UNDEF, /* +2 */
ESRCH, /* +3 */
EINTR, /* +4 */
UNDEF, /* +5 */
ENXIO, /* +6 */
UNDEF, /* +7 */
UNDEF, /* +8 */
EBADF, /* +9 */
UNDEF, /* +10 */
UNDEF, /* +11 */
UNDEF, /* +12 */
EACCES, /* +13 */
EFAULT, /* +14 */
UNDEF, /* +15 */
UNDEF, /* +16 */
UNDEF, /* +17 */
UNDEF, /* +18 */
UNDEF, /* +19 */
UNDEF, /* +20 */
UNDEF, /* +21 */
EINVAL, /* +22 */
UNDEF, /* +23 */
EMFILE, /* +24 */
UNDEF, /* +25 */
UNDEF, /* +26 */
UNDEF, /* +27 */
UNDEF, /* +28 */
UNDEF, /* +29 */
UNDEF, /* +30 */
UNDEF, /* +31 */
EPIPE, /* +32 */
UNDEF, /* +33 */
UNDEF, /* +34 */
EWOULDBLOCK, /* +35 */
EINPROGRESS, /* +36 */
EALREADY, /* +37 */
ENOTSOCK, /* +38 */
EDESTADDRREQ, /* +39 */
EMSGSIZE, /* +40 */
EPROTOTYPE, /* +41 */
ENOPROTOOPT, /* +42 */
EPROTONOSUPPORT, /* +43 */
ESOCKTNOSUPPORT, /* +44 */
EOPNOTSUPP, /* +45 */
EPFNOSUPPORT, /* +46 */
EAFNOSUPPORT, /* +47 */
EADDRINUSE, /* +48 */
EADDRNOTAVAIL, /* +49 */
ENETDOWN, /* +50 */
ENETUNREACH, /* +51 */
ENETRESET, /* +52 */
ECONNABORTED, /* +53 */
ECONNRESET, /* +54 */
ENOBUFS, /* +55 */
EISCONN, /* +56 */
ENOTCONN, /* +57 */
ESHUTDOWN, /* +58 */
ETOOMANYREFS, /* +59 */
ETIMEDOUT, /* +60 */
ECONNREFUSED, /* +61 */
ELOOP, /* +62 */
ENAMETOOLONG, /* +63 */
EHOSTDOWN, /* +64 */
EHOSTUNREACH, /* +65 */
ENOTEMPTY, /* +66 */
UNDEF, /* +67 */
UNDEF, /* +68 */
UNDEF, /* +69 */
UNDEF, /* +70 */
UNDEF, /* +71 */
UNDEF, /* +72 */
UNDEF, /* +73 */
UNDEF, /* +74 */
UNDEF, /* +75 */
UNDEF, /* +76 */
UNDEF, /* +77 */
UNDEF, /* +78 */
UNDEF, /* +79 */
UNDEF, /* +80 */
UNDEF, /* +81 */
UNDEF, /* +82 */
UNDEF, /* +83 */
UNDEF, /* +84 */
UNDEF, /* +85 */
UNDEF, /* +86 */
UNDEF, /* +87 */
UNDEF, /* +88 */
UNDEF, /* +89 */
UNDEF, /* +90 */
UNDEF, /* +91 */
UNDEF, /* +92 */
UNDEF, /* +93 */
UNDEF, /* +94 */
UNDEF, /* +95 */
UNDEF, /* +96 */
UNDEF, /* +97 */
UNDEF, /* +98 */
UNDEF, /* +99 */
EIO /* +100: SOCEOS2ERR */
};
/* Obtain, translate, and return the error code of the most recent
TCP/IP call. */
static int tcpip_errno (void)
{
int e;
e = tip_sock_errno ();
last_sock_errno = e;
if (e < SOCK_ERRNO_BASE || e >= SOCK_ERRNO_BASE + sizeof (sock_errno_tab))
return (EINVAL);
return (sock_errno_tab[e - SOCK_ERRNO_BASE]);
}
/* Fake a low-level file I/O handle for a socket. Instead of (or in
addition to) relocating OS/2 file handles, we might open the "NUL"
device to fill the slot used for the faked handle. */
static int tcpip_new_handle (int s, int *errnop)
{
int i;
/* We might want to prefer handles with high numbers to minimize
relocation of file handles; however, we don't know the value of
the application's `_nfiles' variable. */
LOCK_FILES;
for (i = 0; i < handle_count; ++i)
if (!(handle_flags[i] & HF_OPEN))
{
alloc_file_description (i);
if (!IS_VALID_FILE (i))
break;
set_handle_flags (i, HF_OPEN | HF_SOCKET);
GET_FILE (i)->x.socket.handle = s;
UNLOCK_FILES;
*errnop = 0;
return (i);
}
UNLOCK_FILES;
tip_soclose (s);
*errnop = EMFILE;
return (-1);
}
/* __socket() */
int tcpip_socket (int domain, int type, int protocol, int *errnop)
{
int s;
if (!tcpip_init ())
{
*errnop = ENETDOWN; /* TODO: last_sock_errno */
return (-1);
}
s = tip_socket (domain, type, protocol);
if (s == -1)
{
*errnop = tcpip_errno ();
return (-1);
}
return (tcpip_new_handle (s, errnop));
}
/* __getsockhandle() */
int tcpip_getsockhandle (ULONG handle, int *errnop)
{
if (!IS_SOCKET (handle) || !IS_VALID_FILE (handle))
{
*errnop = EBADF;
return (-1);
}
*errnop = 0;
return (GET_FILE (handle)->x.socket.handle);
}
/* __accept() */
int tcpip_accept (ULONG handle, void *addr, int *paddrlen, int *errnop)
{
int s;
if (!IS_SOCKET (handle) || !IS_VALID_FILE (handle))
{
*errnop = EBADF; /* TODO: last_sock_errno */
return (-1);
}
s = tip_accept (GET_FILE (handle)->x.socket.handle, addr, paddrlen);
if (s == -1)
{
*errnop = tcpip_errno ();
return (-1);
}
return (tcpip_new_handle (s, errnop));
}
/* __bind() */
int tcpip_bind (ULONG handle, void *addr, int addrlen)
{
int rc;
if (!IS_SOCKET (handle) || !IS_VALID_FILE (handle))
return (EBADF); /* TODO: last_sock_errno */
rc = tip_bind (GET_FILE (handle)->x.socket.handle, addr, addrlen);
if (rc != 0)
return (tcpip_errno ());
last_sock_errno = 0;
return (0);
}
/* __connect() */
int tcpip_connect (ULONG handle, void *addr, int addrlen)
{
int rc;
if (!IS_SOCKET (handle) || !IS_VALID_FILE (handle))
return (EBADF); /* TODO: last_sock_errno */
rc = tip_connect (GET_FILE (handle)->x.socket.handle, addr, addrlen);
if (rc != 0)
return (tcpip_errno ());
last_sock_errno = 0;
return (0);
}
/* __listen() */
int tcpip_listen (ULONG handle, int backlog)
{
int rc;
if (!IS_SOCKET (handle) || !IS_VALID_FILE (handle))
return (EBADF); /* TODO: last_sock_errno */
rc = tip_listen (GET_FILE (handle)->x.socket.handle, backlog);
if (rc != 0)
return (tcpip_errno ());
last_sock_errno = 0;
return (0);
}
/* __recv() */
int tcpip_recv (ULONG handle, void *buf, int len, unsigned flags, int *errnop)
{
int rc;
if (!IS_SOCKET (handle) || !IS_VALID_FILE (handle))
{
*errnop = EBADF; /* TODO: last_sock_errno */
return (-1);
}
if (len > 0x7fff) len = 0x7ffc;
rc = tip_recv (GET_FILE (handle)->x.socket.handle, buf, len, flags);
if (rc == -1)
{
*errnop = tcpip_errno ();
return (-1);
}
*errnop = 0;
last_sock_errno = 0;
return (rc);
}
/* __recvfrom() */
int tcpip_recvfrom (const struct _recvfrom *args, int *errnop)
{
ULONG handle;
int rc, len;
handle = args->handle;
if (!IS_SOCKET (handle) || !IS_VALID_FILE (handle))
{
*errnop = EBADF; /* TODO: last_sock_errno */
return (-1);
}
len = args->len;
if (len > 0x7fff) len = 0x7ffc;
rc = tip_recvfrom (GET_FILE (handle)->x.socket.handle, args->buf, len,
args->flags, args->from, args->pfromlen);
if (rc == -1)
{
*errnop = tcpip_errno ();
return (-1);
}
*errnop = 0;
last_sock_errno = 0;
return (rc);
}
/* __send() */
int tcpip_send (ULONG handle, const void *buf, int len, unsigned flags,
int *errnop)
{
int rc, n, result, e;
const char *p;
if (!IS_SOCKET (handle) || !IS_VALID_FILE (handle))
{
*errnop = EBADF; /* TODO: last_sock_errno */
return (-1);
}
/* TODO: Return EMSGSIZE if appropriate. */
p = buf; result = 0;
while (len > 0)
{
n = (len > 0x7fff ? 0x7ffc : len);
rc = tip_send (GET_FILE (handle)->x.socket.handle, p, n, flags);
if (rc == -1)
{
e = tcpip_errno ();
if (e == EWOULDBLOCK && result != 0)
break;
*errnop = e;
return (-1);
}
result += rc;
if (rc != n) break;
p += rc; len -= rc;
}
*errnop = 0;
last_sock_errno = 0;
return (result);
}
/* __sendto() */
int tcpip_sendto (const struct _sendto *args, int *errnop)
{
ULONG handle;
int rc, len, n, result, e;
const char *p;
handle = args->handle;
if (!IS_SOCKET (handle) || !IS_VALID_FILE (handle))
{
*errnop = EBADF; /* TODO: last_sock_errno */
return (-1);
}
/* TODO: Return EMSGSIZE if appropriate. */
p = args->buf; result = 0; len = args->len;
while (len > 0)
{
n = (len > 0x7fff ? 0x7ffc : len);
rc = tip_sendto (GET_FILE (handle)->x.socket.handle, p, n, args->flags,
args->to, args->tolen);
if (rc == -1)
{
e = tcpip_errno ();
if (e == EWOULDBLOCK && result != 0)
break;
*errnop = e;
return (-1);
}
result += rc;
if (rc != n) break;
p += rc; len -= rc;
}
*errnop = 0;
last_sock_errno = 0;
return (result);
}
/* __close()
TODO: Maintain shared table of TCP/IP handles with reference
counts, for inherited socket handles. Use a process-local table
for now. */
int tcpip_close (ULONG handle)
{
if (!IS_VALID_FILE (handle))
return (EBADF);
if (GET_FILE (handle)->ref_count == 1)
{
if (tip_soclose (GET_FILE (handle)->x.socket.handle) != 0)
return (tcpip_errno ());
}
close_handle (handle);
last_sock_errno = 0;
return (0);
}
/* __dup() for a socket handle. The target handle has already been
closed unless both HANDLE and TARGET are equal. */
int tcpip_dup (ULONG handle, ULONG target, int *errnop)
{
int i;
if (!IS_VALID_FILE (handle))
{
*errnop = EBADF;
return (-1);
}
if (target == (ULONG)(-1))
{
LOCK_FILES;
for (i = 0; i < handle_count; ++i)
if (!(handle_flags[i] & HF_OPEN))
{
handle_flags[i] = handle_flags[handle];
handle_file[i] = handle_file[handle];
GET_FILE(handle)->ref_count += 1;
UNLOCK_FILES;
*errnop = 0;
return (i);
}
UNLOCK_FILES;
*errnop = EMFILE;
return (-1);
}
else if (handle == target)
{
*errnop = 0;
return (target);
}
else if (target >= handle_count)
{
*errnop = EBADF;
return (-1);
}
else
{
handle_flags[target] = handle_flags[handle];
handle_file[target] = handle_file[handle];
GET_FILE(handle)->ref_count += 1;
*errnop = 0;
return (target);
}
}
/* __read() for a socket handle. */
int tcpip_read (ULONG handle, void *buf, ULONG len, int *errnop)
{
int rc;
if (len > 0x7fff) len = 0x7ffc;
rc = tip_recv (GET_FILE (handle)->x.socket.handle, buf, len, 0);
if (rc == -1)
{
*errnop = tcpip_errno ();
return (-1);
}
*errnop = 0;
last_sock_errno = 0;
return (rc);
}
/* __write() for a socket handle. */
int tcpip_write (ULONG handle, const void *buf, ULONG len, int *errnop)
{
int rc, n, result, e;
const char *p;
p = buf; result = 0;
while (len > 0)
{
n = (len > 0x7fff ? 0x7ffc : len);
rc = tip_send (GET_FILE (handle)->x.socket.handle, p, n, 0);
if (rc == -1)
{
e = tcpip_errno ();
if (e == EWOULDBLOCK && result != 0)
break;
*errnop = e;
return (-1);
}
result += rc;
if (rc != n) break;
p += rc; len -= rc;
}
*errnop = 0;
last_sock_errno = 0;
return (result);
}
/* __fstat() for a socket handle. */
int tcpip_fstat (ULONG handle, struct stat *dst, int *errnop)
{
memset (dst, 0, sizeof (struct stat));
dst->st_mode = MAKEPERM (S_IREAD|S_IWRITE);
dst->st_mode |= S_IFSOCK;
dst->st_size = 0;
dst->st_dev = 0;
dst->st_uid = 0; /* root */
dst->st_gid = 0; /* root */
dst->st_ino = ino_number;
if (++ino_number == 0)
ino_number = 1;
dst->st_rdev = dst->st_dev;
dst->st_nlink = 1;
*errnop = 0;
return (0);
}
/* Call ioctl() of IBM TCP/IP for OS/2. */
static int map_ioctl (ULONG handle, ULONG request, ULONG arg, ULONG datalen,
int *errnop)
{
int rc;
rc = tip_ioctl (GET_FILE (handle)->x.socket.handle,
_TCPIP_FIONREAD, (void *)arg, datalen);
if (rc == -1)
{
*errnop = tcpip_errno ();
return (-1);
}
*errnop = 0;
return (rc);
}
/* __ioctl() for a socket handle. */
int tcpip_ioctl (ULONG handle, ULONG request, ULONG arg, int *errnop)
{
int rc;
if (!IS_VALID_FILE (handle))
{
*errnop = EBADF;
return (-1);
}
switch (request)
{
case TCGETA:
case TCSETA:
case TCSETAF:
case TCSETAW:
case TCFLSH:
case TCSBRK:
case TCXONC:
case _TCGA:
case _TCSANOW:
case _TCSADRAIN:
case _TCSAFLUSH:
/* These requests are not yet implemented. */
*errnop = EINVAL;
return (-1);
case FGETHTYPE:
*(int *)arg = HT_SOCKET;
*errnop = 0;
return (0);
case FIONREAD:
return (map_ioctl (handle, _TCPIP_FIONREAD, arg, sizeof (int), errnop));
case FIOASYNC:
case SIOCATMARK:
return (map_ioctl (handle, request, arg, sizeof (int), errnop));
case SIOCADDRT:
case SIOCDELRT:
return (map_ioctl (handle, request, arg, sizeof (struct rtentry),
errnop));
case SIOCDARP:
case SIOCGARP:
case SIOCSARP:
return (map_ioctl (handle, request, arg, sizeof (struct arpreq),
errnop));
case SIOCGIFADDR:
case SIOCGIFBRDADDR:
case SIOCGIFDSTADDR:
case SIOCGIFFLAGS:
case SIOCGIFMETRIC:
case SIOCGIFNETMASK:
case SIOCSIFADDR:
case SIOCSIFBRDADDR:
case SIOCSIFDSTADDR:
case SIOCSIFFLAGS:
case SIOCSIFMETRIC:
case SIOCSIFNETMASK:
return (map_ioctl (handle, request, arg, sizeof (struct ifreq),
errnop));
case SIOCGIFCONF:
return (map_ioctl (handle, request, arg, sizeof (struct ifconf),
errnop));
case FIONBIO:
rc = map_ioctl (handle, request, arg, sizeof (int), errnop);
if (rc == 0)
{
if (*(int *)arg)
handle_flags[handle] |= HF_NDELAY;
else
handle_flags[handle] &= ~HF_NDELAY;
}
return (rc);
default:
*errnop = EINVAL;
return (-1);
}
}
/* __fcntl() for a socket handle. This function is called for F_SETFL
only, and only if O_NDELAY was changed. */
int tcpip_fcntl (ULONG handle, ULONG request, ULONG arg, int *errnop)
{
int on;
on = arg & O_NDELAY;
return (tcpip_ioctl (handle, FIONBIO, (ULONG)&arg, errnop));
}
/* __getsockopt() */
int tcpip_getsockopt (ULONG handle, int level, int optname, void *optval,
int *poptlen)
{
int rc;
if (!IS_SOCKET (handle) || !IS_VALID_FILE (handle))
return (ENOTSOCK); /* TODO: last_sock_errno */
rc = tip_getsockopt (GET_FILE (handle)->x.socket.handle, level, optname,
optval, poptlen);
if (rc == -1)
return (tcpip_errno ());
last_sock_errno = 0;
return (0);
}
/* __setsockopt() */
int tcpip_setsockopt (ULONG handle, int level, int optname, const void *optval,
int optlen)
{
int rc;
if (!IS_SOCKET (handle) || !IS_VALID_FILE (handle))
return (ENOTSOCK); /* TODO: last_sock_errno */
rc = tip_setsockopt (GET_FILE (handle)->x.socket.handle, level, optname,
optval, optlen);
if (rc == -1)
return (tcpip_errno ());
last_sock_errno = 0;
return (0);
}
/* __getsockname() */
int tcpip_getsockname (ULONG handle, void *addr, int *paddrlen)
{
int rc;
if (!IS_SOCKET (handle) || !IS_VALID_FILE (handle))
return (ENOTSOCK); /* TODO: last_sock_errno */
rc = tip_getsockname (GET_FILE (handle)->x.socket.handle, addr, paddrlen);
if (rc == -1)
return (tcpip_errno ());
last_sock_errno = 0;
return (0);
}
/* __shutdown() */
int tcpip_shutdown (ULONG handle, int how)
{
int rc;
if (!IS_SOCKET (handle) || !IS_VALID_FILE (handle))
return (ENOTSOCK); /* TODO: last_sock_errno */
rc = tip_shutdown (GET_FILE (handle)->x.socket.handle, how);
if (rc != 0)
return (tcpip_errno ());
last_sock_errno = 0;
return (0);
}
/* __getpeername() */
int tcpip_getpeername (ULONG handle, void *addr, int *paddrlen)
{
int rc;
if (!IS_SOCKET (handle) || !IS_VALID_FILE (handle))
return (ENOTSOCK); /* TODO: last_sock_errno */
rc = tip_getpeername (GET_FILE (handle)->x.socket.handle, addr, paddrlen);
if (rc == -1)
return (tcpip_errno ());
last_sock_errno = 0;
return (0);
}
/* __gethostbyname() */
int tcpip_gethostbyname (const char *name, void **dst)
{
void *p;
if (!tcpip_init ())
return (NO_RECOVERY);
p = tip_gethostbyname (name);
*dst = p;
if (p == NULL)
{
/* h_errno seems to be always zero. Bug? */
if (*tip_h_errno == 0)
return (NO_RECOVERY);
else
return (*tip_h_errno);
}
else
return (0);
}
/* __gethostbyaddr() */
int tcpip_gethostbyaddr (const char *addr, int len, int type, void **dst)
{
void *p;
if (!tcpip_init ())
return (NO_RECOVERY);
p = tip_gethostbyaddr (addr, len, type);
*dst = p;
if (p == NULL)
{
/* h_errno seems to be always zero. Bug? */
if (*tip_h_errno == 0)
return (NO_RECOVERY);
else
return (*tip_h_errno);
}
else
return (0);
}
/* __getservbyname() */
int tcpip_getservbyname (const char *name, const char *proto, void **dst)
{
void *p;
if (!tcpip_init ())
return (-1);
p = tip_getservbyname (name, proto);
*dst = p;
return (p != NULL ? 0 : -1);
}
/* __getservbyport() */
int tcpip_getservbyport (int port, const char *proto, void **dst)
{
void *p;
if (!tcpip_init ())
return (-1);
p = tip_getservbyport (port, proto);
*dst = p;
return (p != NULL ? 0 : -1);
}
/* __gethostid() */
int tcpip_gethostid (int *dst)
{
if (!tcpip_init ())
return (ENETDOWN);
*dst = tip_gethostid ();
last_sock_errno = 0;
return (0);
}
/* __gethostname() */
int tcpip_gethostname (char *name, int len)
{
int rc;
/* TODO: Get hostname from environment variable if the net is
down. */
if (!tcpip_init ())
return (ENETDOWN);
/* If HOSTNAME is not set, IBM's gethostname() simply leaves the
buffer alone! */
*name = 0;
rc = tip_gethostname (name, len);
if (rc != 0)
return (tcpip_errno ());
last_sock_errno = 0;
return (0);
}
/* __getprotobyname() */
int tcpip_getprotobyname (const char *name, void **dst)
{
void *p;
if (!tcpip_init ())
return (-1);
p = tip_getprotobyname (name);
*dst = p;
return (p != NULL ? 0 : -1);
}
/* __getprotobynumber() */
int tcpip_getprotobynumber (int proto, void **dst)
{
void *p;
if (!tcpip_init ())
return (-1);
p = tip_getprotobynumber (proto);
*dst = p;
return (p != NULL ? 0 : -1);
}
/* __getnetbyname() */
int tcpip_getnetbyname (const char *name, void **dst)
{
void *p;
if (!tcpip_init ())
return (-1);
p = tip_getnetbyname (name);
*dst = p;
return (p != NULL ? 0 : -1);
}
/* __getnetbyaddr() */
int tcpip_getnetbyaddr (long net, void **dst)
{
void *p;
if (!tcpip_init ())
return (-1);
p = tip_getnetbyaddr (net);
*dst = p;
return (p != NULL ? 0 : -1);
}
/* Poll socket handles for __select(). Update the bitstrings if a
handle is ready. */
int tcpip_select_poll (struct select_data *d, int *errnop)
{
int i, j, n;
int sockets[SELECT_MAX_SOCKETS];
memcpy (sockets, d->sockets, d->socket_count * sizeof (sockets[0]));
n = tip_select (sockets, d->socket_nread, d->socket_nwrite,
d->socket_nexcept, 0);
if (n < 0)
{
*errnop = tcpip_errno ();
return (-1);
}
if (n == 0)
return (0);
j = 0; n = 0;
for (i = 0; i < d->socket_nread; ++i, ++j)
if (sockets[j] != -1)
{
FD_SET (d->socketh[i], &d->rbits);
++n;
}
for (i = 0; i < d->socket_nwrite; ++i, ++j)
if (sockets[j] != -1)
{
FD_SET (d->socketh[i], &d->wbits);
++n;
}
for (i = 0; i < d->socket_nexcept; ++i, ++j)
if (sockets[j] != -1)
{
FD_SET (d->socketh[i], &d->ebits);
++n;
}
*errnop = 0;
d->ready_count += n;
return (n);
}
/* Notify select_wait() of termination of tcpip_select_thread(). */
static ULONG select_exception (EXCEPTIONREPORTRECORD *report,
EXCEPTIONREGISTRATIONRECORD *registration,
CONTEXTRECORD *context,
void *dummy)
{
if (report->fHandlerFlags & (EH_EXIT_UNWIND|EH_UNWINDING))
return (XCPT_CONTINUE_SEARCH);
switch (report->ExceptionNum)
{
case XCPT_ASYNC_PROCESS_TERMINATE: /* This is the correct one */
case XCPT_PROCESS_TERMINATE: /* OS/2 bug */
DosPostEventSem (socket_done_sem);
break;
}
return (XCPT_CONTINUE_SEARCH);
}
#define POLL_SLEEP 64
/* Wait until a socket handle becomes ready, for __select(). This
function is run in a separate thread. Post `socket_sem' if and
when a socket is ready or the time-out expires. Post
`socket_done_sem' when the thread terminates. */
void tcpip_select_thread (ULONG arg)
{
EXCEPTIONREGISTRATIONRECORD registration;
const struct select_data *d;
int n;
int sockets[SELECT_MAX_SOCKETS];
long timeout;
registration.prev_structure = NULL;
registration.ExceptionHandler = select_exception;
DosSetExceptionHandler (®istration);
/* Exception handler has been installed -- killing this thread is
now allowed. */
DosPostEventSem (socket_start_sem);
d = (const struct select_data *)arg;
memcpy (sockets, d->sockets, d->socket_count * sizeof (sockets[0]));
timeout = (d->timeout == SEM_INDEFINITE_WAIT ? -1 : d->timeout);
if (dont_doskillthread)
while (!select_socket_done)
{
n = tip_select (sockets, d->socket_nread, d->socket_nwrite,
d->socket_nexcept, POLL_SLEEP);
if (n != 0)
break;
}
else
{
n = tip_select (sockets, d->socket_nread, d->socket_nwrite,
d->socket_nexcept, d->timeout);
}
DosPostEventSem (socket_done_sem);
DosUnsetExceptionHandler (®istration);
DosPostEventSem (socket_sem);
DosExit (EXIT_THREAD, 0);
}