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 | }
|
---|