source: vendor/emx/current/src/os2/tcpip.c

Last change on this file was 18, checked in by bird, 22 years ago

Initial revision

  • Property cvs2svn:cvs-rev set to 1.1
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 39.3 KB
Line 
1/* tcpip.c -- TCP/IP
2 Copyright (c) 1994-2000 by Eberhard Mattes
3
4This file is part of emx.
5
6emx is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11emx is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with emx; see the file COPYING. If not, write to
18the Free Software Foundation, 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA.
20
21As special exception, emx.dll can be distributed without source code
22unless it has been changed. If you modify emx.dll, this exception
23no longer applies and you must remove this paragraph from all source
24files 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
64static 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
70static int last_sock_errno;
71
72/* Module handles of the two IBM TCP/IP for OS/2 DLLs. */
73
74static HMODULE hmod_so32dll;
75static HMODULE hmod_tcp32dll;
76
77/* List of file handles created by sock_init(). This is used for
78 fork(). */
79
80static ULONG sock_init_count;
81static ULONG sock_init_array[MAXFH_SOCK_INIT];
82
83struct sockaddr;
84
85/* Pointers to entrypoints of the IBM TCP/IP for OS/2 DLLs. */
86
87static int (*tip_accept)(int, struct sockaddr *, int *);
88static void (*tip_addsockettolist)(int);
89static int (*tip_bind)(int, struct sockaddr *, int);
90static int (*tip_connect)(int, struct sockaddr *, int);
91static void * (*tip_gethostbyaddr) (const char *, int, int);
92static void * (*tip_gethostbyname) (const char *);
93static int (*tip_gethostid) (void);
94static int (*tip_gethostname) (char *, int len);
95static void * (*tip_getnetbyaddr) (long);
96static void * (*tip_getnetbyname) (const char *);
97static int (*tip_getpeername) (int, void *, int *);
98static void * (*tip_getprotobyname) (const char *);
99static void * (*tip_getprotobynumber) (int);
100static void * (*tip_getservbyname) (const char *, const char *);
101static void * (*tip_getservbyport) (int, const char *);
102static int (*tip_getsockname) (int, void *, int *);
103static int (*tip_getsockopt) (int, int, int, void *, int *);
104static int (*tip_ioctl)(int, int, void *, int);
105static int (*tip_listen)(int, int);
106static int (*tip_removesocketfromlist)(int);
107static int (*tip_recv)(int, void *, int, int);
108static int (*tip_recvfrom)(int, void *, int, int, struct sockaddr *, int *);
109static int (*tip_select)(int *, int, int, int, long);
110static int (*tip_send)(int, const void *, int, int);
111static int (*tip_sendto)(int, const void *, int, int, const struct sockaddr *,
112 int);
113static int (*tip_setsockopt) (int, int, int, const void *, int);
114static int (*tip_shutdown) (int, int);
115static int (*tip_socket) (int domain, int type, int protocol);
116static int (*tip_sock_errno)(void);
117static int (*tip_sock_init)(void);
118static int (*tip_soclose)(int handle);
119static 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
132static 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
166void 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
182void 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
205static 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
277static 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
344int 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
423void 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
459void 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
485void 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
504static 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
613static 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
629static 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
684int 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
707int 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
721int 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
744int 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
761int 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
778int 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
795int 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
833int 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
875int 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
928int 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
986int 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
1004int 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
1054int 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
1073int 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
1103int 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
1124static 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
1143int 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
1238int 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
1249int 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
1268int 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
1287int 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
1304int 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
1321int 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
1338int 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
1363int 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
1388int 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
1403int 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
1418int 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
1431int 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
1456int 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
1471int 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
1486int 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
1501int 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
1516int 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
1572int 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}
Note: See TracBrowser for help on using the repository browser.