nsprpub/pr/src/md/os2/os2sock.c

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:606d17549fe1
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 /* OS/2 Sockets module
8 *
9 */
10
11 /*Note from DSR111297 - it should be noted that there are two flavors of select() on OS/2 */
12 /*There is standard BSD (which is kind of slow) and a new flavor of select() that takes */
13 /*an integer list of sockets, the number of read sockets, write sockets, except sockets, and */
14 /*a millisecond count for timeout. In the interest of performance I have choosen the OS/2 */
15 /*specific version of select(). See OS/2 TCP/IP Programmer's Toolkit for more info. */
16
17 #include "primpl.h"
18
19 #include <sys/time.h> /* For timeval. */
20
21 #define _PR_INTERRUPT_CHECK_INTERVAL_SECS 5
22 #define READ_FD 1
23 #define WRITE_FD 2
24
25 /* --- SOCKET IO --------------------------------------------------------- */
26
27
28 PRInt32
29 _PR_MD_SOCKET(int domain, int type, int flags)
30 {
31 PRInt32 osfd, err;
32
33 osfd = socket(domain, type, flags);
34
35 if (osfd == -1)
36 {
37 err = sock_errno();
38 _PR_MD_MAP_SOCKET_ERROR(err);
39 }
40
41 return(osfd);
42 }
43
44 /*
45 ** _MD_CloseSocket() -- Close a socket
46 **
47 */
48 PRInt32
49 _MD_CloseSocket(PRInt32 osfd)
50 {
51 PRInt32 rv, err;
52
53 rv = soclose(osfd);
54 if (rv == -1) {
55 err = sock_errno();
56 _PR_MD_MAP_CLOSE_ERROR(err);
57 }
58 return rv;
59 }
60
61 PRInt32
62 _MD_SocketAvailable(PRFileDesc *fd)
63 {
64 PRInt32 result;
65
66 if (so_ioctl(fd->secret->md.osfd, FIONREAD, (char *) &result, sizeof(result)) < 0) {
67 PR_SetError(PR_BAD_DESCRIPTOR_ERROR, sock_errno());
68 return -1;
69 }
70 return result;
71 }
72
73 static PRInt32
74 socket_io_wait( PRInt32 osfd, PRInt32 fd_type, PRIntervalTime timeout )
75 {
76 PRInt32 rv = -1;
77 PRThread *me = _PR_MD_CURRENT_THREAD();
78 PRIntervalTime epoch, now, elapsed, remaining;
79 PRBool wait_for_remaining;
80 PRInt32 syserror;
81 #ifdef BSD_SELECT
82 struct timeval tv;
83 fd_set rd_wr;
84 #else
85 int socks[1];
86 long lTimeout;
87 #endif
88
89 switch (timeout) {
90 case PR_INTERVAL_NO_WAIT:
91 PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
92 break;
93 case PR_INTERVAL_NO_TIMEOUT:
94 /*
95 * This is a special case of the 'default' case below.
96 * Please see the comments there.
97 */
98 #ifdef BSD_SELECT
99 tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS;
100 tv.tv_usec = 0;
101 FD_ZERO(&rd_wr);
102 do {
103 FD_SET(osfd, &rd_wr);
104 if (fd_type == READ_FD)
105 rv = bsdselect(osfd + 1, &rd_wr, NULL, NULL, &tv);
106 else
107 rv = bsdselect(osfd + 1, NULL, &rd_wr, NULL, &tv);
108 #else
109 lTimeout = _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000;
110 do {
111 socks[0] = osfd;
112 if (fd_type == READ_FD)
113 rv = os2_select(socks, 1, 0, 0, lTimeout);
114 else
115 rv = os2_select(socks, 0, 1, 0, lTimeout);
116 #endif
117 if (rv == -1 && (syserror = sock_errno()) != EINTR) {
118 _PR_MD_MAP_SELECT_ERROR(syserror);
119 break;
120 }
121 if (_PR_PENDING_INTERRUPT(me)) {
122 me->flags &= ~_PR_INTERRUPT;
123 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
124 rv = -1;
125 break;
126 }
127 } while (rv == 0 || (rv == -1 && syserror == EINTR));
128 break;
129 default:
130 now = epoch = PR_IntervalNow();
131 remaining = timeout;
132 #ifdef BSD_SELECT
133 FD_ZERO(&rd_wr);
134 #endif
135 do {
136 /*
137 * We block in select for at most
138 * _PR_INTERRUPT_CHECK_INTERVAL_SECS seconds,
139 * so that there is an upper limit on the delay
140 * before the interrupt bit is checked.
141 */
142 #ifdef BSD_SELECT
143 wait_for_remaining = PR_TRUE;
144 tv.tv_sec = PR_IntervalToSeconds(remaining);
145 if (tv.tv_sec > _PR_INTERRUPT_CHECK_INTERVAL_SECS) {
146 wait_for_remaining = PR_FALSE;
147 tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS;
148 tv.tv_usec = 0;
149 } else {
150 tv.tv_usec = PR_IntervalToMicroseconds(
151 remaining -
152 PR_SecondsToInterval(tv.tv_sec));
153 }
154 FD_SET(osfd, &rd_wr);
155 if (fd_type == READ_FD)
156 rv = bsdselect(osfd + 1, &rd_wr, NULL, NULL, &tv);
157 else
158 rv = bsdselect(osfd + 1, NULL, &rd_wr, NULL, &tv);
159 #else
160 wait_for_remaining = PR_TRUE;
161 lTimeout = PR_IntervalToMilliseconds(remaining);
162 if (lTimeout > _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000) {
163 wait_for_remaining = PR_FALSE;
164 lTimeout = _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000;
165 }
166 socks[0] = osfd;
167 if (fd_type == READ_FD)
168 rv = os2_select(socks, 1, 0, 0, lTimeout);
169 else
170 rv = os2_select(socks, 0, 1, 0, lTimeout);
171 #endif
172 /*
173 * we don't consider EINTR a real error
174 */
175 if (rv == -1 && (syserror = sock_errno()) != EINTR) {
176 _PR_MD_MAP_SELECT_ERROR(syserror);
177 break;
178 }
179 if (_PR_PENDING_INTERRUPT(me)) {
180 me->flags &= ~_PR_INTERRUPT;
181 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
182 rv = -1;
183 break;
184 }
185 /*
186 * We loop again if select timed out or got interrupted
187 * by a signal, and the timeout deadline has not passed yet.
188 */
189 if (rv == 0 || (rv == -1 && syserror == EINTR)) {
190 /*
191 * If select timed out, we know how much time
192 * we spent in blocking, so we can avoid a
193 * PR_IntervalNow() call.
194 */
195 if (rv == 0) {
196 if (wait_for_remaining) {
197 now += remaining;
198 } else {
199 #ifdef BSD_SELECT
200 now += PR_SecondsToInterval(tv.tv_sec)
201 + PR_MicrosecondsToInterval(tv.tv_usec);
202 #else
203 now += PR_MillisecondsToInterval(lTimeout);
204 #endif
205 }
206 } else {
207 now = PR_IntervalNow();
208 }
209 elapsed = (PRIntervalTime) (now - epoch);
210 if (elapsed >= timeout) {
211 PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
212 rv = -1;
213 break;
214 } else {
215 remaining = timeout - elapsed;
216 }
217 }
218 } while (rv == 0 || (rv == -1 && syserror == EINTR));
219 break;
220 }
221 return(rv);
222 }
223
224 PRInt32
225 _MD_Accept(PRFileDesc *fd, PRNetAddr *addr,
226 PRUint32 *addrlen, PRIntervalTime timeout)
227 {
228 PRInt32 osfd = fd->secret->md.osfd;
229 PRInt32 rv, err;
230 PRThread *me = _PR_MD_CURRENT_THREAD();
231
232 while ((rv = accept(osfd, (struct sockaddr*) addr, (int*)addrlen)) == -1)
233 {
234 err = sock_errno();
235 if ((err == EWOULDBLOCK) || (err == ECONNABORTED))
236 {
237 if (fd->secret->nonblocking) {
238 break;
239 }
240 if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0)
241 goto done;
242 } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){
243 continue;
244 } else {
245 break;
246 }
247 }
248 if (rv < 0) {
249 _PR_MD_MAP_ACCEPT_ERROR(err);
250 }
251 done:
252 return(rv);
253 }
254
255 PRInt32
256 _PR_MD_CONNECT(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen,
257 PRIntervalTime timeout)
258 {
259 PRInt32 rv, err;
260 PRThread *me = _PR_MD_CURRENT_THREAD();
261 PRInt32 osfd = fd->secret->md.osfd;
262 PRNetAddr addrCopy = *addr; /* Work around a bug in OS/2 where connect
263 * modifies the sockaddr structure.
264 * See Bugzilla bug 100776. */
265
266 /*
267 * We initiate the connection setup by making a nonblocking connect()
268 * call. If the connect() call fails, there are two cases we handle
269 * specially:
270 * 1. The connect() call was interrupted by a signal. In this case
271 * we simply retry connect().
272 * 2. The NSPR socket is nonblocking and connect() fails with
273 * EINPROGRESS. We first wait until the socket becomes writable.
274 * Then we try to find out whether the connection setup succeeded
275 * or failed.
276 */
277
278 retry:
279 if ((rv = connect(osfd, (struct sockaddr *)&addrCopy, addrlen)) == -1)
280 {
281 err = sock_errno();
282
283 if (err == EINTR) {
284 if (_PR_PENDING_INTERRUPT(me)) {
285 me->flags &= ~_PR_INTERRUPT;
286 PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0);
287 return -1;
288 }
289 goto retry;
290 }
291
292 if (!fd->secret->nonblocking && (err == EINPROGRESS))
293 {
294 /*
295 * socket_io_wait() may return -1 or 1.
296 */
297
298 rv = socket_io_wait(osfd, WRITE_FD, timeout);
299 if (rv == -1) {
300 return -1;
301 }
302
303 PR_ASSERT(rv == 1);
304 if (_PR_PENDING_INTERRUPT(me)) {
305 me->flags &= ~_PR_INTERRUPT;
306 PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0);
307 return -1;
308 }
309 err = _MD_os2_get_nonblocking_connect_error(osfd);
310 if (err != 0) {
311 _PR_MD_MAP_CONNECT_ERROR(err);
312 return -1;
313 }
314 return 0;
315 }
316
317 _PR_MD_MAP_CONNECT_ERROR(err);
318 }
319
320 return rv;
321 } /* _MD_connect */
322
323 PRInt32
324 _PR_MD_BIND(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen)
325 {
326 PRInt32 rv, err;
327 rv = bind(fd->secret->md.osfd, (struct sockaddr *) addr, (int )addrlen);
328 if (rv < 0) {
329 err = sock_errno();
330 _PR_MD_MAP_BIND_ERROR(err);
331 }
332 return(rv);
333 }
334
335
336 PRInt32
337 _PR_MD_LISTEN(PRFileDesc *fd, PRIntn backlog)
338 {
339 PRInt32 rv, err;
340 rv = listen(fd->secret->md.osfd, backlog);
341 if (rv < 0) {
342 err = sock_errno();
343 _PR_MD_MAP_DEFAULT_ERROR(err);
344 }
345 return(rv);
346 }
347
348
349 PRInt32
350 _PR_MD_RECV(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags,
351 PRIntervalTime timeout)
352 {
353 PRInt32 osfd = fd->secret->md.osfd;
354 PRInt32 rv, err;
355 PRThread *me = _PR_MD_CURRENT_THREAD();
356
357 while ((rv = recv(osfd,buf,amount,flags)) == -1)
358 {
359 err = sock_errno();
360 if ((err == EWOULDBLOCK)) {
361 if (fd->secret->nonblocking) {
362 break;
363 }
364 if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0)
365 goto done;
366 } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){
367 continue;
368 } else {
369 break;
370 }
371 }
372 if (rv < 0) {
373 _PR_MD_MAP_RECV_ERROR(err);
374 }
375 done:
376 return(rv);
377 }
378
379 PRInt32
380 _PR_MD_SEND(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
381 PRIntervalTime timeout)
382 {
383 PRInt32 osfd = fd->secret->md.osfd;
384 PRInt32 rv, err;
385 PRThread *me = _PR_MD_CURRENT_THREAD();
386
387 while ((rv = send(osfd,buf,amount,flags)) == -1)
388 {
389 err = sock_errno();
390 if ((err == EWOULDBLOCK)) {
391 if (fd->secret->nonblocking) {
392 break;
393 }
394 if ((rv = socket_io_wait(osfd, WRITE_FD, timeout)) < 0)
395 goto done;
396 } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){
397 continue;
398 } else {
399 break;
400 }
401 }
402
403 /*
404 * optimization; if bytes sent is less than "amount" call
405 * select before returning. This is because it is likely that
406 * the next send() call will return EWOULDBLOCK.
407 */
408 if ((!fd->secret->nonblocking) && (rv > 0) && (rv < amount)
409 && (timeout != PR_INTERVAL_NO_WAIT))
410 {
411 if (socket_io_wait(osfd, WRITE_FD, timeout)< 0) {
412 rv = -1;
413 goto done;
414 }
415 }
416 if (rv < 0) {
417 _PR_MD_MAP_SEND_ERROR(err);
418 }
419 done:
420 return(rv);
421 }
422
423 PRInt32
424 _PR_MD_SENDTO(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
425 const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout)
426 {
427 PRInt32 osfd = fd->secret->md.osfd;
428 PRInt32 rv, err;
429 PRThread *me = _PR_MD_CURRENT_THREAD();
430 while ((rv = sendto(osfd, buf, amount, flags,
431 (struct sockaddr *) addr, addrlen)) == -1)
432 {
433 err = sock_errno();
434 if ((err == EWOULDBLOCK))
435 {
436 if (fd->secret->nonblocking) {
437 break;
438 }
439 if ((rv = socket_io_wait(osfd, WRITE_FD, timeout)) < 0)
440 goto done;
441 } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){
442 continue;
443 } else {
444 break;
445 }
446 }
447 if (rv < 0) {
448 _PR_MD_MAP_SENDTO_ERROR(err);
449 }
450 done:
451 return(rv);
452 }
453
454 PRInt32
455 _PR_MD_RECVFROM(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags,
456 PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout)
457 {
458 PRInt32 osfd = fd->secret->md.osfd;
459 PRInt32 rv, err;
460 PRThread *me = _PR_MD_CURRENT_THREAD();
461
462 while( (*addrlen = PR_NETADDR_SIZE(addr)),
463 ((rv = recvfrom(osfd, buf, amount, flags,
464 (struct sockaddr *) addr, (int *)addrlen)) == -1))
465 {
466 err = sock_errno();
467 if ((err == EWOULDBLOCK)) {
468 if (fd->secret->nonblocking) {
469 break;
470 }
471 if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0)
472 goto done;
473 } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){
474 continue;
475 } else {
476 break;
477 }
478 }
479 if (rv < 0) {
480 _PR_MD_MAP_RECVFROM_ERROR(err);
481 }
482 done:
483 return(rv);
484 }
485
486 PRInt32
487 _PR_MD_WRITEV(PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size,
488 PRIntervalTime timeout)
489 {
490 PRInt32 rv, err;
491 PRThread *me = _PR_MD_CURRENT_THREAD();
492 PRInt32 index, amount = 0;
493 PRInt32 osfd = fd->secret->md.osfd;
494 struct iovec osiov[PR_MAX_IOVECTOR_SIZE];
495
496 /* Ensured by PR_Writev */
497 PR_ASSERT(iov_size <= PR_MAX_IOVECTOR_SIZE);
498
499 /*
500 * We can't pass iov to so_writev because PRIOVec and struct iovec
501 * may not be binary compatible. Make osiov a copy of iov and
502 * pass osiov to so_writev .
503 */
504 for (index = 0; index < iov_size; index++) {
505 osiov[index].iov_base = iov[index].iov_base;
506 osiov[index].iov_len = iov[index].iov_len;
507 }
508
509 /*
510 * Calculate the total number of bytes to be sent; needed for
511 * optimization later.
512 * We could avoid this if this number was passed in; but it is
513 * probably not a big deal because iov_size is usually small (less than
514 * 3)
515 */
516 if (!fd->secret->nonblocking) {
517 for (index=0; index<iov_size; index++) {
518 amount += iov[index].iov_len;
519 }
520 }
521
522 while ((rv = so_writev(osfd, osiov, iov_size)) == -1) {
523 err = sock_errno();
524 if ((err == EWOULDBLOCK)) {
525 if (fd->secret->nonblocking) {
526 break;
527 }
528 if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))<0)
529 goto done;
530 } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){
531 continue;
532 } else {
533 break;
534 }
535 }
536
537 /*
538 * optimization; if bytes sent is less than "amount" call
539 * select before returning. This is because it is likely that
540 * the next writev() call will return EWOULDBLOCK.
541 */
542 if ((!fd->secret->nonblocking) && (rv > 0) && (rv < amount)
543 && (timeout != PR_INTERVAL_NO_WAIT)) {
544 if (socket_io_wait(osfd, WRITE_FD, timeout) < 0) {
545 rv = -1;
546 goto done;
547 }
548 }
549 if (rv < 0) {
550 _PR_MD_MAP_WRITEV_ERROR(err);
551 }
552 done:
553 return(rv);
554 }
555
556 PRInt32
557 _PR_MD_SHUTDOWN(PRFileDesc *fd, PRIntn how)
558 {
559 PRInt32 rv;
560
561 rv = shutdown(fd->secret->md.osfd, how);
562 if (rv < 0)
563 _PR_MD_MAP_SHUTDOWN_ERROR(sock_errno());
564 return rv;
565 }
566
567 PRInt32
568 _PR_MD_SOCKETPAIR(int af, int type, int flags, PRInt32 *osfd)
569 {
570 PRInt32 rv, err;
571
572 rv = socketpair(af, type, flags, osfd);
573 if (rv < 0) {
574 err = _MD_ERRNO();
575 _PR_MD_MAP_SOCKETPAIR_ERROR(err);
576 }
577 return rv;
578 }
579
580 PRStatus
581 _PR_MD_GETSOCKNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen)
582 {
583 PRInt32 rv, err;
584
585 rv = getsockname(fd->secret->md.osfd,
586 (struct sockaddr *) addr, (int *)addrlen);
587 if (rv < 0) {
588 err = sock_errno();
589 _PR_MD_MAP_GETSOCKNAME_ERROR(err);
590 }
591 return rv==0?PR_SUCCESS:PR_FAILURE;
592 }
593
594 PRStatus
595 _PR_MD_GETPEERNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen)
596 {
597 PRInt32 rv, err;
598
599 rv = getpeername(fd->secret->md.osfd,
600 (struct sockaddr *) addr, (int *)addrlen);
601 if (rv < 0) {
602 err = sock_errno();
603 _PR_MD_MAP_GETPEERNAME_ERROR(err);
604 }
605 return rv==0?PR_SUCCESS:PR_FAILURE;
606 }
607
608 PRStatus
609 _PR_MD_GETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname,
610 char* optval, PRInt32* optlen)
611 {
612 PRInt32 rv, err;
613
614 rv = getsockopt(fd->secret->md.osfd, level, optname, optval, (int *)optlen);
615 if (rv < 0) {
616 err = sock_errno();
617 _PR_MD_MAP_GETSOCKOPT_ERROR(err);
618 }
619 return rv==0?PR_SUCCESS:PR_FAILURE;
620 }
621
622 PRStatus
623 _PR_MD_SETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname,
624 const char* optval, PRInt32 optlen)
625 {
626 PRInt32 rv, err;
627
628 rv = setsockopt(fd->secret->md.osfd, level, optname, optval, optlen);
629 if (rv < 0) {
630 err = sock_errno();
631 _PR_MD_MAP_SETSOCKOPT_ERROR(err);
632 }
633 return rv==0?PR_SUCCESS:PR_FAILURE;
634 }
635
636 void
637 _MD_MakeNonblock(PRFileDesc *fd)
638 {
639 PRInt32 osfd = fd->secret->md.osfd;
640 PRInt32 err;
641 PRUint32 one = 1;
642
643 if (osfd <= 2) {
644 /* Don't mess around with stdin, stdout or stderr */
645 return;
646 }
647
648 err = so_ioctl( osfd, FIONBIO, (char *) &one, sizeof(one));
649 if ( err != 0 )
650 {
651 err = sock_errno();
652 _PR_MD_MAP_SOCKET_ERROR(err);
653 }
654 }

mercurial