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
_PR_MD_SOCKET(int domain,int type,int flags)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
_MD_CloseSocket(PRInt32 osfd)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
_MD_SocketAvailable(PRFileDesc * fd)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
socket_io_wait(PRInt32 osfd,PRInt32 fd_type,PRIntervalTime timeout)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 }
107 else {
108 rv = bsdselect(osfd + 1, NULL, &rd_wr, NULL, &tv);
109 }
110 #else
111 lTimeout = _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000;
112 do {
113 socks[0] = osfd;
114 if (fd_type == READ_FD) {
115 rv = os2_select(socks, 1, 0, 0, lTimeout);
116 }
117 else {
118 rv = os2_select(socks, 0, 1, 0, lTimeout);
119 }
120 #endif
121 if (rv == -1 && (syserror = sock_errno()) != EINTR) {
122 _PR_MD_MAP_SELECT_ERROR(syserror);
123 break;
124 }
125 if (_PR_PENDING_INTERRUPT(me)) {
126 me->flags &= ~_PR_INTERRUPT;
127 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
128 rv = -1;
129 break;
130 }
131 } while (rv == 0 || (rv == -1 && syserror == EINTR));
132 break;
133 default:
134 now = epoch = PR_IntervalNow();
135 remaining = timeout;
136 #ifdef BSD_SELECT
137 FD_ZERO(&rd_wr);
138 #endif
139 do {
140 /*
141 * We block in select for at most
142 * _PR_INTERRUPT_CHECK_INTERVAL_SECS seconds,
143 * so that there is an upper limit on the delay
144 * before the interrupt bit is checked.
145 */
146 #ifdef BSD_SELECT
147 wait_for_remaining = PR_TRUE;
148 tv.tv_sec = PR_IntervalToSeconds(remaining);
149 if (tv.tv_sec > _PR_INTERRUPT_CHECK_INTERVAL_SECS) {
150 wait_for_remaining = PR_FALSE;
151 tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS;
152 tv.tv_usec = 0;
153 } else {
154 tv.tv_usec = PR_IntervalToMicroseconds(
155 remaining -
156 PR_SecondsToInterval(tv.tv_sec));
157 }
158 FD_SET(osfd, &rd_wr);
159 if (fd_type == READ_FD) {
160 rv = bsdselect(osfd + 1, &rd_wr, NULL, NULL, &tv);
161 }
162 else {
163 rv = bsdselect(osfd + 1, NULL, &rd_wr, NULL, &tv);
164 }
165 #else
166 wait_for_remaining = PR_TRUE;
167 lTimeout = PR_IntervalToMilliseconds(remaining);
168 if (lTimeout > _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000) {
169 wait_for_remaining = PR_FALSE;
170 lTimeout = _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000;
171 }
172 socks[0] = osfd;
173 if (fd_type == READ_FD) {
174 rv = os2_select(socks, 1, 0, 0, lTimeout);
175 }
176 else {
177 rv = os2_select(socks, 0, 1, 0, lTimeout);
178 }
179 #endif
180 /*
181 * we don't consider EINTR a real error
182 */
183 if (rv == -1 && (syserror = sock_errno()) != EINTR) {
184 _PR_MD_MAP_SELECT_ERROR(syserror);
185 break;
186 }
187 if (_PR_PENDING_INTERRUPT(me)) {
188 me->flags &= ~_PR_INTERRUPT;
189 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
190 rv = -1;
191 break;
192 }
193 /*
194 * We loop again if select timed out or got interrupted
195 * by a signal, and the timeout deadline has not passed yet.
196 */
197 if (rv == 0 || (rv == -1 && syserror == EINTR)) {
198 /*
199 * If select timed out, we know how much time
200 * we spent in blocking, so we can avoid a
201 * PR_IntervalNow() call.
202 */
203 if (rv == 0) {
204 if (wait_for_remaining) {
205 now += remaining;
206 } else {
207 #ifdef BSD_SELECT
208 now += PR_SecondsToInterval(tv.tv_sec)
209 + PR_MicrosecondsToInterval(tv.tv_usec);
210 #else
211 now += PR_MillisecondsToInterval(lTimeout);
212 #endif
213 }
214 } else {
215 now = PR_IntervalNow();
216 }
217 elapsed = (PRIntervalTime) (now - epoch);
218 if (elapsed >= timeout) {
219 PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
220 rv = -1;
221 break;
222 } else {
223 remaining = timeout - elapsed;
224 }
225 }
226 } while (rv == 0 || (rv == -1 && syserror == EINTR));
227 break;
228 }
229 return(rv);
230 }
231
232 PRInt32
233 _MD_Accept(PRFileDesc *fd, PRNetAddr *addr,
234 PRUint32 *addrlen, PRIntervalTime timeout)
235 {
236 PRInt32 osfd = fd->secret->md.osfd;
237 PRInt32 rv, err;
238 PRThread *me = _PR_MD_CURRENT_THREAD();
239
240 while ((rv = accept(osfd, (struct sockaddr*) addr, (int*)addrlen)) == -1)
241 {
242 err = sock_errno();
243 if ((err == EWOULDBLOCK) || (err == ECONNABORTED))
244 {
245 if (fd->secret->nonblocking) {
246 break;
247 }
248 if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0) {
249 goto done;
250 }
251 } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) {
252 continue;
253 } else {
254 break;
255 }
256 }
257 if (rv < 0) {
258 _PR_MD_MAP_ACCEPT_ERROR(err);
259 }
260 done:
261 return(rv);
262 }
263
264 PRInt32
265 _PR_MD_CONNECT(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen,
266 PRIntervalTime timeout)
267 {
268 PRInt32 rv, err;
269 PRThread *me = _PR_MD_CURRENT_THREAD();
270 PRInt32 osfd = fd->secret->md.osfd;
271 PRNetAddr addrCopy = *addr; /* Work around a bug in OS/2 where connect
272 * modifies the sockaddr structure.
273 * See Bugzilla bug 100776. */
274
275 /*
276 * We initiate the connection setup by making a nonblocking connect()
277 * call. If the connect() call fails, there are two cases we handle
278 * specially:
279 * 1. The connect() call was interrupted by a signal. In this case
280 * we simply retry connect().
281 * 2. The NSPR socket is nonblocking and connect() fails with
282 * EINPROGRESS. We first wait until the socket becomes writable.
283 * Then we try to find out whether the connection setup succeeded
284 * or failed.
285 */
286
287 retry:
288 if ((rv = connect(osfd, (struct sockaddr *)&addrCopy, addrlen)) == -1)
289 {
290 err = sock_errno();
291
292 if (err == EINTR) {
293 if (_PR_PENDING_INTERRUPT(me)) {
294 me->flags &= ~_PR_INTERRUPT;
295 PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0);
296 return -1;
297 }
298 goto retry;
299 }
300
301 if (!fd->secret->nonblocking && (err == EINPROGRESS))
302 {
303 /*
304 * socket_io_wait() may return -1 or 1.
305 */
306
307 rv = socket_io_wait(osfd, WRITE_FD, timeout);
308 if (rv == -1) {
309 return -1;
310 }
311
312 PR_ASSERT(rv == 1);
313 if (_PR_PENDING_INTERRUPT(me)) {
314 me->flags &= ~_PR_INTERRUPT;
315 PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0);
316 return -1;
317 }
318 err = _MD_os2_get_nonblocking_connect_error(osfd);
319 if (err != 0) {
320 _PR_MD_MAP_CONNECT_ERROR(err);
321 return -1;
322 }
323 return 0;
324 }
325
326 _PR_MD_MAP_CONNECT_ERROR(err);
327 }
328
329 return rv;
330 } /* _MD_connect */
331
332 PRInt32
333 _PR_MD_BIND(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen)
334 {
335 PRInt32 rv, err;
336 rv = bind(fd->secret->md.osfd, (struct sockaddr *) addr, (int )addrlen);
337 if (rv < 0) {
338 err = sock_errno();
339 _PR_MD_MAP_BIND_ERROR(err);
340 }
341 return(rv);
342 }
343
344
345 PRInt32
346 _PR_MD_LISTEN(PRFileDesc *fd, PRIntn backlog)
347 {
348 PRInt32 rv, err;
349 rv = listen(fd->secret->md.osfd, backlog);
350 if (rv < 0) {
351 err = sock_errno();
352 _PR_MD_MAP_DEFAULT_ERROR(err);
353 }
354 return(rv);
355 }
356
357
358 PRInt32
359 _PR_MD_RECV(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags,
360 PRIntervalTime timeout)
361 {
362 PRInt32 osfd = fd->secret->md.osfd;
363 PRInt32 rv, err;
364 PRThread *me = _PR_MD_CURRENT_THREAD();
365
366 while ((rv = recv(osfd,buf,amount,flags)) == -1)
367 {
368 err = sock_errno();
369 if ((err == EWOULDBLOCK)) {
370 if (fd->secret->nonblocking) {
371 break;
372 }
373 if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0) {
374 goto done;
375 }
376 } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) {
377 continue;
378 } else {
379 break;
380 }
381 }
382 if (rv < 0) {
383 _PR_MD_MAP_RECV_ERROR(err);
384 }
385 done:
386 return(rv);
387 }
388
389 PRInt32
390 _PR_MD_SEND(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
391 PRIntervalTime timeout)
392 {
393 PRInt32 osfd = fd->secret->md.osfd;
394 PRInt32 rv, err;
395 PRThread *me = _PR_MD_CURRENT_THREAD();
396
397 while ((rv = send(osfd,buf,amount,flags)) == -1)
398 {
399 err = sock_errno();
400 if ((err == EWOULDBLOCK)) {
401 if (fd->secret->nonblocking) {
402 break;
403 }
404 if ((rv = socket_io_wait(osfd, WRITE_FD, timeout)) < 0) {
405 goto done;
406 }
407 } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) {
408 continue;
409 } else {
410 break;
411 }
412 }
413
414 /*
415 * optimization; if bytes sent is less than "amount" call
416 * select before returning. This is because it is likely that
417 * the next send() call will return EWOULDBLOCK.
418 */
419 if ((!fd->secret->nonblocking) && (rv > 0) && (rv < amount)
420 && (timeout != PR_INTERVAL_NO_WAIT))
421 {
422 if (socket_io_wait(osfd, WRITE_FD, timeout)< 0) {
423 rv = -1;
424 goto done;
425 }
426 }
427 if (rv < 0) {
428 _PR_MD_MAP_SEND_ERROR(err);
429 }
430 done:
431 return(rv);
432 }
433
434 PRInt32
435 _PR_MD_SENDTO(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
436 const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout)
437 {
438 PRInt32 osfd = fd->secret->md.osfd;
439 PRInt32 rv, err;
440 PRThread *me = _PR_MD_CURRENT_THREAD();
441 while ((rv = sendto(osfd, buf, amount, flags,
442 (struct sockaddr *) addr, addrlen)) == -1)
443 {
444 err = sock_errno();
445 if ((err == EWOULDBLOCK))
446 {
447 if (fd->secret->nonblocking) {
448 break;
449 }
450 if ((rv = socket_io_wait(osfd, WRITE_FD, timeout)) < 0) {
451 goto done;
452 }
453 } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) {
454 continue;
455 } else {
456 break;
457 }
458 }
459 if (rv < 0) {
460 _PR_MD_MAP_SENDTO_ERROR(err);
461 }
462 done:
463 return(rv);
464 }
465
466 PRInt32
467 _PR_MD_RECVFROM(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags,
468 PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout)
469 {
470 PRInt32 osfd = fd->secret->md.osfd;
471 PRInt32 rv, err;
472 PRThread *me = _PR_MD_CURRENT_THREAD();
473
474 while( (*addrlen = PR_NETADDR_SIZE(addr)),
475 ((rv = recvfrom(osfd, buf, amount, flags,
476 (struct sockaddr *) addr, (int *)addrlen)) == -1))
477 {
478 err = sock_errno();
479 if ((err == EWOULDBLOCK)) {
480 if (fd->secret->nonblocking) {
481 break;
482 }
483 if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0) {
484 goto done;
485 }
486 } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) {
487 continue;
488 } else {
489 break;
490 }
491 }
492 if (rv < 0) {
493 _PR_MD_MAP_RECVFROM_ERROR(err);
494 }
495 done:
496 return(rv);
497 }
498
499 PRInt32
500 _PR_MD_WRITEV(PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size,
501 PRIntervalTime timeout)
502 {
503 PRInt32 rv, err;
504 PRThread *me = _PR_MD_CURRENT_THREAD();
505 PRInt32 index, amount = 0;
506 PRInt32 osfd = fd->secret->md.osfd;
507 struct iovec osiov[PR_MAX_IOVECTOR_SIZE];
508
509 /* Ensured by PR_Writev */
510 PR_ASSERT(iov_size <= PR_MAX_IOVECTOR_SIZE);
511
512 /*
513 * We can't pass iov to so_writev because PRIOVec and struct iovec
514 * may not be binary compatible. Make osiov a copy of iov and
515 * pass osiov to so_writev .
516 */
517 for (index = 0; index < iov_size; index++) {
518 osiov[index].iov_base = iov[index].iov_base;
519 osiov[index].iov_len = iov[index].iov_len;
520 }
521
522 /*
523 * Calculate the total number of bytes to be sent; needed for
524 * optimization later.
525 * We could avoid this if this number was passed in; but it is
526 * probably not a big deal because iov_size is usually small (less than
527 * 3)
528 */
529 if (!fd->secret->nonblocking) {
530 for (index=0; index<iov_size; index++) {
531 amount += iov[index].iov_len;
532 }
533 }
534
535 while ((rv = so_writev(osfd, osiov, iov_size)) == -1) {
536 err = sock_errno();
537 if ((err == EWOULDBLOCK)) {
538 if (fd->secret->nonblocking) {
539 break;
540 }
541 if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))<0) {
542 goto done;
543 }
544 } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) {
545 continue;
546 } else {
547 break;
548 }
549 }
550
551 /*
552 * optimization; if bytes sent is less than "amount" call
553 * select before returning. This is because it is likely that
554 * the next writev() call will return EWOULDBLOCK.
555 */
556 if ((!fd->secret->nonblocking) && (rv > 0) && (rv < amount)
557 && (timeout != PR_INTERVAL_NO_WAIT)) {
558 if (socket_io_wait(osfd, WRITE_FD, timeout) < 0) {
559 rv = -1;
560 goto done;
561 }
562 }
563 if (rv < 0) {
564 _PR_MD_MAP_WRITEV_ERROR(err);
565 }
566 done:
567 return(rv);
568 }
569
570 PRInt32
571 _PR_MD_SHUTDOWN(PRFileDesc *fd, PRIntn how)
572 {
573 PRInt32 rv;
574
575 rv = shutdown(fd->secret->md.osfd, how);
576 if (rv < 0) {
577 _PR_MD_MAP_SHUTDOWN_ERROR(sock_errno());
578 }
579 return rv;
580 }
581
582 PRInt32
583 _PR_MD_SOCKETPAIR(int af, int type, int flags, PRInt32 *osfd)
584 {
585 PRInt32 rv, err;
586
587 rv = socketpair(af, type, flags, osfd);
588 if (rv < 0) {
589 err = _MD_ERRNO();
590 _PR_MD_MAP_SOCKETPAIR_ERROR(err);
591 }
592 return rv;
593 }
594
595 PRStatus
596 _PR_MD_GETSOCKNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen)
597 {
598 PRInt32 rv, err;
599
600 rv = getsockname(fd->secret->md.osfd,
601 (struct sockaddr *) addr, (int *)addrlen);
602 if (rv < 0) {
603 err = sock_errno();
604 _PR_MD_MAP_GETSOCKNAME_ERROR(err);
605 }
606 return rv==0?PR_SUCCESS:PR_FAILURE;
607 }
608
609 PRStatus
610 _PR_MD_GETPEERNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen)
611 {
612 PRInt32 rv, err;
613
614 rv = getpeername(fd->secret->md.osfd,
615 (struct sockaddr *) addr, (int *)addrlen);
616 if (rv < 0) {
617 err = sock_errno();
618 _PR_MD_MAP_GETPEERNAME_ERROR(err);
619 }
620 return rv==0?PR_SUCCESS:PR_FAILURE;
621 }
622
623 PRStatus
624 _PR_MD_GETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname,
625 char* optval, PRInt32* optlen)
626 {
627 PRInt32 rv, err;
628
629 rv = getsockopt(fd->secret->md.osfd, level, optname, optval, (int *)optlen);
630 if (rv < 0) {
631 err = sock_errno();
632 _PR_MD_MAP_GETSOCKOPT_ERROR(err);
633 }
634 return rv==0?PR_SUCCESS:PR_FAILURE;
635 }
636
637 PRStatus
638 _PR_MD_SETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname,
639 const char* optval, PRInt32 optlen)
640 {
641 PRInt32 rv, err;
642
643 rv = setsockopt(fd->secret->md.osfd, level, optname, optval, optlen);
644 if (rv < 0) {
645 err = sock_errno();
646 _PR_MD_MAP_SETSOCKOPT_ERROR(err);
647 }
648 return rv==0?PR_SUCCESS:PR_FAILURE;
649 }
650
651 void
652 _MD_MakeNonblock(PRFileDesc *fd)
653 {
654 PRInt32 osfd = fd->secret->md.osfd;
655 PRInt32 err;
656 PRUint32 one = 1;
657
658 if (osfd <= 2) {
659 /* Don't mess around with stdin, stdout or stderr */
660 return;
661 }
662
663 err = so_ioctl( osfd, FIONBIO, (char *) &one, sizeof(one));
664 if ( err != 0 )
665 {
666 err = sock_errno();
667 _PR_MD_MAP_SOCKET_ERROR(err);
668 }
669 }
670