| 1 | /* tcpip.c -- TCP/IP
|
|---|
| 2 | Copyright (c) 1994-2000 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, 59 Temple Place - Suite 330,
|
|---|
| 19 | Boston, MA 02111-1307, USA.
|
|---|
| 20 |
|
|---|
| 21 | As special exception, emx.dll can be distributed without source code
|
|---|
| 22 | unless it has been changed. If you modify emx.dll, this exception
|
|---|
| 23 | no longer applies and you must remove this paragraph from all source
|
|---|
| 24 | files for emx.dll. */
|
|---|
| 25 |
|
|---|
| 26 |
|
|---|
| 27 | /* TODO:
|
|---|
| 28 |
|
|---|
| 29 | - inheritance of socket handles
|
|---|
| 30 | - add IBM TCP/IP for OS/2 layer (sock_errno() etc.) */
|
|---|
| 31 |
|
|---|
| 32 | #define INCL_DOSDEVIOCTL
|
|---|
| 33 | #define INCL_DOSEXCEPTIONS
|
|---|
| 34 | #define INCL_DOSMODULEMGR
|
|---|
| 35 | #define INCL_DOSPROCESS
|
|---|
| 36 | #define INCL_DOSSEMAPHORES
|
|---|
| 37 | #include <os2emx.h>
|
|---|
| 38 | #include <emx/syscalls.h>
|
|---|
| 39 | #include <sys/errno.h>
|
|---|
| 40 | #include <sys/types.h>
|
|---|
| 41 | #include <sys/stat.h>
|
|---|
| 42 | #include <sys/fcntl.h>
|
|---|
| 43 | #include <sys/ioctl.h>
|
|---|
| 44 | #include <sys/socket.h>
|
|---|
| 45 | #include <sys/so_ioctl.h>
|
|---|
| 46 | #include <net/route.h>
|
|---|
| 47 | #include <net/if.h>
|
|---|
| 48 | #include <net/if_arp.h>
|
|---|
| 49 | #include <netdb.h>
|
|---|
| 50 | #include "emxdll.h"
|
|---|
| 51 | #include "files.h"
|
|---|
| 52 | #include "tcpip.h"
|
|---|
| 53 | #include "select.h"
|
|---|
| 54 | #include "clib.h"
|
|---|
| 55 |
|
|---|
| 56 | /* Error codes of IBM TCP/IP for OS/2 start at this number. */
|
|---|
| 57 |
|
|---|
| 58 | #define SOCK_ERRNO_BASE 10000
|
|---|
| 59 |
|
|---|
| 60 | /* This variable is zero while tcpip_init() has not been called. A
|
|---|
| 61 | positive value means that initialization of TCP/IP was successful,
|
|---|
| 62 | a negative value means that initialization of TCP/IP failed. */
|
|---|
| 63 |
|
|---|
| 64 | static int tcpip_initialized;
|
|---|
| 65 |
|
|---|
| 66 | /* This variable holds the value returned by the most recent call to
|
|---|
| 67 | sock_errno(). In the future, it will be used for providing a
|
|---|
| 68 | sock_errno() system call. */
|
|---|
| 69 |
|
|---|
| 70 | static int last_sock_errno;
|
|---|
| 71 |
|
|---|
| 72 | /* Module handles of the two IBM TCP/IP for OS/2 DLLs. */
|
|---|
| 73 |
|
|---|
| 74 | static HMODULE hmod_so32dll;
|
|---|
| 75 | static HMODULE hmod_tcp32dll;
|
|---|
| 76 |
|
|---|
| 77 | /* List of file handles created by sock_init(). This is used for
|
|---|
| 78 | fork(). */
|
|---|
| 79 |
|
|---|
| 80 | static ULONG sock_init_count;
|
|---|
| 81 | static ULONG sock_init_array[MAXFH_SOCK_INIT];
|
|---|
| 82 |
|
|---|
| 83 | struct sockaddr;
|
|---|
| 84 |
|
|---|
| 85 | /* Pointers to entrypoints of the IBM TCP/IP for OS/2 DLLs. */
|
|---|
| 86 |
|
|---|
| 87 | static int (*tip_accept)(int, struct sockaddr *, int *);
|
|---|
| 88 | static void (*tip_addsockettolist)(int);
|
|---|
| 89 | static int (*tip_bind)(int, struct sockaddr *, int);
|
|---|
| 90 | static int (*tip_connect)(int, struct sockaddr *, int);
|
|---|
| 91 | static void * (*tip_gethostbyaddr) (const char *, int, int);
|
|---|
| 92 | static void * (*tip_gethostbyname) (const char *);
|
|---|
| 93 | static int (*tip_gethostid) (void);
|
|---|
| 94 | static int (*tip_gethostname) (char *, int len);
|
|---|
| 95 | static void * (*tip_getnetbyaddr) (long);
|
|---|
| 96 | static void * (*tip_getnetbyname) (const char *);
|
|---|
| 97 | static int (*tip_getpeername) (int, void *, int *);
|
|---|
| 98 | static void * (*tip_getprotobyname) (const char *);
|
|---|
| 99 | static void * (*tip_getprotobynumber) (int);
|
|---|
| 100 | static void * (*tip_getservbyname) (const char *, const char *);
|
|---|
| 101 | static void * (*tip_getservbyport) (int, const char *);
|
|---|
| 102 | static int (*tip_getsockname) (int, void *, int *);
|
|---|
| 103 | static int (*tip_getsockopt) (int, int, int, void *, int *);
|
|---|
| 104 | static int (*tip_ioctl)(int, int, void *, int);
|
|---|
| 105 | static int (*tip_listen)(int, int);
|
|---|
| 106 | static int (*tip_removesocketfromlist)(int);
|
|---|
| 107 | static int (*tip_recv)(int, void *, int, int);
|
|---|
| 108 | static int (*tip_recvfrom)(int, void *, int, int, struct sockaddr *, int *);
|
|---|
| 109 | static int (*tip_select)(int *, int, int, int, long);
|
|---|
| 110 | static int (*tip_send)(int, const void *, int, int);
|
|---|
| 111 | static int (*tip_sendto)(int, const void *, int, int, const struct sockaddr *,
|
|---|
| 112 | int);
|
|---|
| 113 | static int (*tip_setsockopt) (int, int, int, const void *, int);
|
|---|
| 114 | static int (*tip_shutdown) (int, int);
|
|---|
| 115 | static int (*tip_socket) (int domain, int type, int protocol);
|
|---|
| 116 | static int (*tip_sock_errno)(void);
|
|---|
| 117 | static int (*tip_sock_init)(void);
|
|---|
| 118 | static int (*tip_soclose)(int handle);
|
|---|
| 119 | static int *tip_h_errno;
|
|---|
| 120 |
|
|---|
| 121 | /* These macros are used for getting the addresses of DLL entrypoints. */
|
|---|
| 122 |
|
|---|
| 123 | #define LOAD(hmod,name,var) (DosQueryProcAddr (hmod, 0, name, (PPFN)var) != 0)
|
|---|
| 124 | #define LOAD_SO(name,var) LOAD (hmod_so32dll, name, var)
|
|---|
| 125 | #define LOAD_TCP(name,var) LOAD (hmod_tcp32dll, name, var)
|
|---|
| 126 |
|
|---|
| 127 |
|
|---|
| 128 | /* Close a socket for this process (the per-process reference count
|
|---|
| 129 | has become zero). Adjust the global reference count and close the
|
|---|
| 130 | socket if the number of processes using that socket gets zero. */
|
|---|
| 131 |
|
|---|
| 132 | static int tcpip_close_process (int s)
|
|---|
| 133 | {
|
|---|
| 134 | int flag;
|
|---|
| 135 |
|
|---|
| 136 | LOCK_COMMON;
|
|---|
| 137 | flag = (sock_proc_count[s] > 0 && --sock_proc_count[s] == 0);
|
|---|
| 138 | UNLOCK_COMMON;
|
|---|
| 139 |
|
|---|
| 140 | if (flag)
|
|---|
| 141 | {
|
|---|
| 142 | int rc = tip_soclose (s);
|
|---|
| 143 | if (rc != 0 && (debug_flags & DEBUG_SOCLOSE)
|
|---|
| 144 | && tip_sock_errno () == SOCK_ERRNO_BASE + 38) /* ENOTSOCK */
|
|---|
| 145 | rc = 0; /* Don't mind socket closed behind our back */
|
|---|
| 146 | return rc;
|
|---|
| 147 | }
|
|---|
| 148 | else
|
|---|
| 149 | {
|
|---|
| 150 | /* Call removesocketfromlist() to prevent SO32DLL.DLL's exit
|
|---|
| 151 | list procedure from closing the socket -- it's still in use
|
|---|
| 152 | by another process which inherited or imported the socket
|
|---|
| 153 | handle. */
|
|---|
| 154 |
|
|---|
| 155 | tip_removesocketfromlist (s);
|
|---|
| 156 | return 0;
|
|---|
| 157 | }
|
|---|
| 158 | }
|
|---|
| 159 |
|
|---|
| 160 |
|
|---|
| 161 | /* This function is called by the exit list procedure (and by
|
|---|
| 162 | term_tcpip(), which is in turn called by the DLL termination
|
|---|
| 163 | function). It closes all open sockets. Calling exit_tcpip() more
|
|---|
| 164 | than once is harmless. */
|
|---|
| 165 |
|
|---|
| 166 | void exit_tcpip (void)
|
|---|
| 167 | {
|
|---|
| 168 | ULONG i;
|
|---|
| 169 |
|
|---|
| 170 | if (tcpip_initialized > 0)
|
|---|
| 171 | for (i = 0; i < handle_count; ++i)
|
|---|
| 172 | if ((files[i].flags & (HF_OPEN | HF_SOCKET)) == (HF_OPEN | HF_SOCKET)
|
|---|
| 173 | && files[i].ref_count != 0)
|
|---|
| 174 | {
|
|---|
| 175 | files[i].flags = 0;
|
|---|
| 176 | files[i].ref_count = 0;
|
|---|
| 177 | tcpip_close_process (files[i].x.socket.handle);
|
|---|
| 178 | }
|
|---|
| 179 | }
|
|---|
| 180 |
|
|---|
| 181 |
|
|---|
| 182 | void term_tcpip (void)
|
|---|
| 183 | {
|
|---|
| 184 | /* Close all sockets in case the exit list procedure has not been
|
|---|
| 185 | called. This happens if DosFreeModule is used. Calling
|
|---|
| 186 | exit_tcpip() more than once is benign. */
|
|---|
| 187 |
|
|---|
| 188 | exit_tcpip ();
|
|---|
| 189 |
|
|---|
| 190 | /* Unload the TCP/IP DLLs. */
|
|---|
| 191 |
|
|---|
| 192 | if (tcpip_initialized > 0)
|
|---|
| 193 | {
|
|---|
| 194 | tcpip_initialized = 0;
|
|---|
| 195 | DosFreeModule (hmod_so32dll);
|
|---|
| 196 | DosFreeModule (hmod_tcp32dll);
|
|---|
| 197 | }
|
|---|
| 198 | }
|
|---|
| 199 |
|
|---|
| 200 |
|
|---|
| 201 | /* See tcpip_init() for details. This function is called by
|
|---|
| 202 | tcpip_init() and tcp_init_fork(). See those functions for
|
|---|
| 203 | additional actions to be taken. */
|
|---|
| 204 |
|
|---|
| 205 | static int tcpip_init2 (void)
|
|---|
| 206 | {
|
|---|
| 207 | /* Load the two IBM TCP/IP for SO/2 DLLs. */
|
|---|
| 208 |
|
|---|
| 209 | if (load_module ("SO32DLL", &hmod_so32dll) != 0)
|
|---|
| 210 | {
|
|---|
| 211 | tcpip_initialized = -1;
|
|---|
| 212 | return FALSE;
|
|---|
| 213 | }
|
|---|
| 214 | if (load_module ("TCP32DLL", &hmod_tcp32dll) != 0)
|
|---|
| 215 | {
|
|---|
| 216 | DosFreeModule (hmod_so32dll);
|
|---|
| 217 | tcpip_initialized = -1;
|
|---|
| 218 | return FALSE;
|
|---|
| 219 | }
|
|---|
| 220 |
|
|---|
| 221 | /* Initialize the pointers to the DLL entrypoints and call
|
|---|
| 222 | sock_init(). */
|
|---|
| 223 |
|
|---|
| 224 | if (LOAD_SO ("SOCK_INIT", &tip_sock_init)
|
|---|
| 225 | || LOAD_SO ("SOCK_ERRNO", &tip_sock_errno)
|
|---|
| 226 | || LOAD_SO ("ACCEPT", &tip_accept)
|
|---|
| 227 | || LOAD_SO ("ADDSOCKETTOLIST", &tip_addsockettolist)
|
|---|
| 228 | || LOAD_SO ("BIND", &tip_bind)
|
|---|
| 229 | || LOAD_SO ("CONNECT", &tip_connect)
|
|---|
| 230 | || LOAD_SO ("GETHOSTID", &tip_gethostid)
|
|---|
| 231 | || LOAD_SO ("GETPEERNAME", &tip_getpeername)
|
|---|
| 232 | || LOAD_SO ("GETSOCKNAME", &tip_getsockname)
|
|---|
| 233 | || LOAD_SO ("GETSOCKOPT", &tip_getsockopt)
|
|---|
| 234 | || LOAD_SO ("IOCTL", &tip_ioctl)
|
|---|
| 235 | || LOAD_SO ("LISTEN", &tip_listen)
|
|---|
| 236 | || LOAD_SO ("REMOVESOCKETFROMLIST", &tip_removesocketfromlist)
|
|---|
| 237 | || LOAD_SO ("RECV", &tip_recv)
|
|---|
| 238 | || LOAD_SO ("RECVFROM", &tip_recvfrom)
|
|---|
| 239 | || LOAD_SO ("SELECT", &tip_select)
|
|---|
| 240 | || LOAD_SO ("SEND", &tip_send)
|
|---|
| 241 | || LOAD_SO ("SENDTO", &tip_sendto)
|
|---|
| 242 | || LOAD_SO ("SETSOCKOPT", &tip_setsockopt)
|
|---|
| 243 | || LOAD_SO ("SHUTDOWN", &tip_shutdown)
|
|---|
| 244 | || LOAD_SO ("SOCKET", &tip_socket)
|
|---|
| 245 | || LOAD_SO ("SOCLOSE", &tip_soclose)
|
|---|
| 246 | || LOAD_TCP ("GETHOSTBYADDR", &tip_gethostbyaddr)
|
|---|
| 247 | || LOAD_TCP ("GETHOSTBYNAME", &tip_gethostbyname)
|
|---|
| 248 | || LOAD_TCP ("GETHOSTNAME", &tip_gethostname)
|
|---|
| 249 | || LOAD_TCP ("GETNETBYADDR", &tip_getnetbyaddr)
|
|---|
| 250 | || LOAD_TCP ("GETNETBYNAME", &tip_getnetbyname)
|
|---|
| 251 | || LOAD_TCP ("GETPROTOBYNAME", &tip_getprotobyname)
|
|---|
| 252 | || LOAD_TCP ("GETPROTOBYNUMBER", &tip_getprotobynumber)
|
|---|
| 253 | || LOAD_TCP ("GETSERVBYNAME", &tip_getservbyname)
|
|---|
| 254 | || LOAD_TCP ("GETSERVBYPORT", &tip_getservbyport)
|
|---|
| 255 | || LOAD_TCP ("H_ERRNO", &tip_h_errno)
|
|---|
| 256 | || tip_sock_init () != 0)
|
|---|
| 257 | {
|
|---|
| 258 | DosFreeModule (hmod_so32dll);
|
|---|
| 259 | DosFreeModule (hmod_tcp32dll);
|
|---|
| 260 | tcpip_initialized = -1;
|
|---|
| 261 | return FALSE;
|
|---|
| 262 | }
|
|---|
| 263 |
|
|---|
| 264 | /* Success! */
|
|---|
| 265 |
|
|---|
| 266 | tcpip_initialized = 1;
|
|---|
| 267 | return TRUE;
|
|---|
| 268 | }
|
|---|
| 269 |
|
|---|
| 270 |
|
|---|
| 271 | /* Initialize TCP/IP. Return FALSE on failure, return TRUE on
|
|---|
| 272 | success. This function must be called before using any of the
|
|---|
| 273 | above `tip_*' pointers. Functions which check HF_SOCKET don't have
|
|---|
| 274 | to call tcpip_init() as the HF_SOCKET bit can only be set by a
|
|---|
| 275 | function which calls tcpip_init(). */
|
|---|
| 276 |
|
|---|
| 277 | static int tcpip_init (void)
|
|---|
| 278 | {
|
|---|
| 279 | int result;
|
|---|
| 280 | ULONG count;
|
|---|
| 281 |
|
|---|
| 282 | /* If tcpip_init() has already been called, use the result of the
|
|---|
| 283 | first call. */
|
|---|
| 284 |
|
|---|
| 285 | if (tcpip_initialized < 0)
|
|---|
| 286 | return FALSE;
|
|---|
| 287 | if (tcpip_initialized > 0)
|
|---|
| 288 | return TRUE;
|
|---|
| 289 |
|
|---|
| 290 | /* Ensure that only one thread can enter tcpip_init2(). We can use
|
|---|
| 291 | the `files_access' semaphore for this.
|
|---|
| 292 |
|
|---|
| 293 | We should suspend all other threads to prevent them from opening
|
|---|
| 294 | or closing handles while we look for unused handles.
|
|---|
| 295 | Unfortunately, that cannot be done without risking a deadlock.
|
|---|
| 296 | As fork() works with single-thread processes only anyway, we
|
|---|
| 297 | ignore the problem of other threads opening or closing
|
|---|
| 298 | handles. */
|
|---|
| 299 |
|
|---|
| 300 | DosEnterMustComplete (&count);
|
|---|
| 301 | LOCK_FILES;
|
|---|
| 302 |
|
|---|
| 303 | /* Check tcpip_initialized, in case another thread blocked us in the
|
|---|
| 304 | previous statement. */
|
|---|
| 305 |
|
|---|
| 306 | if (tcpip_initialized < 0)
|
|---|
| 307 | result = FALSE;
|
|---|
| 308 | else if (tcpip_initialized > 0)
|
|---|
| 309 | result = TRUE;
|
|---|
| 310 | else
|
|---|
| 311 | {
|
|---|
| 312 | /* Call tcpip_init2(), recording the file handles used by
|
|---|
| 313 | sock_init() for fork(). */
|
|---|
| 314 |
|
|---|
| 315 | sock_init_count = find_unused_handles (sock_init_array, MAXFH_SOCK_INIT);
|
|---|
| 316 | result = tcpip_init2 ();
|
|---|
| 317 |
|
|---|
| 318 | /* Adjust sock_init_count in case sock_init() creates less than
|
|---|
| 319 | MAXFH_SOCK_INIT handles. */
|
|---|
| 320 |
|
|---|
| 321 | if (result)
|
|---|
| 322 | {
|
|---|
| 323 | ULONG temp;
|
|---|
| 324 |
|
|---|
| 325 | if (find_unused_handles (&temp, 1) == 1)
|
|---|
| 326 | while (sock_init_count > 0
|
|---|
| 327 | && sock_init_array[sock_init_count-1] >= temp)
|
|---|
| 328 | --sock_init_count;
|
|---|
| 329 | }
|
|---|
| 330 | else
|
|---|
| 331 | sock_init_count = 0;
|
|---|
| 332 | }
|
|---|
| 333 |
|
|---|
| 334 | UNLOCK_FILES;
|
|---|
| 335 | DosExitMustComplete (&count);
|
|---|
| 336 | return result;
|
|---|
| 337 | }
|
|---|
| 338 |
|
|---|
| 339 |
|
|---|
| 340 | /* Initialize TCP/IP in a forked process that inherits socket handles
|
|---|
| 341 | from its parent. As we have only one thread now, we don't have to
|
|---|
| 342 | lock out other threads. */
|
|---|
| 343 |
|
|---|
| 344 | int tcpip_init_fork (const struct fork_data_done *p)
|
|---|
| 345 | {
|
|---|
| 346 | #define MAX_FILL 128
|
|---|
| 347 | ULONG unused[MAX_FILL];
|
|---|
| 348 | int i, j, n, fill_count, result;
|
|---|
| 349 |
|
|---|
| 350 | /* Copy sock_init_array from the parent process in case this process
|
|---|
| 351 | forks. */
|
|---|
| 352 |
|
|---|
| 353 | sock_init_count = p->sock_init_count;
|
|---|
| 354 | memcpy (sock_init_array, p->sock_init_array, sizeof (sock_init_array));
|
|---|
| 355 |
|
|---|
| 356 | /* Fill unused handle slots to make sock_init() use the same handles
|
|---|
| 357 | as in the parent process. Temporarily set `handle_count' as it
|
|---|
| 358 | has not yet been initialized and is used by
|
|---|
| 359 | find_unused_handles(). */
|
|---|
| 360 |
|
|---|
| 361 | n = MAX_FILL;
|
|---|
| 362 | if (sock_init_count > 0 && sock_init_array[sock_init_count-1] + 1 < n)
|
|---|
| 363 | n = sock_init_array[sock_init_count-1] + 1;
|
|---|
| 364 | handle_count = n;
|
|---|
| 365 | n = find_unused_handles (unused, n);
|
|---|
| 366 | handle_count = 0;
|
|---|
| 367 |
|
|---|
| 368 | i = j = 0; fill_count = 0;
|
|---|
| 369 | while (i < n && j < sock_init_count)
|
|---|
| 370 | if (unused[i] == sock_init_array[j])
|
|---|
| 371 | {
|
|---|
| 372 | /* The slot is unused in this process and in its parent
|
|---|
| 373 | process. It will be used by sock_init(). */
|
|---|
| 374 |
|
|---|
| 375 | ++i; ++j;
|
|---|
| 376 | }
|
|---|
| 377 | else if (unused[i] < sock_init_array[j])
|
|---|
| 378 | {
|
|---|
| 379 | ULONG handle, action;
|
|---|
| 380 |
|
|---|
| 381 | /* The file handle is unused in this process, but is used in
|
|---|
| 382 | the parent process. Fill it. We could use DosDupHandle if
|
|---|
| 383 | we knew an open file handle. However, if we inherited
|
|---|
| 384 | socket handles only, there is no such handle. */
|
|---|
| 385 |
|
|---|
| 386 | if (DosOpen ("nul", &handle, &action, 0, 0,
|
|---|
| 387 | OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW,
|
|---|
| 388 | (OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE
|
|---|
| 389 | | OPEN_FLAGS_NOINHERIT), NULL) != 0
|
|---|
| 390 | || handle != unused[i])
|
|---|
| 391 | return FALSE;
|
|---|
| 392 |
|
|---|
| 393 | /* Remember the file handle, to be able to close it later. We
|
|---|
| 394 | reuse elements of unused[] which have already been
|
|---|
| 395 | processed. */
|
|---|
| 396 |
|
|---|
| 397 | unused[fill_count++] = unused[i];
|
|---|
| 398 | ++i;
|
|---|
| 399 | }
|
|---|
| 400 | else
|
|---|
| 401 | {
|
|---|
| 402 | /* A file handle used by this process is unused in the parent
|
|---|
| 403 | process. This should not happen and cannot be handled. */
|
|---|
| 404 |
|
|---|
| 405 | return FALSE;
|
|---|
| 406 | }
|
|---|
| 407 |
|
|---|
| 408 | /* Now initialize TCP/IP. This calls sock_init(). */
|
|---|
| 409 |
|
|---|
| 410 | result = tcpip_init2 ();
|
|---|
| 411 |
|
|---|
| 412 | /* Close stuffed file handles. */
|
|---|
| 413 |
|
|---|
| 414 | for (i = 0; i < fill_count; ++i)
|
|---|
| 415 | DosClose (unused[i]);
|
|---|
| 416 |
|
|---|
| 417 | return result;
|
|---|
| 418 | }
|
|---|
| 419 |
|
|---|
| 420 |
|
|---|
| 421 | /* Initialize file tables for inherited socket handles. */
|
|---|
| 422 |
|
|---|
| 423 | void copy_fork_sock (const struct fork_data_done *p)
|
|---|
| 424 | {
|
|---|
| 425 | ULONG i, fd, s;
|
|---|
| 426 |
|
|---|
| 427 | for (i = 0; i < p->sock_count; ++i)
|
|---|
| 428 | {
|
|---|
| 429 | fd = p->sock_array[i].f;
|
|---|
| 430 | s = p->sock_array[i].s;
|
|---|
| 431 | close_handle (fd); /* Clear reference count */
|
|---|
| 432 | alloc_file_description (fd);
|
|---|
| 433 | if (IS_VALID_FILE (fd))
|
|---|
| 434 | {
|
|---|
| 435 | int j = 0;
|
|---|
| 436 | set_handle_flags (fd, HF_OPEN | HF_SOCKET);
|
|---|
| 437 | GET_FILE (fd)->x.socket.handle = s;
|
|---|
| 438 | GET_FILE (fd)->x.socket.fd_flags = 0;
|
|---|
| 439 | while (j < i && p->sock_array[j].s != s)
|
|---|
| 440 | ++j;
|
|---|
| 441 | if (j == i)
|
|---|
| 442 | tip_addsockettolist (s); /* Inform SO32DLL.DLL */
|
|---|
| 443 | }
|
|---|
| 444 | else
|
|---|
| 445 | tcpip_close_process (s);
|
|---|
| 446 | }
|
|---|
| 447 | }
|
|---|
| 448 |
|
|---|
| 449 |
|
|---|
| 450 | /* Tell the child process about sockets: Build a list of sockets to be
|
|---|
| 451 | inherited.
|
|---|
| 452 |
|
|---|
| 453 | TODO: Closing a socket in another thread while fork() is in
|
|---|
| 454 | progress might result in a socket handle leak.
|
|---|
| 455 |
|
|---|
| 456 | FORK_OBJ_SIZE is big enough for MAX_SOCKETS sockets being passed
|
|---|
| 457 | down to the child process. */
|
|---|
| 458 |
|
|---|
| 459 | void tcpip_fork_sock (struct fork_data_done *p)
|
|---|
| 460 | {
|
|---|
| 461 | ULONG i;
|
|---|
| 462 | my_file *f;
|
|---|
| 463 |
|
|---|
| 464 | p->sock_init_count = sock_init_count;
|
|---|
| 465 | memcpy (p->sock_init_array, sock_init_array, sizeof (p->sock_init_array));
|
|---|
| 466 | p->sock_count = 0;
|
|---|
| 467 | p->sock_array = (struct fork_sock *)((char *)p + p->size);
|
|---|
| 468 | for (i = 0; i < handle_count; ++i)
|
|---|
| 469 | if (IS_SOCKET (i) && IS_VALID_FILE (i)
|
|---|
| 470 | && p->size + sizeof (struct fork_sock) <= FORK_OBJ_SIZE)
|
|---|
| 471 | {
|
|---|
| 472 | f = GET_FILE (i);
|
|---|
| 473 | p->sock_array[p->sock_count].f = i;
|
|---|
| 474 | p->sock_array[p->sock_count].s = f->x.socket.handle;
|
|---|
| 475 | ++p->sock_count; p->size += sizeof (struct fork_sock);
|
|---|
| 476 | LOCK_COMMON;
|
|---|
| 477 | ++sock_proc_count[f->x.socket.handle];
|
|---|
| 478 | UNLOCK_COMMON;
|
|---|
| 479 | }
|
|---|
| 480 | }
|
|---|
| 481 |
|
|---|
| 482 |
|
|---|
| 483 | /* Forking a process failed. Adjust socket reference counts. */
|
|---|
| 484 |
|
|---|
| 485 | void tcpip_undo_fork_sock (const struct fork_data_done *p)
|
|---|
| 486 | {
|
|---|
| 487 | ULONG i;
|
|---|
| 488 |
|
|---|
| 489 | LOCK_COMMON;
|
|---|
| 490 | for (i = 0; i < p->sock_count; ++i)
|
|---|
| 491 | --sock_proc_count[p->sock_array[i].s];
|
|---|
| 492 | UNLOCK_COMMON;
|
|---|
| 493 | }
|
|---|
| 494 |
|
|---|
| 495 |
|
|---|
| 496 | /* Use UNDEF for error codes which are supposed to not being
|
|---|
| 497 | returned by IBM TCP/IP for OS/2. */
|
|---|
| 498 |
|
|---|
| 499 | #define UNDEF EINVAL
|
|---|
| 500 |
|
|---|
| 501 | /* This table maps error codes of IBM TCP/IP for OS/2 (offset by
|
|---|
| 502 | SOCK_ERRNO_BASE) to emx errno numbers. */
|
|---|
| 503 |
|
|---|
| 504 | static unsigned char const sock_errno_tab[] =
|
|---|
| 505 | {
|
|---|
| 506 | UNDEF, /* +0 */
|
|---|
| 507 | EPERM, /* +1 */
|
|---|
| 508 | UNDEF, /* +2 */
|
|---|
| 509 | ESRCH, /* +3 */
|
|---|
| 510 | EINTR, /* +4 */
|
|---|
| 511 | UNDEF, /* +5 */
|
|---|
| 512 | ENXIO, /* +6 */
|
|---|
| 513 | UNDEF, /* +7 */
|
|---|
| 514 | UNDEF, /* +8 */
|
|---|
| 515 | EBADF, /* +9 */
|
|---|
| 516 | UNDEF, /* +10 */
|
|---|
| 517 | UNDEF, /* +11 */
|
|---|
| 518 | UNDEF, /* +12 */
|
|---|
| 519 | EACCES, /* +13 */
|
|---|
| 520 | EFAULT, /* +14 */
|
|---|
| 521 | UNDEF, /* +15 */
|
|---|
| 522 | UNDEF, /* +16 */
|
|---|
| 523 | UNDEF, /* +17 */
|
|---|
| 524 | UNDEF, /* +18 */
|
|---|
| 525 | UNDEF, /* +19 */
|
|---|
| 526 | UNDEF, /* +20 */
|
|---|
| 527 | UNDEF, /* +21 */
|
|---|
| 528 | EINVAL, /* +22 */
|
|---|
| 529 | UNDEF, /* +23 */
|
|---|
| 530 | EMFILE, /* +24 */
|
|---|
| 531 | UNDEF, /* +25 */
|
|---|
| 532 | UNDEF, /* +26 */
|
|---|
| 533 | UNDEF, /* +27 */
|
|---|
| 534 | UNDEF, /* +28 */
|
|---|
| 535 | UNDEF, /* +29 */
|
|---|
| 536 | UNDEF, /* +30 */
|
|---|
| 537 | UNDEF, /* +31 */
|
|---|
| 538 | EPIPE, /* +32 */
|
|---|
| 539 | UNDEF, /* +33 */
|
|---|
| 540 | UNDEF, /* +34 */
|
|---|
| 541 | EWOULDBLOCK, /* +35 */
|
|---|
| 542 | EINPROGRESS, /* +36 */
|
|---|
| 543 | EALREADY, /* +37 */
|
|---|
| 544 | ENOTSOCK, /* +38 */
|
|---|
| 545 | EDESTADDRREQ, /* +39 */
|
|---|
| 546 | EMSGSIZE, /* +40 */
|
|---|
| 547 | EPROTOTYPE, /* +41 */
|
|---|
| 548 | ENOPROTOOPT, /* +42 */
|
|---|
| 549 | EPROTONOSUPPORT, /* +43 */
|
|---|
| 550 | ESOCKTNOSUPPORT, /* +44 */
|
|---|
| 551 | EOPNOTSUPP, /* +45 */
|
|---|
| 552 | EPFNOSUPPORT, /* +46 */
|
|---|
| 553 | EAFNOSUPPORT, /* +47 */
|
|---|
| 554 | EADDRINUSE, /* +48 */
|
|---|
| 555 | EADDRNOTAVAIL, /* +49 */
|
|---|
| 556 | ENETDOWN, /* +50 */
|
|---|
| 557 | ENETUNREACH, /* +51 */
|
|---|
| 558 | ENETRESET, /* +52 */
|
|---|
| 559 | ECONNABORTED, /* +53 */
|
|---|
| 560 | ECONNRESET, /* +54 */
|
|---|
| 561 | ENOBUFS, /* +55 */
|
|---|
| 562 | EISCONN, /* +56 */
|
|---|
| 563 | ENOTCONN, /* +57 */
|
|---|
| 564 | ESHUTDOWN, /* +58 */
|
|---|
| 565 | ETOOMANYREFS, /* +59 */
|
|---|
| 566 | ETIMEDOUT, /* +60 */
|
|---|
| 567 | ECONNREFUSED, /* +61 */
|
|---|
| 568 | ELOOP, /* +62 */
|
|---|
| 569 | ENAMETOOLONG, /* +63 */
|
|---|
| 570 | EHOSTDOWN, /* +64 */
|
|---|
| 571 | EHOSTUNREACH, /* +65 */
|
|---|
| 572 | ENOTEMPTY, /* +66 */
|
|---|
| 573 | UNDEF, /* +67 */
|
|---|
| 574 | UNDEF, /* +68 */
|
|---|
| 575 | UNDEF, /* +69 */
|
|---|
| 576 | UNDEF, /* +70 */
|
|---|
| 577 | UNDEF, /* +71 */
|
|---|
| 578 | UNDEF, /* +72 */
|
|---|
| 579 | UNDEF, /* +73 */
|
|---|
| 580 | UNDEF, /* +74 */
|
|---|
| 581 | UNDEF, /* +75 */
|
|---|
| 582 | UNDEF, /* +76 */
|
|---|
| 583 | UNDEF, /* +77 */
|
|---|
| 584 | UNDEF, /* +78 */
|
|---|
| 585 | UNDEF, /* +79 */
|
|---|
| 586 | UNDEF, /* +80 */
|
|---|
| 587 | UNDEF, /* +81 */
|
|---|
| 588 | UNDEF, /* +82 */
|
|---|
| 589 | UNDEF, /* +83 */
|
|---|
| 590 | UNDEF, /* +84 */
|
|---|
| 591 | UNDEF, /* +85 */
|
|---|
| 592 | UNDEF, /* +86 */
|
|---|
| 593 | UNDEF, /* +87 */
|
|---|
| 594 | UNDEF, /* +88 */
|
|---|
| 595 | UNDEF, /* +89 */
|
|---|
| 596 | UNDEF, /* +90 */
|
|---|
| 597 | UNDEF, /* +91 */
|
|---|
| 598 | UNDEF, /* +92 */
|
|---|
| 599 | UNDEF, /* +93 */
|
|---|
| 600 | UNDEF, /* +94 */
|
|---|
| 601 | UNDEF, /* +95 */
|
|---|
| 602 | UNDEF, /* +96 */
|
|---|
| 603 | UNDEF, /* +97 */
|
|---|
| 604 | UNDEF, /* +98 */
|
|---|
| 605 | UNDEF, /* +99 */
|
|---|
| 606 | EIO /* +100: SOCEOS2ERR */
|
|---|
| 607 | };
|
|---|
| 608 |
|
|---|
| 609 |
|
|---|
| 610 | /* Obtain, translate, and return the error code of the most recent
|
|---|
| 611 | TCP/IP call. */
|
|---|
| 612 |
|
|---|
| 613 | static int tcpip_errno (void)
|
|---|
| 614 | {
|
|---|
| 615 | int e;
|
|---|
| 616 |
|
|---|
| 617 | e = tip_sock_errno ();
|
|---|
| 618 | last_sock_errno = e;
|
|---|
| 619 | if (e < SOCK_ERRNO_BASE || e >= SOCK_ERRNO_BASE + sizeof (sock_errno_tab))
|
|---|
| 620 | return EINVAL;
|
|---|
| 621 | return sock_errno_tab[e - SOCK_ERRNO_BASE];
|
|---|
| 622 | }
|
|---|
| 623 |
|
|---|
| 624 |
|
|---|
| 625 | /* Fake a low-level file I/O handle for a socket. Instead of (or in
|
|---|
| 626 | addition to) relocating OS/2 file handles, we might open the "NUL"
|
|---|
| 627 | device to fill the slot used for the faked handle. */
|
|---|
| 628 |
|
|---|
| 629 | static int tcpip_new_handle (int s, int *errnop)
|
|---|
| 630 | {
|
|---|
| 631 | int i;
|
|---|
| 632 |
|
|---|
| 633 | /* Check index for sock_proc_count[]. */
|
|---|
| 634 |
|
|---|
| 635 | if (s < 0 || s >= MAX_SOCKETS)
|
|---|
| 636 | {
|
|---|
| 637 | tip_soclose (s);
|
|---|
| 638 | *errnop = EMFILE;
|
|---|
| 639 | return -1;
|
|---|
| 640 | }
|
|---|
| 641 |
|
|---|
| 642 | /* We might want to prefer handles with high numbers to minimize
|
|---|
| 643 | relocation of file handles; however, we don't know the value of
|
|---|
| 644 | the application's `_nfiles' variable (and nowadays there's no
|
|---|
| 645 | longer a limit). */
|
|---|
| 646 |
|
|---|
| 647 | LOCK_FILES;
|
|---|
| 648 | for (i = 0; i < handle_count; ++i)
|
|---|
| 649 | if (!(handle_flags[i] & HF_OPEN))
|
|---|
| 650 | {
|
|---|
| 651 | alloc_file_description (i);
|
|---|
| 652 | if (!IS_VALID_FILE (i))
|
|---|
| 653 | break;
|
|---|
| 654 | set_handle_flags (i, HF_OPEN | HF_SOCKET);
|
|---|
| 655 | GET_FILE (i)->x.socket.handle = s;
|
|---|
| 656 | GET_FILE (i)->x.socket.fd_flags = 0;
|
|---|
| 657 |
|
|---|
| 658 | /* Note: By incrementing sock_proc_count[s] after adding the
|
|---|
| 659 | socket to our table of file descriptors, the socket might
|
|---|
| 660 | be closed twice if the process terminates between those two
|
|---|
| 661 | actions. That's preferable to not closing the socket. (It
|
|---|
| 662 | can hurt only if another process uses the same socket
|
|---|
| 663 | handle at the same time, which is quite unlikely as IBM
|
|---|
| 664 | TCP/IP reuses socket handles not before about `2048 new
|
|---|
| 665 | sockets later'.)
|
|---|
| 666 |
|
|---|
| 667 | As the socket handle is not yet visible to the application
|
|---|
| 668 | program, LOCK_COMMON and UNLOCK_COMMON are not required. */
|
|---|
| 669 |
|
|---|
| 670 | sock_proc_count[s] += 1;
|
|---|
| 671 | UNLOCK_FILES;
|
|---|
| 672 | *errnop = 0;
|
|---|
| 673 | return i;
|
|---|
| 674 | }
|
|---|
| 675 | UNLOCK_FILES;
|
|---|
| 676 | tip_soclose (s);
|
|---|
| 677 | *errnop = EMFILE;
|
|---|
| 678 | return -1;
|
|---|
| 679 | }
|
|---|
| 680 |
|
|---|
| 681 |
|
|---|
| 682 | /* __socket() */
|
|---|
| 683 |
|
|---|
| 684 | int tcpip_socket (int domain, int type, int protocol, int *errnop)
|
|---|
| 685 | {
|
|---|
| 686 | int s;
|
|---|
| 687 |
|
|---|
| 688 | if (!tcpip_init ())
|
|---|
| 689 | {
|
|---|
| 690 | *errnop = ENETDOWN; /* TODO: last_sock_errno */
|
|---|
| 691 | return -1;
|
|---|
| 692 | }
|
|---|
| 693 |
|
|---|
| 694 | s = tip_socket (domain, type, protocol);
|
|---|
| 695 | if (s == -1)
|
|---|
| 696 | {
|
|---|
| 697 | *errnop = tcpip_errno ();
|
|---|
| 698 | return -1;
|
|---|
| 699 | }
|
|---|
| 700 |
|
|---|
| 701 | return tcpip_new_handle (s, errnop);
|
|---|
| 702 | }
|
|---|
| 703 |
|
|---|
| 704 |
|
|---|
| 705 | /* __getsockhandle() */
|
|---|
| 706 |
|
|---|
| 707 | int tcpip_getsockhandle (ULONG handle, int *errnop)
|
|---|
| 708 | {
|
|---|
| 709 | if (!IS_SOCKET (handle) || !IS_VALID_FILE (handle))
|
|---|
| 710 | {
|
|---|
| 711 | *errnop = EBADF;
|
|---|
| 712 | return -1;
|
|---|
| 713 | }
|
|---|
| 714 | *errnop = 0;
|
|---|
| 715 | return GET_FILE (handle)->x.socket.handle;
|
|---|
| 716 | }
|
|---|
| 717 |
|
|---|
| 718 |
|
|---|
| 719 | /* __accept() */
|
|---|
| 720 |
|
|---|
| 721 | int tcpip_accept (ULONG handle, void *addr, int *paddrlen, int *errnop)
|
|---|
| 722 | {
|
|---|
| 723 | int s;
|
|---|
| 724 |
|
|---|
| 725 | if (!IS_SOCKET (handle) || !IS_VALID_FILE (handle))
|
|---|
| 726 | {
|
|---|
| 727 | *errnop = EBADF; /* TODO: last_sock_errno */
|
|---|
| 728 | return -1;
|
|---|
| 729 | }
|
|---|
| 730 |
|
|---|
| 731 | s = tip_accept (GET_FILE (handle)->x.socket.handle, addr, paddrlen);
|
|---|
| 732 | if (s == -1)
|
|---|
| 733 | {
|
|---|
| 734 | *errnop = tcpip_errno ();
|
|---|
| 735 | return -1;
|
|---|
| 736 | }
|
|---|
| 737 |
|
|---|
| 738 | return tcpip_new_handle (s, errnop);
|
|---|
| 739 | }
|
|---|
| 740 |
|
|---|
| 741 |
|
|---|
| 742 | /* __bind() */
|
|---|
| 743 |
|
|---|
| 744 | int tcpip_bind (ULONG handle, void *addr, int addrlen)
|
|---|
| 745 | {
|
|---|
| 746 | int rc;
|
|---|
| 747 |
|
|---|
| 748 | if (!IS_SOCKET (handle) || !IS_VALID_FILE (handle))
|
|---|
| 749 | return EBADF; /* TODO: last_sock_errno */
|
|---|
| 750 |
|
|---|
| 751 | rc = tip_bind (GET_FILE (handle)->x.socket.handle, addr, addrlen);
|
|---|
| 752 | if (rc != 0)
|
|---|
| 753 | return tcpip_errno ();
|
|---|
| 754 | last_sock_errno = 0;
|
|---|
| 755 | return 0;
|
|---|
| 756 | }
|
|---|
| 757 |
|
|---|
| 758 |
|
|---|
| 759 | /* __connect() */
|
|---|
| 760 |
|
|---|
| 761 | int tcpip_connect (ULONG handle, void *addr, int addrlen)
|
|---|
| 762 | {
|
|---|
| 763 | int rc;
|
|---|
| 764 |
|
|---|
| 765 | if (!IS_SOCKET (handle) || !IS_VALID_FILE (handle))
|
|---|
| 766 | return EBADF; /* TODO: last_sock_errno */
|
|---|
| 767 |
|
|---|
| 768 | rc = tip_connect (GET_FILE (handle)->x.socket.handle, addr, addrlen);
|
|---|
| 769 | if (rc != 0)
|
|---|
| 770 | return tcpip_errno ();
|
|---|
| 771 | last_sock_errno = 0;
|
|---|
| 772 | return 0;
|
|---|
| 773 | }
|
|---|
| 774 |
|
|---|
| 775 |
|
|---|
| 776 | /* __listen() */
|
|---|
| 777 |
|
|---|
| 778 | int tcpip_listen (ULONG handle, int backlog)
|
|---|
| 779 | {
|
|---|
| 780 | int rc;
|
|---|
| 781 |
|
|---|
| 782 | if (!IS_SOCKET (handle) || !IS_VALID_FILE (handle))
|
|---|
| 783 | return EBADF; /* TODO: last_sock_errno */
|
|---|
| 784 |
|
|---|
| 785 | rc = tip_listen (GET_FILE (handle)->x.socket.handle, backlog);
|
|---|
| 786 | if (rc != 0)
|
|---|
| 787 | return tcpip_errno ();
|
|---|
| 788 | last_sock_errno = 0;
|
|---|
| 789 | return 0;
|
|---|
| 790 | }
|
|---|
| 791 |
|
|---|
| 792 |
|
|---|
| 793 | /* __recv() */
|
|---|
| 794 |
|
|---|
| 795 | int tcpip_recv (ULONG handle, void *buf, int len, unsigned flags, int *errnop)
|
|---|
| 796 | {
|
|---|
| 797 | int r;
|
|---|
| 798 |
|
|---|
| 799 | if (!IS_SOCKET (handle))
|
|---|
| 800 | {
|
|---|
| 801 | ULONG rc, nread;
|
|---|
| 802 | rc = DosRead (handle, buf, (ULONG)len, &nread);
|
|---|
| 803 | if (rc != 0)
|
|---|
| 804 | {
|
|---|
| 805 | *errnop = set_error (rc);
|
|---|
| 806 | return -1;
|
|---|
| 807 | }
|
|---|
| 808 | *errnop = 0;
|
|---|
| 809 | return (int)nread;
|
|---|
| 810 | }
|
|---|
| 811 |
|
|---|
| 812 | if (!IS_VALID_FILE (handle))
|
|---|
| 813 | {
|
|---|
| 814 | *errnop = EBADF; /* TODO: last_sock_errno */
|
|---|
| 815 | return -1;
|
|---|
| 816 | }
|
|---|
| 817 |
|
|---|
| 818 | if (len > 0x7fff) len = 0x7ffc;
|
|---|
| 819 | r = tip_recv (GET_FILE (handle)->x.socket.handle, buf, len, flags);
|
|---|
| 820 | if (r == -1)
|
|---|
| 821 | {
|
|---|
| 822 | *errnop = tcpip_errno ();
|
|---|
| 823 | return -1;
|
|---|
| 824 | }
|
|---|
| 825 | *errnop = 0;
|
|---|
| 826 | last_sock_errno = 0;
|
|---|
| 827 | return r;
|
|---|
| 828 | }
|
|---|
| 829 |
|
|---|
| 830 |
|
|---|
| 831 | /* __recvfrom() */
|
|---|
| 832 |
|
|---|
| 833 | int tcpip_recvfrom (const struct _recvfrom *args, int *errnop)
|
|---|
| 834 | {
|
|---|
| 835 | ULONG handle;
|
|---|
| 836 | int r, len;
|
|---|
| 837 |
|
|---|
| 838 | handle = args->handle;
|
|---|
| 839 | if (!IS_SOCKET (handle))
|
|---|
| 840 | {
|
|---|
| 841 | ULONG rc, nread;
|
|---|
| 842 | rc = DosRead (handle, args->buf, (ULONG)args->len, &nread);
|
|---|
| 843 | if (rc != 0)
|
|---|
| 844 | {
|
|---|
| 845 | *errnop = set_error (rc);
|
|---|
| 846 | return -1;
|
|---|
| 847 | }
|
|---|
| 848 | *errnop = 0;
|
|---|
| 849 | return (int)nread;
|
|---|
| 850 | }
|
|---|
| 851 |
|
|---|
| 852 | if (!IS_VALID_FILE (handle))
|
|---|
| 853 | {
|
|---|
| 854 | *errnop = EBADF; /* TODO: last_sock_errno */
|
|---|
| 855 | return -1;
|
|---|
| 856 | }
|
|---|
| 857 |
|
|---|
| 858 | len = args->len;
|
|---|
| 859 | if (len > 0x7fff) len = 0x7ffc;
|
|---|
| 860 | r = tip_recvfrom (GET_FILE (handle)->x.socket.handle, args->buf, len,
|
|---|
| 861 | args->flags, args->from, args->pfromlen);
|
|---|
| 862 | if (r == -1)
|
|---|
| 863 | {
|
|---|
| 864 | *errnop = tcpip_errno ();
|
|---|
| 865 | return -1;
|
|---|
| 866 | }
|
|---|
| 867 | *errnop = 0;
|
|---|
| 868 | last_sock_errno = 0;
|
|---|
| 869 | return r;
|
|---|
| 870 | }
|
|---|
| 871 |
|
|---|
| 872 |
|
|---|
| 873 | /* __send() */
|
|---|
| 874 |
|
|---|
| 875 | int tcpip_send (ULONG handle, const void *buf, int len, unsigned flags,
|
|---|
| 876 | int *errnop)
|
|---|
| 877 | {
|
|---|
| 878 | int r, n, result, e;
|
|---|
| 879 | const char *p;
|
|---|
| 880 |
|
|---|
| 881 | if (!IS_SOCKET (handle))
|
|---|
| 882 | {
|
|---|
| 883 | ULONG rc, nwritten;
|
|---|
| 884 | rc = DosWrite (handle, buf, (ULONG)len, &nwritten);
|
|---|
| 885 | if (rc != 0)
|
|---|
| 886 | {
|
|---|
| 887 | *errnop = set_error (rc);
|
|---|
| 888 | return -1;
|
|---|
| 889 | }
|
|---|
| 890 | *errnop = 0;
|
|---|
| 891 | return (int)nwritten;
|
|---|
| 892 | }
|
|---|
| 893 |
|
|---|
| 894 | if (!IS_VALID_FILE (handle))
|
|---|
| 895 | {
|
|---|
| 896 | *errnop = EBADF; /* TODO: last_sock_errno */
|
|---|
| 897 | return -1;
|
|---|
| 898 | }
|
|---|
| 899 |
|
|---|
| 900 | /* TODO: Return EMSGSIZE if appropriate. */
|
|---|
| 901 |
|
|---|
| 902 | p = buf; result = 0;
|
|---|
| 903 | while (len > 0)
|
|---|
| 904 | {
|
|---|
| 905 | n = (len > 0x7fff ? 0x7ffc : len);
|
|---|
| 906 | r = tip_send (GET_FILE (handle)->x.socket.handle, p, n, flags);
|
|---|
| 907 | if (r == -1)
|
|---|
| 908 | {
|
|---|
| 909 | e = tcpip_errno ();
|
|---|
| 910 | if (e == EWOULDBLOCK && result != 0)
|
|---|
| 911 | break;
|
|---|
| 912 | *errnop = e;
|
|---|
| 913 | return -1;
|
|---|
| 914 | }
|
|---|
| 915 | result += r;
|
|---|
| 916 | if (r != n) break;
|
|---|
| 917 | p += r; len -= r;
|
|---|
| 918 | }
|
|---|
| 919 |
|
|---|
| 920 | *errnop = 0;
|
|---|
| 921 | last_sock_errno = 0;
|
|---|
| 922 | return result;
|
|---|
| 923 | }
|
|---|
| 924 |
|
|---|
| 925 |
|
|---|
| 926 | /* __sendto() */
|
|---|
| 927 |
|
|---|
| 928 | int tcpip_sendto (const struct _sendto *args, int *errnop)
|
|---|
| 929 | {
|
|---|
| 930 | ULONG handle;
|
|---|
| 931 | int r, len, n, result, e;
|
|---|
| 932 | const char *p;
|
|---|
| 933 |
|
|---|
| 934 | handle = args->handle;
|
|---|
| 935 | if (!IS_SOCKET (handle))
|
|---|
| 936 | {
|
|---|
| 937 | ULONG rc, nwritten;
|
|---|
| 938 | rc = DosWrite (handle, args->buf, (ULONG)args->len, &nwritten);
|
|---|
| 939 | if (rc != 0)
|
|---|
| 940 | {
|
|---|
| 941 | *errnop = set_error (rc);
|
|---|
| 942 | return -1;
|
|---|
| 943 | }
|
|---|
| 944 | *errnop = 0;
|
|---|
| 945 | return (int)nwritten;
|
|---|
| 946 | }
|
|---|
| 947 |
|
|---|
| 948 | if (!IS_VALID_FILE (handle))
|
|---|
| 949 | {
|
|---|
| 950 | *errnop = EBADF; /* TODO: last_sock_errno */
|
|---|
| 951 | return -1;
|
|---|
| 952 | }
|
|---|
| 953 |
|
|---|
| 954 | /* TODO: Return EMSGSIZE if appropriate. */
|
|---|
| 955 |
|
|---|
| 956 | p = args->buf; result = 0; len = args->len;
|
|---|
| 957 | while (len > 0)
|
|---|
| 958 | {
|
|---|
| 959 | n = (len > 0x7fff ? 0x7ffc : len);
|
|---|
| 960 | r = tip_sendto (GET_FILE (handle)->x.socket.handle, p, n, args->flags,
|
|---|
| 961 | args->to, args->tolen);
|
|---|
| 962 | if (r == -1)
|
|---|
| 963 | {
|
|---|
| 964 | e = tcpip_errno ();
|
|---|
| 965 | if (e == EWOULDBLOCK && result != 0)
|
|---|
| 966 | break;
|
|---|
| 967 | *errnop = e;
|
|---|
| 968 | return -1;
|
|---|
| 969 | }
|
|---|
| 970 | result += r;
|
|---|
| 971 | if (r != n) break;
|
|---|
| 972 | p += r; len -= r;
|
|---|
| 973 | }
|
|---|
| 974 |
|
|---|
| 975 | *errnop = 0;
|
|---|
| 976 | last_sock_errno = 0;
|
|---|
| 977 | return result;
|
|---|
| 978 | }
|
|---|
| 979 |
|
|---|
| 980 |
|
|---|
| 981 | /* __close() for a socket handle. First adjust the local reference
|
|---|
| 982 | count. If it becomes zero, call tcpip_close_process() to adjust
|
|---|
| 983 | the global reference count and to close the socket if it becomes
|
|---|
| 984 | zero. */
|
|---|
| 985 |
|
|---|
| 986 | int tcpip_close (ULONG handle)
|
|---|
| 987 | {
|
|---|
| 988 | if (!IS_VALID_FILE (handle))
|
|---|
| 989 | return EBADF;
|
|---|
| 990 | if (GET_FILE (handle)->ref_count == 1)
|
|---|
| 991 | {
|
|---|
| 992 | if (tcpip_close_process (GET_FILE (handle)->x.socket.handle) != 0)
|
|---|
| 993 | return tcpip_errno ();
|
|---|
| 994 | }
|
|---|
| 995 | close_handle (handle);
|
|---|
| 996 | last_sock_errno = 0;
|
|---|
| 997 | return 0;
|
|---|
| 998 | }
|
|---|
| 999 |
|
|---|
| 1000 |
|
|---|
| 1001 | /* __dup() for a socket handle. The target handle has already been
|
|---|
| 1002 | closed unless both HANDLE and TARGET are equal. */
|
|---|
| 1003 |
|
|---|
| 1004 | int tcpip_dup (ULONG handle, ULONG target, int *errnop)
|
|---|
| 1005 | {
|
|---|
| 1006 | int i;
|
|---|
| 1007 |
|
|---|
| 1008 | if (!IS_VALID_FILE (handle))
|
|---|
| 1009 | {
|
|---|
| 1010 | *errnop = EBADF;
|
|---|
| 1011 | return -1;
|
|---|
| 1012 | }
|
|---|
| 1013 | if (target == (ULONG)(-1))
|
|---|
| 1014 | {
|
|---|
| 1015 | LOCK_FILES;
|
|---|
| 1016 | for (i = 0; i < handle_count; ++i)
|
|---|
| 1017 | if (!(handle_flags[i] & HF_OPEN))
|
|---|
| 1018 | {
|
|---|
| 1019 | handle_flags[i] = handle_flags[handle];
|
|---|
| 1020 | handle_file[i] = handle_file[handle];
|
|---|
| 1021 | GET_FILE(handle)->ref_count += 1;
|
|---|
| 1022 | UNLOCK_FILES;
|
|---|
| 1023 | *errnop = 0;
|
|---|
| 1024 | return i;
|
|---|
| 1025 | }
|
|---|
| 1026 | UNLOCK_FILES;
|
|---|
| 1027 | *errnop = EMFILE;
|
|---|
| 1028 | return -1;
|
|---|
| 1029 | }
|
|---|
| 1030 | else if (handle == target)
|
|---|
| 1031 | {
|
|---|
| 1032 | *errnop = 0;
|
|---|
| 1033 | return target;
|
|---|
| 1034 | }
|
|---|
| 1035 | else if (target >= handle_count)
|
|---|
| 1036 | {
|
|---|
| 1037 | *errnop = EBADF;
|
|---|
| 1038 | return -1;
|
|---|
| 1039 | }
|
|---|
| 1040 | else
|
|---|
| 1041 | {
|
|---|
| 1042 | do_close (target);
|
|---|
| 1043 | handle_flags[target] = handle_flags[handle];
|
|---|
| 1044 | handle_file[target] = handle_file[handle];
|
|---|
| 1045 | GET_FILE(handle)->ref_count += 1;
|
|---|
| 1046 | *errnop = 0;
|
|---|
| 1047 | return target;
|
|---|
| 1048 | }
|
|---|
| 1049 | }
|
|---|
| 1050 |
|
|---|
| 1051 |
|
|---|
| 1052 | /* __read() for a socket handle. */
|
|---|
| 1053 |
|
|---|
| 1054 | int tcpip_read (ULONG handle, void *buf, ULONG len, int *errnop)
|
|---|
| 1055 | {
|
|---|
| 1056 | int rc;
|
|---|
| 1057 |
|
|---|
| 1058 | if (len > 0x7fff) len = 0x7ffc;
|
|---|
| 1059 | rc = tip_recv (GET_FILE (handle)->x.socket.handle, buf, len, 0);
|
|---|
| 1060 | if (rc == -1)
|
|---|
| 1061 | {
|
|---|
| 1062 | *errnop = tcpip_errno ();
|
|---|
| 1063 | return -1;
|
|---|
| 1064 | }
|
|---|
| 1065 | *errnop = 0;
|
|---|
| 1066 | last_sock_errno = 0;
|
|---|
| 1067 | return rc;
|
|---|
| 1068 | }
|
|---|
| 1069 |
|
|---|
| 1070 |
|
|---|
| 1071 | /* __write() for a socket handle. */
|
|---|
| 1072 |
|
|---|
| 1073 | int tcpip_write (ULONG handle, const void *buf, ULONG len, int *errnop)
|
|---|
| 1074 | {
|
|---|
| 1075 | int rc, n, result, e;
|
|---|
| 1076 | const char *p;
|
|---|
| 1077 |
|
|---|
| 1078 | p = buf; result = 0;
|
|---|
| 1079 | while (len > 0)
|
|---|
| 1080 | {
|
|---|
| 1081 | n = (len > 0x7fff ? 0x7ffc : len);
|
|---|
| 1082 | rc = tip_send (GET_FILE (handle)->x.socket.handle, p, n, 0);
|
|---|
| 1083 | if (rc == -1)
|
|---|
| 1084 | {
|
|---|
| 1085 | e = tcpip_errno ();
|
|---|
| 1086 | if (e == EWOULDBLOCK && result != 0)
|
|---|
| 1087 | break;
|
|---|
| 1088 | *errnop = e;
|
|---|
| 1089 | return -1;
|
|---|
| 1090 | }
|
|---|
| 1091 | result += rc;
|
|---|
| 1092 | if (rc != n) break;
|
|---|
| 1093 | p += rc; len -= rc;
|
|---|
| 1094 | }
|
|---|
| 1095 | *errnop = 0;
|
|---|
| 1096 | last_sock_errno = 0;
|
|---|
| 1097 | return result;
|
|---|
| 1098 | }
|
|---|
| 1099 |
|
|---|
| 1100 |
|
|---|
| 1101 | /* __fstat() for a socket handle. */
|
|---|
| 1102 |
|
|---|
| 1103 | int tcpip_fstat (ULONG handle, struct stat *dst, int *errnop)
|
|---|
| 1104 | {
|
|---|
| 1105 | memset (dst, 0, sizeof (struct stat));
|
|---|
| 1106 | dst->st_mode = MAKEPERM (S_IREAD|S_IWRITE);
|
|---|
| 1107 | dst->st_mode |= S_IFSOCK;
|
|---|
| 1108 | dst->st_size = 0;
|
|---|
| 1109 | dst->st_dev = 0;
|
|---|
| 1110 | dst->st_uid = 0; /* root */
|
|---|
| 1111 | dst->st_gid = 0; /* root */
|
|---|
| 1112 | dst->st_ino = ino_number;
|
|---|
| 1113 | if (++ino_number == 0)
|
|---|
| 1114 | ino_number = 1;
|
|---|
| 1115 | dst->st_rdev = dst->st_dev;
|
|---|
| 1116 | dst->st_nlink = 1;
|
|---|
| 1117 | *errnop = 0;
|
|---|
| 1118 | return 0;
|
|---|
| 1119 | }
|
|---|
| 1120 |
|
|---|
| 1121 |
|
|---|
| 1122 | /* Call ioctl() of IBM TCP/IP for OS/2. */
|
|---|
| 1123 |
|
|---|
| 1124 | static int map_ioctl (ULONG handle, ULONG request, ULONG arg, ULONG datalen,
|
|---|
| 1125 | int *errnop)
|
|---|
| 1126 | {
|
|---|
| 1127 | int rc;
|
|---|
| 1128 |
|
|---|
| 1129 | rc = tip_ioctl (GET_FILE (handle)->x.socket.handle, request,
|
|---|
| 1130 | (void *)arg, datalen);
|
|---|
| 1131 | if (rc == -1)
|
|---|
| 1132 | {
|
|---|
| 1133 | *errnop = tcpip_errno ();
|
|---|
| 1134 | return -1;
|
|---|
| 1135 | }
|
|---|
| 1136 | *errnop = 0;
|
|---|
| 1137 | return rc;
|
|---|
| 1138 | }
|
|---|
| 1139 |
|
|---|
| 1140 |
|
|---|
| 1141 | /* __ioctl() for a socket handle. */
|
|---|
| 1142 |
|
|---|
| 1143 | int tcpip_ioctl (ULONG handle, ULONG request, ULONG arg, int *errnop)
|
|---|
| 1144 | {
|
|---|
| 1145 | int rc;
|
|---|
| 1146 |
|
|---|
| 1147 | if (!IS_VALID_FILE (handle))
|
|---|
| 1148 | {
|
|---|
| 1149 | *errnop = EBADF;
|
|---|
| 1150 | return -1;
|
|---|
| 1151 | }
|
|---|
| 1152 |
|
|---|
| 1153 | switch (request)
|
|---|
| 1154 | {
|
|---|
| 1155 | case TCGETA:
|
|---|
| 1156 | case TCSETA:
|
|---|
| 1157 | case TCSETAF:
|
|---|
| 1158 | case TCSETAW:
|
|---|
| 1159 | case TCFLSH:
|
|---|
| 1160 | case TCSBRK:
|
|---|
| 1161 | case TCXONC:
|
|---|
| 1162 | case _TCGA:
|
|---|
| 1163 | case _TCSANOW:
|
|---|
| 1164 | case _TCSADRAIN:
|
|---|
| 1165 | case _TCSAFLUSH:
|
|---|
| 1166 |
|
|---|
| 1167 | /* These requests are not yet implemented. */
|
|---|
| 1168 |
|
|---|
| 1169 | *errnop = EINVAL;
|
|---|
| 1170 | return -1;
|
|---|
| 1171 |
|
|---|
| 1172 | case FGETHTYPE:
|
|---|
| 1173 |
|
|---|
| 1174 | *(int *)arg = HT_SOCKET;
|
|---|
| 1175 | *errnop = 0;
|
|---|
| 1176 | return 0;
|
|---|
| 1177 |
|
|---|
| 1178 | case FIONREAD:
|
|---|
| 1179 |
|
|---|
| 1180 | return map_ioctl (handle, _TCPIP_FIONREAD, arg, sizeof (int), errnop);
|
|---|
| 1181 |
|
|---|
| 1182 | case FIOASYNC:
|
|---|
| 1183 | case SIOCATMARK:
|
|---|
| 1184 |
|
|---|
| 1185 | return map_ioctl (handle, request, arg, sizeof (int), errnop);
|
|---|
| 1186 |
|
|---|
| 1187 | case SIOCADDRT:
|
|---|
| 1188 | case SIOCDELRT:
|
|---|
| 1189 |
|
|---|
| 1190 | return map_ioctl (handle, request, arg, sizeof (struct rtentry), errnop);
|
|---|
| 1191 |
|
|---|
| 1192 | case SIOCDARP:
|
|---|
| 1193 | case SIOCGARP:
|
|---|
| 1194 | case SIOCSARP:
|
|---|
| 1195 |
|
|---|
| 1196 | return map_ioctl (handle, request, arg, sizeof (struct arpreq), errnop);
|
|---|
| 1197 |
|
|---|
| 1198 | case SIOCGIFADDR:
|
|---|
| 1199 | case SIOCGIFBRDADDR:
|
|---|
| 1200 | case SIOCGIFDSTADDR:
|
|---|
| 1201 | case SIOCGIFFLAGS:
|
|---|
| 1202 | case SIOCGIFMETRIC:
|
|---|
| 1203 | case SIOCGIFNETMASK:
|
|---|
| 1204 | case SIOCSIFADDR:
|
|---|
| 1205 | case SIOCSIFBRDADDR:
|
|---|
| 1206 | case SIOCSIFDSTADDR:
|
|---|
| 1207 | case SIOCSIFFLAGS:
|
|---|
| 1208 | case SIOCSIFMETRIC:
|
|---|
| 1209 | case SIOCSIFNETMASK:
|
|---|
| 1210 |
|
|---|
| 1211 | return map_ioctl (handle, request, arg, sizeof (struct ifreq), errnop);
|
|---|
| 1212 |
|
|---|
| 1213 | case SIOCGIFCONF:
|
|---|
| 1214 |
|
|---|
| 1215 | return map_ioctl (handle, request, arg, sizeof (struct ifconf), errnop);
|
|---|
| 1216 |
|
|---|
| 1217 | case FIONBIO:
|
|---|
| 1218 | rc = map_ioctl (handle, request, arg, sizeof (int), errnop);
|
|---|
| 1219 | if (rc == 0)
|
|---|
| 1220 | {
|
|---|
| 1221 | if (*(int *)arg)
|
|---|
| 1222 | handle_flags[handle] |= HF_NDELAY;
|
|---|
| 1223 | else
|
|---|
| 1224 | handle_flags[handle] &= ~HF_NDELAY;
|
|---|
| 1225 | }
|
|---|
| 1226 | return rc;
|
|---|
| 1227 |
|
|---|
| 1228 | default:
|
|---|
| 1229 | *errnop = EINVAL;
|
|---|
| 1230 | return -1;
|
|---|
| 1231 | }
|
|---|
| 1232 | }
|
|---|
| 1233 |
|
|---|
| 1234 |
|
|---|
| 1235 | /* __fcntl() for a socket handle. This function is called for F_SETFL
|
|---|
| 1236 | only, and only if O_NDELAY was changed. */
|
|---|
| 1237 |
|
|---|
| 1238 | int tcpip_fcntl (ULONG handle, ULONG request, ULONG arg, int *errnop)
|
|---|
| 1239 | {
|
|---|
| 1240 | int on;
|
|---|
| 1241 |
|
|---|
| 1242 | on = arg & O_NDELAY;
|
|---|
| 1243 | return tcpip_ioctl (handle, FIONBIO, (ULONG)&on, errnop);
|
|---|
| 1244 | }
|
|---|
| 1245 |
|
|---|
| 1246 |
|
|---|
| 1247 | /* __getsockopt() */
|
|---|
| 1248 |
|
|---|
| 1249 | int tcpip_getsockopt (ULONG handle, int level, int optname, void *optval,
|
|---|
| 1250 | int *poptlen)
|
|---|
| 1251 | {
|
|---|
| 1252 | int rc;
|
|---|
| 1253 |
|
|---|
| 1254 | if (!IS_SOCKET (handle) || !IS_VALID_FILE (handle))
|
|---|
| 1255 | return ENOTSOCK; /* TODO: last_sock_errno */
|
|---|
| 1256 |
|
|---|
| 1257 | rc = tip_getsockopt (GET_FILE (handle)->x.socket.handle, level, optname,
|
|---|
| 1258 | optval, poptlen);
|
|---|
| 1259 | if (rc == -1)
|
|---|
| 1260 | return tcpip_errno ();
|
|---|
| 1261 | last_sock_errno = 0;
|
|---|
| 1262 | return 0;
|
|---|
| 1263 | }
|
|---|
| 1264 |
|
|---|
| 1265 |
|
|---|
| 1266 | /* __setsockopt() */
|
|---|
| 1267 |
|
|---|
| 1268 | int tcpip_setsockopt (ULONG handle, int level, int optname, const void *optval,
|
|---|
| 1269 | int optlen)
|
|---|
| 1270 | {
|
|---|
| 1271 | int rc;
|
|---|
| 1272 |
|
|---|
| 1273 | if (!IS_SOCKET (handle) || !IS_VALID_FILE (handle))
|
|---|
| 1274 | return ENOTSOCK; /* TODO: last_sock_errno */
|
|---|
| 1275 |
|
|---|
| 1276 | rc = tip_setsockopt (GET_FILE (handle)->x.socket.handle, level, optname,
|
|---|
| 1277 | optval, optlen);
|
|---|
| 1278 | if (rc == -1)
|
|---|
| 1279 | return tcpip_errno ();
|
|---|
| 1280 | last_sock_errno = 0;
|
|---|
| 1281 | return 0;
|
|---|
| 1282 | }
|
|---|
| 1283 |
|
|---|
| 1284 |
|
|---|
| 1285 | /* __getsockname() */
|
|---|
| 1286 |
|
|---|
| 1287 | int tcpip_getsockname (ULONG handle, void *addr, int *paddrlen)
|
|---|
| 1288 | {
|
|---|
| 1289 | int rc;
|
|---|
| 1290 |
|
|---|
| 1291 | if (!IS_SOCKET (handle) || !IS_VALID_FILE (handle))
|
|---|
| 1292 | return ENOTSOCK; /* TODO: last_sock_errno */
|
|---|
| 1293 |
|
|---|
| 1294 | rc = tip_getsockname (GET_FILE (handle)->x.socket.handle, addr, paddrlen);
|
|---|
| 1295 | if (rc == -1)
|
|---|
| 1296 | return tcpip_errno ();
|
|---|
| 1297 | last_sock_errno = 0;
|
|---|
| 1298 | return 0;
|
|---|
| 1299 | }
|
|---|
| 1300 |
|
|---|
| 1301 |
|
|---|
| 1302 | /* __shutdown() */
|
|---|
| 1303 |
|
|---|
| 1304 | int tcpip_shutdown (ULONG handle, int how)
|
|---|
| 1305 | {
|
|---|
| 1306 | int rc;
|
|---|
| 1307 |
|
|---|
| 1308 | if (!IS_SOCKET (handle) || !IS_VALID_FILE (handle))
|
|---|
| 1309 | return ENOTSOCK; /* TODO: last_sock_errno */
|
|---|
| 1310 |
|
|---|
| 1311 | rc = tip_shutdown (GET_FILE (handle)->x.socket.handle, how);
|
|---|
| 1312 | if (rc != 0)
|
|---|
| 1313 | return tcpip_errno ();
|
|---|
| 1314 | last_sock_errno = 0;
|
|---|
| 1315 | return 0;
|
|---|
| 1316 | }
|
|---|
| 1317 |
|
|---|
| 1318 |
|
|---|
| 1319 | /* __getpeername() */
|
|---|
| 1320 |
|
|---|
| 1321 | int tcpip_getpeername (ULONG handle, void *addr, int *paddrlen)
|
|---|
| 1322 | {
|
|---|
| 1323 | int rc;
|
|---|
| 1324 |
|
|---|
| 1325 | if (!IS_SOCKET (handle) || !IS_VALID_FILE (handle))
|
|---|
| 1326 | return ENOTSOCK; /* TODO: last_sock_errno */
|
|---|
| 1327 |
|
|---|
| 1328 | rc = tip_getpeername (GET_FILE (handle)->x.socket.handle, addr, paddrlen);
|
|---|
| 1329 | if (rc == -1)
|
|---|
| 1330 | return tcpip_errno ();
|
|---|
| 1331 | last_sock_errno = 0;
|
|---|
| 1332 | return 0;
|
|---|
| 1333 | }
|
|---|
| 1334 |
|
|---|
| 1335 |
|
|---|
| 1336 | /* __gethostbyname() */
|
|---|
| 1337 |
|
|---|
| 1338 | int tcpip_gethostbyname (const char *name, void **dst)
|
|---|
| 1339 | {
|
|---|
| 1340 | void *p;
|
|---|
| 1341 |
|
|---|
| 1342 | if (!tcpip_init ())
|
|---|
| 1343 | return NO_RECOVERY;
|
|---|
| 1344 |
|
|---|
| 1345 | p = tip_gethostbyname (name);
|
|---|
| 1346 | *dst = p;
|
|---|
| 1347 | if (p == NULL)
|
|---|
| 1348 | {
|
|---|
| 1349 | /* h_errno seems to be always zero. Bug? */
|
|---|
| 1350 |
|
|---|
| 1351 | if (*tip_h_errno == 0)
|
|---|
| 1352 | return NO_RECOVERY;
|
|---|
| 1353 | else
|
|---|
| 1354 | return *tip_h_errno;
|
|---|
| 1355 | }
|
|---|
| 1356 | else
|
|---|
| 1357 | return 0;
|
|---|
| 1358 | }
|
|---|
| 1359 |
|
|---|
| 1360 |
|
|---|
| 1361 | /* __gethostbyaddr() */
|
|---|
| 1362 |
|
|---|
| 1363 | int tcpip_gethostbyaddr (const char *addr, int len, int type, void **dst)
|
|---|
| 1364 | {
|
|---|
| 1365 | void *p;
|
|---|
| 1366 |
|
|---|
| 1367 | if (!tcpip_init ())
|
|---|
| 1368 | return NO_RECOVERY;
|
|---|
| 1369 |
|
|---|
| 1370 | p = tip_gethostbyaddr (addr, len, type);
|
|---|
| 1371 | *dst = p;
|
|---|
| 1372 | if (p == NULL)
|
|---|
| 1373 | {
|
|---|
| 1374 | /* h_errno seems to be always zero. Bug? */
|
|---|
| 1375 |
|
|---|
| 1376 | if (*tip_h_errno == 0)
|
|---|
| 1377 | return NO_RECOVERY;
|
|---|
| 1378 | else
|
|---|
| 1379 | return *tip_h_errno;
|
|---|
| 1380 | }
|
|---|
| 1381 | else
|
|---|
| 1382 | return 0;
|
|---|
| 1383 | }
|
|---|
| 1384 |
|
|---|
| 1385 |
|
|---|
| 1386 | /* __getservbyname() */
|
|---|
| 1387 |
|
|---|
| 1388 | int tcpip_getservbyname (const char *name, const char *proto, void **dst)
|
|---|
| 1389 | {
|
|---|
| 1390 | void *p;
|
|---|
| 1391 |
|
|---|
| 1392 | if (!tcpip_init ())
|
|---|
| 1393 | return -1;
|
|---|
| 1394 |
|
|---|
| 1395 | p = tip_getservbyname (name, proto);
|
|---|
| 1396 | *dst = p;
|
|---|
| 1397 | return (p != NULL ? 0 : -1);
|
|---|
| 1398 | }
|
|---|
| 1399 |
|
|---|
| 1400 |
|
|---|
| 1401 | /* __getservbyport() */
|
|---|
| 1402 |
|
|---|
| 1403 | int tcpip_getservbyport (int port, const char *proto, void **dst)
|
|---|
| 1404 | {
|
|---|
| 1405 | void *p;
|
|---|
| 1406 |
|
|---|
| 1407 | if (!tcpip_init ())
|
|---|
| 1408 | return -1;
|
|---|
| 1409 |
|
|---|
| 1410 | p = tip_getservbyport (port, proto);
|
|---|
| 1411 | *dst = p;
|
|---|
| 1412 | return (p != NULL ? 0 : -1);
|
|---|
| 1413 | }
|
|---|
| 1414 |
|
|---|
| 1415 |
|
|---|
| 1416 | /* __gethostid() */
|
|---|
| 1417 |
|
|---|
| 1418 | int tcpip_gethostid (int *dst)
|
|---|
| 1419 | {
|
|---|
| 1420 | if (!tcpip_init ())
|
|---|
| 1421 | return ENETDOWN;
|
|---|
| 1422 |
|
|---|
| 1423 | *dst = tip_gethostid ();
|
|---|
| 1424 | last_sock_errno = 0;
|
|---|
| 1425 | return 0;
|
|---|
| 1426 | }
|
|---|
| 1427 |
|
|---|
| 1428 |
|
|---|
| 1429 | /* __gethostname() */
|
|---|
| 1430 |
|
|---|
| 1431 | int tcpip_gethostname (char *name, int len)
|
|---|
| 1432 | {
|
|---|
| 1433 | int rc;
|
|---|
| 1434 |
|
|---|
| 1435 | /* TODO: Get hostname from environment variable if the net is
|
|---|
| 1436 | down. */
|
|---|
| 1437 |
|
|---|
| 1438 | if (!tcpip_init ())
|
|---|
| 1439 | return ENETDOWN;
|
|---|
| 1440 |
|
|---|
| 1441 | /* If HOSTNAME is not set, IBM's gethostname() simply leaves the
|
|---|
| 1442 | buffer alone! */
|
|---|
| 1443 |
|
|---|
| 1444 | *name = 0;
|
|---|
| 1445 |
|
|---|
| 1446 | rc = tip_gethostname (name, len);
|
|---|
| 1447 | if (rc != 0)
|
|---|
| 1448 | return tcpip_errno ();
|
|---|
| 1449 | last_sock_errno = 0;
|
|---|
| 1450 | return 0;
|
|---|
| 1451 | }
|
|---|
| 1452 |
|
|---|
| 1453 |
|
|---|
| 1454 | /* __getprotobyname() */
|
|---|
| 1455 |
|
|---|
| 1456 | int tcpip_getprotobyname (const char *name, void **dst)
|
|---|
| 1457 | {
|
|---|
| 1458 | void *p;
|
|---|
| 1459 |
|
|---|
| 1460 | if (!tcpip_init ())
|
|---|
| 1461 | return -1;
|
|---|
| 1462 |
|
|---|
| 1463 | p = tip_getprotobyname (name);
|
|---|
| 1464 | *dst = p;
|
|---|
| 1465 | return (p != NULL ? 0 : -1);
|
|---|
| 1466 | }
|
|---|
| 1467 |
|
|---|
| 1468 |
|
|---|
| 1469 | /* __getprotobynumber() */
|
|---|
| 1470 |
|
|---|
| 1471 | int tcpip_getprotobynumber (int proto, void **dst)
|
|---|
| 1472 | {
|
|---|
| 1473 | void *p;
|
|---|
| 1474 |
|
|---|
| 1475 | if (!tcpip_init ())
|
|---|
| 1476 | return -1;
|
|---|
| 1477 |
|
|---|
| 1478 | p = tip_getprotobynumber (proto);
|
|---|
| 1479 | *dst = p;
|
|---|
| 1480 | return (p != NULL ? 0 : -1);
|
|---|
| 1481 | }
|
|---|
| 1482 |
|
|---|
| 1483 |
|
|---|
| 1484 | /* __getnetbyname() */
|
|---|
| 1485 |
|
|---|
| 1486 | int tcpip_getnetbyname (const char *name, void **dst)
|
|---|
| 1487 | {
|
|---|
| 1488 | void *p;
|
|---|
| 1489 |
|
|---|
| 1490 | if (!tcpip_init ())
|
|---|
| 1491 | return -1;
|
|---|
| 1492 |
|
|---|
| 1493 | p = tip_getnetbyname (name);
|
|---|
| 1494 | *dst = p;
|
|---|
| 1495 | return (p != NULL ? 0 : -1);
|
|---|
| 1496 | }
|
|---|
| 1497 |
|
|---|
| 1498 |
|
|---|
| 1499 | /* __getnetbyaddr() */
|
|---|
| 1500 |
|
|---|
| 1501 | int tcpip_getnetbyaddr (long net, void **dst)
|
|---|
| 1502 | {
|
|---|
| 1503 | void *p;
|
|---|
| 1504 |
|
|---|
| 1505 | if (!tcpip_init ())
|
|---|
| 1506 | return -1;
|
|---|
| 1507 |
|
|---|
| 1508 | p = tip_getnetbyaddr (net);
|
|---|
| 1509 | *dst = p;
|
|---|
| 1510 | return (p != NULL ? 0 : -1);
|
|---|
| 1511 | }
|
|---|
| 1512 |
|
|---|
| 1513 |
|
|---|
| 1514 | /* __impsockhandle() */
|
|---|
| 1515 |
|
|---|
| 1516 | int tcpip_impsockhandle (ULONG handle, ULONG flags, int *errnop)
|
|---|
| 1517 | {
|
|---|
| 1518 | int result, optlen, optval;
|
|---|
| 1519 | ULONG i;
|
|---|
| 1520 |
|
|---|
| 1521 | if (!tcpip_init ())
|
|---|
| 1522 | {
|
|---|
| 1523 | *errnop = ENETDOWN;
|
|---|
| 1524 | return -1;
|
|---|
| 1525 | }
|
|---|
| 1526 |
|
|---|
| 1527 | if (flags != 0)
|
|---|
| 1528 | {
|
|---|
| 1529 | *errnop = EINVAL;
|
|---|
| 1530 | return -1;
|
|---|
| 1531 | }
|
|---|
| 1532 |
|
|---|
| 1533 | /* Check if HANDLE is a known socket handle of this process. */
|
|---|
| 1534 |
|
|---|
| 1535 | LOCK_FILES;
|
|---|
| 1536 | for (i = 0; i < handle_count; ++i)
|
|---|
| 1537 | if (IS_SOCKET (i) && IS_VALID_FILE (i)
|
|---|
| 1538 | && GET_FILE (i)->x.socket.handle == handle)
|
|---|
| 1539 | {
|
|---|
| 1540 | GET_FILE (i)->ref_count += 1;
|
|---|
| 1541 | UNLOCK_FILES;
|
|---|
| 1542 | *errnop = 0;
|
|---|
| 1543 | return i;
|
|---|
| 1544 | }
|
|---|
| 1545 |
|
|---|
| 1546 | /* HANDLE is not a known socket handle of this process. Check if
|
|---|
| 1547 | it's actually a socket handle. */
|
|---|
| 1548 |
|
|---|
| 1549 | optlen = sizeof (optval);
|
|---|
| 1550 | if (tip_getsockopt (handle, SOL_SOCKET, SO_TYPE, &optval, &optlen) != 0)
|
|---|
| 1551 | {
|
|---|
| 1552 | UNLOCK_FILES;
|
|---|
| 1553 | *errnop = ENOTSOCK;
|
|---|
| 1554 | return -1;
|
|---|
| 1555 | }
|
|---|
| 1556 |
|
|---|
| 1557 | /* It's an entirely new socket handle. Install it in SO32DLL.DLL's
|
|---|
| 1558 | tables and in our tables. */
|
|---|
| 1559 |
|
|---|
| 1560 | tip_addsockettolist (handle);
|
|---|
| 1561 | result = tcpip_new_handle (handle, errnop);
|
|---|
| 1562 | if (result == -1)
|
|---|
| 1563 | tip_removesocketfromlist (handle);
|
|---|
| 1564 | UNLOCK_FILES;
|
|---|
| 1565 | return result;
|
|---|
| 1566 | }
|
|---|
| 1567 |
|
|---|
| 1568 |
|
|---|
| 1569 | /* Poll socket handles for __select(). Update the bitstrings if a
|
|---|
| 1570 | handle is ready. */
|
|---|
| 1571 |
|
|---|
| 1572 | int tcpip_select_poll (struct select_data *d, int *errnop)
|
|---|
| 1573 | {
|
|---|
| 1574 | int i, j, n;
|
|---|
| 1575 |
|
|---|
| 1576 | memcpy (d->sockett, d->sockets, d->socket_count * sizeof (int));
|
|---|
| 1577 | n = tip_select (d->sockett, d->socket_nread, d->socket_nwrite,
|
|---|
| 1578 | d->socket_nexcept, 0);
|
|---|
| 1579 | if (n < 0)
|
|---|
| 1580 | {
|
|---|
| 1581 | *errnop = tcpip_errno ();
|
|---|
| 1582 | return -1;
|
|---|
| 1583 | }
|
|---|
| 1584 | if (n == 0)
|
|---|
| 1585 | return 0;
|
|---|
| 1586 | j = 0; n = 0;
|
|---|
| 1587 | for (i = 0; i < d->socket_nread; ++i, ++j)
|
|---|
| 1588 | if (d->sockett[j] != -1)
|
|---|
| 1589 | {
|
|---|
| 1590 | FD_SET (d->socketh[j], d->rbits);
|
|---|
| 1591 | n = 1;
|
|---|
| 1592 | }
|
|---|
| 1593 | for (i = 0; i < d->socket_nwrite; ++i, ++j)
|
|---|
| 1594 | if (d->sockett[j] != -1)
|
|---|
| 1595 | {
|
|---|
| 1596 | FD_SET (d->socketh[j], d->wbits);
|
|---|
| 1597 | n = 1;
|
|---|
| 1598 | }
|
|---|
| 1599 | for (i = 0; i < d->socket_nexcept; ++i, ++j)
|
|---|
| 1600 | if (d->sockett[j] != -1)
|
|---|
| 1601 | {
|
|---|
| 1602 | FD_SET (d->socketh[j], d->ebits);
|
|---|
| 1603 | n = 1;
|
|---|
| 1604 | }
|
|---|
| 1605 | *errnop = 0;
|
|---|
| 1606 | d->ready_flag = TRUE;
|
|---|
| 1607 | return n;
|
|---|
| 1608 | }
|
|---|