source: trunk/src/wsock32/wsock32.cpp@ 21456

Last change on this file since 21456 was 21456, checked in by dmik, 15 years ago

WinSock2: IPPROTO_IP option constants have different values than in Winsock1.1 (closes ticket:10).

File size: 58.1 KB
Line 
1/* $Id: wsock32.cpp,v 1.52 2003-03-03 16:34:39 sandervl Exp $ */
2
3/*
4 *
5 * Project Odin Software License can be found in LICENSE.TXT
6 *
7 * Win32 SOCK32 for OS/2
8 *
9 * Copyright (C) 1999 Patrick Haller <phaller@gmx.net>
10 * Copyright (C) 2000 Sander van Leeuwen (sandervl@xs4all.nl)
11 *
12 * Some parts based on Wine code: (dlls\winsock\socket.c)
13 * (C) 1993,1994,1996,1997 John Brezak, Erik Bos, Alex Korobka.
14 *
15 */
16
17/* Remark:
18 * 1999/11/21 experimental rewrite using IBM's PMWSock only
19 * -> some structural differences remain! (hostent)
20 * 1999/12/01 experimental rewrite works (TELNET)
21 * -> open issue: WSASetLastError / WSAGetLastError
22 * call SetLastError / GetLastError according to docs
23 *
24 * 2000/22/03 Complete rewrite -> got rid of pmwsock
25 *
26 * identical structures:
27 * - sockaddr_in
28 * - WSADATA
29 * - sockaddr
30 * - fd_set
31 * - timeval
32 *
33 * incompatible structures:
34 * - hostent
35 * - netent
36 * - servent
37 * - protent
38 * - linger
39 */
40
41
42/*****************************************************************************
43 * Includes *
44 *****************************************************************************/
45
46#define INCL_BASE
47#include <os2wrap.h> //Odin32 OS/2 api wrappers
48
49#include <string.h>
50#include <odinwrap.h>
51#include <os2sel.h>
52#include <stdlib.h>
53#include <win32api.h>
54#define NO_DCDATA
55#include <winuser32.h>
56#include <wprocess.h>
57#include <dbglog.h>
58
59#include <sys/types.h>
60#include <sys/socket.h>
61#include <net/if.h>
62
63#include "wsock32.h"
64#include "ws2defs.h"
65#include "wsastruct.h"
66#include "asyncthread.h"
67
68#define DBG_LOCALLOG DBG_wsock32
69#include "dbglocal.h"
70
71//
72#define DUMP_PACKETS
73
74ODINDEBUGCHANNEL(WSOCK32-WSOCK32)
75
76/*****************************************************************************
77 * Local variables *
78 *****************************************************************************/
79
80static LPWSINFO lpFirstIData = NULL;
81
82
83//******************************************************************************
84//******************************************************************************
85
86// Note: for the TCP/IP 4.0 headers, SO_SNDTIMEO and SO_RCDTIMEO are
87// unfortunately not defined, so we do this here.
88#ifndef SO_SNDTIMEO
89#define SO_SNDTIMEO 0x1005
90#endif
91
92#ifndef SO_RCVTIMEO
93#define SO_RCVTIMEO 0x1006
94#endif
95
96
97//******************************************************************************
98//******************************************************************************
99LPWSINFO WINSOCK_GetIData(HANDLE tid)
100{
101 LPWSINFO iData;
102 BOOL fCurrentThread = FALSE;
103
104 if(tid == CURRENT_THREAD) {
105 tid = GetCurrentThread();
106 fCurrentThread = TRUE;
107 }
108tryagain:
109 for (iData = lpFirstIData; iData; iData = iData->lpNextIData) {
110 if (iData->dwThisThread == tid)
111 break;
112 }
113 if(iData == NULL && fCurrentThread) {
114 WINSOCK_CreateIData();
115 fCurrentThread = FALSE; //just to prevent infinite loops
116 goto tryagain;
117 }
118 if(iData == NULL) {
119 dprintf(("WINSOCK_GetIData: couldn't find struct for thread %x", tid));
120 DebugInt3();// should never happen!!!!!!!
121 }
122 return iData;
123}
124//******************************************************************************
125//******************************************************************************
126BOOL WINSOCK_CreateIData(void)
127{
128 LPWSINFO iData;
129
130 iData = (LPWSINFO)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WSINFO));
131 if (!iData)
132 return FALSE;
133 iData->dwThisThread = GetCurrentThread();
134 iData->lpNextIData = lpFirstIData;
135 lpFirstIData = iData;
136 return TRUE;
137}
138//******************************************************************************
139//******************************************************************************
140void WINSOCK_DeleteIData(void)
141{
142 LPWSINFO iData = WINSOCK_GetIData();
143 LPWSINFO* ppid;
144 if (iData) {
145 for (ppid = &lpFirstIData; *ppid; ppid = &(*ppid)->lpNextIData) {
146 if (*ppid == iData) {
147 *ppid = iData->lpNextIData;
148 break;
149 }
150 }
151
152 if( iData->flags & WSI_BLOCKINGCALL )
153 dprintf(("\tinside blocking call!\n"));
154
155 /* delete scratch buffers */
156 if(iData->he) free(iData->he);
157 if(iData->se) free(iData->se);
158 if(iData->pe) free(iData->pe);
159
160 //// if( iData->buffer ) SEGPTR_FREE(iData->buffer);
161 //// if( iData->dbuffer ) SEGPTR_FREE(iData->dbuffer);
162
163 HeapFree(GetProcessHeap(), 0, iData);
164 }
165}
166//******************************************************************************
167//******************************************************************************
168void WIN32API WSASetLastError(int iError)
169{
170#ifdef DEBUG
171 char msg[20];
172#endif
173 // according to the docs, WSASetLastError() is just a call-through
174 // to SetLastError()
175 SetLastError(iError);
176#ifdef DEBUG
177 switch (iError)
178 {
179 case NO_ERROR:
180 strcpy(msg, "no error");
181 break;
182 case WSAEINTR:
183 strcpy(msg, "WSAEINTR");
184 break;
185 case WSAEBADF:
186 strcpy(msg, "WSAEBADF");
187 break;
188 case WSAEACCES:
189 strcpy(msg, "WSAEACCES");
190 break;
191 case WSAEFAULT:
192 strcpy(msg, "WSAEFAULT");
193 break;
194 case WSAEINVAL:
195 strcpy(msg, "WSAEINVAL");
196 break;
197 case WSAEMFILE:
198 strcpy(msg, "WSAEMFILE");
199 break;
200 case WSAEWOULDBLOCK:
201 strcpy(msg, "WSAEWOULDBLOCK");
202 break;
203 case WSAEINPROGRESS:
204 strcpy(msg, "WSAEINPROGRESS");
205 break;
206 case WSAEALREADY:
207 strcpy(msg, "WSAEALREADY");
208 break;
209 case WSAHOST_NOT_FOUND:
210 strcpy(msg, "WSAHOST_NOT_FOUND");
211 break;
212 case WSAENOPROTOOPT:
213 strcpy(msg, "WSAENOPROTOOPT");
214 break;
215 case WSAEHOSTUNREACH:
216 strcpy(msg, "WSAEHOSTUNREACH");
217 break;
218 case WSAETIMEDOUT:
219 strcpy(msg, "WSAETIMEDOUT");
220 break;
221 default:
222 strcpy(msg, "unknown");
223 }
224 if (iError != 0)
225 {
226 dprintf(("WSASetLastError 0x%x - %s", iError, msg));
227 }
228#endif
229}
230//******************************************************************************
231//******************************************************************************
232int WIN32API WSAGetLastError()
233{
234 return GetLastError();
235}
236//******************************************************************************
237//******************************************************************************
238ODINFUNCTION2(int,OS2shutdown,
239 SOCKET,s,
240 int,how)
241{
242 int ret;
243
244 if(!fWSAInitialized) {
245 WSASetLastError(WSANOTINITIALISED);
246 return SOCKET_ERROR;
247 }
248 else
249 if(WSAIsBlocking()) {
250 WSASetLastError(WSAEINPROGRESS);
251 return SOCKET_ERROR;
252 }
253 ret = shutdown(s, how);
254
255 if(ret == SOCKET_ERROR) {
256 WSASetLastError(wsaErrno());
257 }
258 else WSASetLastError(NO_ERROR);
259 return ret;
260}
261//******************************************************************************
262//******************************************************************************
263ODINFUNCTION3(SOCKET,OS2socket,
264 int,af,
265 int,type,
266 int,protocol)
267{
268 SOCKET s;
269
270 if(!fWSAInitialized) {
271 WSASetLastError(WSANOTINITIALISED);
272 return SOCKET_ERROR;
273 }
274 else
275 if(WSAIsBlocking()) {
276 WSASetLastError(WSAEINPROGRESS);
277 return SOCKET_ERROR;
278 }
279 s = socket(af, type, protocol);
280
281 if(s == SOCKET_ERROR && sock_errno() == SOCEPFNOSUPPORT) {
282 //map SOCEPFNOSUPPORT to SOCEPFNOSUPPORT
283 WSASetLastError(SOCEPFNOSUPPORT);
284 }
285 else
286 if(s == SOCKET_ERROR) {
287 WSASetLastError(wsaErrno());
288 }
289 else WSASetLastError(NO_ERROR);
290 return s;
291}
292//******************************************************************************
293//******************************************************************************
294ODINFUNCTION1(int,OS2closesocket,SOCKET, s)
295{
296 int ret;
297
298 if(!fWSAInitialized) {
299 WSASetLastError(WSANOTINITIALISED);
300 return SOCKET_ERROR;
301 }
302 else
303 if(WSAIsBlocking()) {
304 WSASetLastError(WSAEINPROGRESS);
305 return SOCKET_ERROR;
306 }
307 //Close WSAAsyncSelect thread if one was created for this socket
308 FindAndSetAsyncEvent(s, WSA_SELECT_HWND, 0, 0, 0);
309
310 // wait thread termination
311 DosSleep(10);
312 ret = soclose(s);
313
314 if(ret == SOCKET_ERROR) {
315 WSASetLastError(wsaErrno());
316 }
317 else WSASetLastError(NO_ERROR);
318 return ret;
319}
320//******************************************************************************
321//******************************************************************************
322ODINFUNCTION3(int,OS2connect,
323 SOCKET, s,
324 const struct sockaddr *,name,
325 int, namelen)
326{
327 int ret;
328
329 if(!fWSAInitialized) {
330 WSASetLastError(WSANOTINITIALISED);
331 return SOCKET_ERROR;
332 }
333 else
334 if(WSAIsBlocking()) {
335 WSASetLastError(WSAEINPROGRESS);
336 return SOCKET_ERROR;
337 }
338 dprintf(("connect to %s", inet_ntoa(((sockaddr_in*)name)->sin_addr)));
339
340 ret = connect(s, (sockaddr *)name, namelen);
341 // map BSD error codes
342 if(ret == SOCKET_ERROR) {
343 int sockerror = sock_errno();
344 if(sockerror && sockerror < SOCBASEERR) {
345 sockerror += SOCBASEERR;
346 }
347 if(sockerror == SOCEINPROGRESS) {
348 WSASetLastError(WSAEWOULDBLOCK);
349 }
350 else
351 if(sockerror == SOCEOPNOTSUPP) {
352 WSASetLastError(WSAEINVAL);
353 }
354 else WSASetLastError(wsaErrno());
355 }
356 else WSASetLastError(NO_ERROR);
357 return ret;
358}
359//******************************************************************************
360//******************************************************************************
361ODINFUNCTION3(int,OS2ioctlsocket,
362 SOCKET,s,
363 long, cmd,
364 u_long *,argp)
365{
366 int ret;
367
368 if(!fWSAInitialized) {
369 WSASetLastError(WSANOTINITIALISED);
370 return SOCKET_ERROR;
371 }
372 else
373 if(WSAIsBlocking()) {
374 WSASetLastError(WSAEINPROGRESS);
375 return SOCKET_ERROR;
376 }
377 // clear high word (not used in OS/2's tcpip stack)
378 cmd = LOUSHORT(cmd);
379
380 if(cmd != FIONBIO && cmd != FIONREAD && cmd != SIOCATMARK) {
381 WSASetLastError(WSAEINVAL);
382 return SOCKET_ERROR;
383 }
384
385 WSASetLastError(NO_ERROR);
386
387 //check if app want to set a socket, which has an outstanding async select,
388 //to blocking mode
389 if (cmd == FIONBIO) {
390 ULONG ulNotifyHandle, ulNotifyData;
391 int mode;
392 ULONG lEvent;
393
394 if(QueryAsyncEvent(s, &mode, &ulNotifyHandle, &ulNotifyData, &lEvent) == TRUE)
395 {
396 if(*argp != 0) {
397 //nothing to do; already non-blocking
398 return NO_ERROR;
399 }
400 else
401 if(lEvent != 0) {
402 dprintf(("Trying to set socket to blocking mode while async select active -> return error!"));
403 WSASetLastError(WSAEINVAL);
404 return SOCKET_ERROR;
405 }
406 }
407 }
408 ret = ioctl(s, cmd, (char *)argp, sizeof(int));
409
410 // Map EOPNOTSUPP to EINVAL
411 int sockerror = sock_errno();
412 if(sockerror && sockerror < SOCBASEERR) {
413 sockerror += SOCBASEERR;
414 }
415
416 if(ret == SOCKET_ERROR && sockerror == SOCEOPNOTSUPP)
417 WSASetLastError(WSAEINVAL);
418 else
419 if(ret == SOCKET_ERROR) {
420 WSASetLastError(wsaErrno());
421 }
422 else WSASetLastError(NO_ERROR);
423 return ret;
424}
425//******************************************************************************
426//******************************************************************************
427ODINFUNCTION3(int,OS2getpeername,
428 SOCKET, s,
429 struct sockaddr *,name,
430 int *, namelen)
431{
432 int ret;
433
434 if(!fWSAInitialized) {
435 WSASetLastError(WSANOTINITIALISED);
436 return SOCKET_ERROR;
437 }
438 else
439 if(WSAIsBlocking()) {
440 WSASetLastError(WSAEINPROGRESS);
441 return SOCKET_ERROR;
442 }
443 else
444 if (namelen == NULL || *namelen < (int)sizeof(struct sockaddr_in)) {
445 WSASetLastError(WSAEFAULT);
446 return SOCKET_ERROR;
447 }
448 ret = getsockname(s, name, namelen);
449 if(ret == SOCKET_ERROR) {
450 WSASetLastError(wsaErrno());
451 }
452 else WSASetLastError(NO_ERROR);
453 return ret;
454}
455//******************************************************************************
456//******************************************************************************
457ODINFUNCTION3(int,OS2getsockname,
458 SOCKET,s,
459 struct sockaddr *,name,
460 int *, namelen)
461{
462 int ret;
463
464 if(!fWSAInitialized) {
465 WSASetLastError(WSANOTINITIALISED);
466 return SOCKET_ERROR;
467 }
468 else
469 if(WSAIsBlocking()) {
470 WSASetLastError(WSAEINPROGRESS);
471 return SOCKET_ERROR;
472 }
473 else
474 if (namelen == NULL || *namelen < (int)sizeof(struct sockaddr_in)) {
475 WSASetLastError(WSAEFAULT);
476 return SOCKET_ERROR;
477 }
478 ret = getsockname(s, name, namelen);
479 if(ret == SOCKET_ERROR) {
480 WSASetLastError(wsaErrno());
481 }
482 else WSASetLastError(NO_ERROR);
483 return ret;
484}
485//******************************************************************************
486//******************************************************************************
487ODINFUNCTION1(u_long,OS2htonl,
488 u_long,hostlong)
489{
490 return(htonl(hostlong));
491}
492//******************************************************************************
493//******************************************************************************
494ODINFUNCTION1(u_short,OS2htons,
495 u_short,hostshort)
496{
497 return(htons(hostshort));
498}
499//******************************************************************************
500//******************************************************************************
501ODINFUNCTION1(u_long,OS2ntohl,
502 u_long,netlong)
503{
504 return(ntohl(netlong));
505}
506//******************************************************************************
507//******************************************************************************
508ODINFUNCTION1(u_short,OS2ntohs,
509 u_short,netshort)
510{
511 return(ntohs(netshort));
512}
513//******************************************************************************
514//******************************************************************************
515ODINFUNCTION1(unsigned long,OS2inet_addr,
516 const char *, cp)
517{
518 dprintf(("WSOCK32: OS2inet_addr(%s)\n",
519 cp));
520
521 return (inet_addr((char *)cp));
522}
523//******************************************************************************
524//******************************************************************************
525ODINFUNCTION1(char *,OS2inet_ntoa,
526 struct in_addr, in)
527{
528 return(inet_ntoa(in));
529}
530//******************************************************************************
531//******************************************************************************
532ODINFUNCTION3(SOCKET,OS2accept, SOCKET, s,
533 struct sockaddr *,addr,
534 int *, addrlen)
535{
536 int ret, mode;
537 ULONG lEvent, notifyData, notifyHandle;
538
539 if(!fWSAInitialized) {
540 WSASetLastError(WSANOTINITIALISED);
541 return SOCKET_ERROR;
542 }
543 else
544 if(WSAIsBlocking()) {
545 WSASetLastError(WSAEINPROGRESS);
546 return SOCKET_ERROR;
547 }
548 else
549 if ((addr != NULL) && (addrlen != NULL)) {
550 if (*addrlen < (int)sizeof(struct sockaddr_in)) {
551 WSASetLastError(WSAEFAULT);
552 return SOCKET_ERROR;
553 }
554 }
555 ret = accept(s, addr, addrlen);
556
557 if(ret != SOCKET_ERROR) {
558 //Enable FD_ACCEPT event flag if WSAAsyncSelect was called for this socket
559 EnableAsyncEvent(s, FD_ACCEPT);
560
561 //if this socket has an active async. select pending, then call WSAAsyncSelect
562 //with the same parameters for the new socket (see docs)
563 if(QueryAsyncEvent(s, &mode, &notifyHandle, &notifyData, &lEvent) == TRUE) {
564 dprintf(("Setting async select for socket %x, mode %d, %x %x %x", ret, mode, notifyHandle, notifyData, lEvent));
565 if(WSAAsyncSelectWorker(ret, mode, notifyHandle, notifyData, lEvent) == SOCKET_ERROR) {
566 ret = SOCKET_ERROR;
567 }
568 }
569 }
570 if(ret == SOCKET_ERROR) {
571 WSASetLastError(wsaErrno());
572 }
573 else WSASetLastError(NO_ERROR);
574 return ret;
575}
576//******************************************************************************
577//******************************************************************************
578ODINFUNCTION3(int,OS2bind,
579 SOCKET ,s,
580 const struct sockaddr *,addr,
581 int, namelen)
582{
583 int ret;
584
585 if(!fWSAInitialized) {
586 WSASetLastError(WSANOTINITIALISED);
587 return SOCKET_ERROR;
588 }
589 else
590 if(WSAIsBlocking()) {
591 WSASetLastError(WSAEINPROGRESS);
592 return SOCKET_ERROR;
593 }
594 else
595 if(namelen < (int)sizeof(struct sockaddr_in)) {
596 WSASetLastError(WSAEFAULT);
597 return SOCKET_ERROR;
598 }
599 dprintf(("bind to %s", inet_ntoa(((sockaddr_in*)addr)->sin_addr)));
600 ret = bind(s, (struct sockaddr *)addr, namelen);
601
602 if(ret == SOCKET_ERROR) {
603 WSASetLastError(wsaErrno());
604 }
605 else WSASetLastError(NO_ERROR);
606 return ret;
607}
608//******************************************************************************
609//******************************************************************************
610ODINFUNCTION2(int,OS2listen,
611 SOCKET, s,
612 int, backlog)
613{
614 int ret, tmp, namelen;
615 struct sockaddr_in name;
616
617 if(!fWSAInitialized) {
618 WSASetLastError(WSANOTINITIALISED);
619 return SOCKET_ERROR;
620 }
621 else
622 if(WSAIsBlocking()) {
623 WSASetLastError(WSAEINPROGRESS);
624 return SOCKET_ERROR;
625 }
626 namelen = sizeof(name);
627 ret = getsockname(s, (struct sockaddr *)&name, &namelen);
628 if (ret == 0) {
629 if (name.sin_port == 0 && name.sin_addr.s_addr == 0) {
630 // Socket is not bound
631 WSASetLastError(WSAEINVAL);
632 return SOCKET_ERROR;
633 }
634 ret = ioctl(s, FIOBSTATUS, (char *)&tmp, sizeof(tmp)) &
635 (SS_ISCONNECTING | SS_ISCONNECTED | SS_ISDISCONNECTING);
636 if(ret) {
637 // Socket is already connected
638 WSASetLastError(WSAEISCONN);
639 return SOCKET_ERROR;
640 }
641 ret = listen(s, backlog);
642 //todo: reset FD_ACCEPT bit? (wine seems to do this, but it's not documented)
643 }
644 if(ret == SOCKET_ERROR) {
645 WSASetLastError(wsaErrno());
646 }
647 else WSASetLastError(NO_ERROR);
648 return ret;
649}
650//******************************************************************************
651//******************************************************************************
652ODINFUNCTION4(int,OS2recv,
653 SOCKET,s,
654 char *,buf,
655 int,len,
656 int,flags)
657{
658 int ret;
659
660 if(!fWSAInitialized) {
661 WSASetLastError(WSANOTINITIALISED);
662 return SOCKET_ERROR;
663 }
664 else
665 if(WSAIsBlocking()) {
666 WSASetLastError(WSAEINPROGRESS);
667 return SOCKET_ERROR;
668 }
669 ret = recv(s, buf, len, flags);
670
671 if(ret == SOCKET_ERROR) {
672 if(wsaErrno() == WSAEWOULDBLOCK) {
673 struct timeval tv;
674 int optlen = sizeof(tv);
675 ret = getsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, &optlen);
676 if(ret == 0 && (tv.tv_sec > 0 || tv.tv_usec > 0)) {
677 dprintf(("WSAEWOULDBLOCK: recv timeout set to %ds%dus -> return WSAETIMEDOUT", tv.tv_sec, tv.tv_usec));
678 WSASetLastError(WSAETIMEDOUT);
679 }
680 else WSASetLastError(WSAEWOULDBLOCK);
681 ret = SOCKET_ERROR;
682 }
683 else WSASetLastError(wsaErrno());
684 }
685 else
686 if(ret == 0) {
687 int tmp, state;
688
689 state = ioctl(s, FIOBSTATUS, (char *)&tmp, sizeof(tmp));
690 if(state & SS_CANTRCVMORE) {
691 dprintf(("recv returned 0, socket is no longer connected -> return WSAENOTCONN"));
692 WSASetLastError(WSANO_DATA);
693 return 0; //graceful close
694 }
695 else
696 if(state & (SS_ISDISCONNECTING|SS_ISDISCONNECTED)) {
697 dprintf(("recv returned 0, socket is no longer connected -> return WSAENOTCONN"));
698 WSASetLastError(WSAENOTCONN);
699 return 0; //graceful close
700 }
701 else
702 if(state & SS_ISCONNECTED && flags != MSG_PEEK) {
703 dprintf(("recv returned 0, but socket is still connected -> return WSAEWOULDBLOCK"));
704 WSASetLastError(WSAEWOULDBLOCK);
705 return SOCKET_ERROR;
706 }
707 }
708 else {
709#ifdef DUMP_PACKETS
710 dprintf(("Packet length %d", ret));
711 for(int i=0;i<(ret+7)/8;i++) {
712 dprintf2(("%02x %02x %02x %02x %02x %02x %02x %02x %c %c %c %c %c %c %c %c", buf[i*8], buf[i*8+1], buf[i*8+2], buf[i*8+3], buf[i*8+4], buf[i*8+5], buf[i*8+6], buf[i*8+7], buf[i*8], buf[i*8+1], buf[i*8+2], buf[i*8+3], buf[i*8+4], buf[i*8+5], buf[i*8+6], buf[i*8+7]));
713 }
714#endif
715 WSASetLastError(NO_ERROR);
716 }
717
718 //Reset FD_READ event flag for WSAAsyncSelect thread if one was created for this socket
719 EnableAsyncEvent(s, FD_READ);
720 return ret;
721}
722//******************************************************************************
723//******************************************************************************
724ODINFUNCTION6(int,OS2recvfrom,
725 SOCKET,s,
726 char *,buf,
727 int,len,
728 int,flags,
729 struct sockaddr *,from,
730 int *,fromlen)
731{
732 int ret;
733
734 if(!fWSAInitialized) {
735 WSASetLastError(WSANOTINITIALISED);
736 return SOCKET_ERROR;
737 }
738 else
739 if(WSAIsBlocking()) {
740 WSASetLastError(WSAEINPROGRESS);
741 return SOCKET_ERROR;
742 }
743 //NOTE: do not check from & fromlen; they are allowed to be NULL/0
744
745 if(from) {
746 dprintf(("recvfrom to %s", inet_ntoa(((sockaddr_in*)from)->sin_addr)));
747 }
748 ret = recvfrom(s, buf, len, flags, from, fromlen);
749
750 if(ret == SOCKET_ERROR) {
751 if(wsaErrno() == WSAEWOULDBLOCK) {
752 struct timeval tv;
753 int optlen = sizeof(tv);
754 ret = getsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, &optlen);
755 if(ret == 0 && (tv.tv_sec > 0 || tv.tv_usec > 0)) {
756 dprintf(("WSAEWOULDBLOCK: recvfrom timeout set to %ds%dus -> return WSAETIMEDOUT", tv.tv_sec, tv.tv_usec));
757 WSASetLastError(WSAETIMEDOUT);
758 }
759 else WSASetLastError(WSAEWOULDBLOCK);
760 ret = SOCKET_ERROR;
761 }
762 else WSASetLastError(wsaErrno());
763 }
764 else {
765#ifdef DUMP_PACKETS
766 dprintf2(("Packet length %d", ret));
767 for(int i=0;i<(ret+7)/8;i++) {
768 dprintf2(("%02x %02x %02x %02x %02x %02x %02x %02x %c %c %c %c %c %c %c %c", buf[i*8], buf[i*8+1], buf[i*8+2], buf[i*8+3], buf[i*8+4], buf[i*8+5], buf[i*8+6], buf[i*8+7], buf[i*8], buf[i*8+1], buf[i*8+2], buf[i*8+3], buf[i*8+4], buf[i*8+5], buf[i*8+6], buf[i*8+7]));
769 }
770#endif
771 WSASetLastError(NO_ERROR);
772 }
773
774 //Reset FD_READ event flagfor WSAAsyncSelect thread if one was created for this socket
775 EnableAsyncEvent(s, FD_READ);
776 return ret;
777}
778//******************************************************************************
779//******************************************************************************
780ODINFUNCTION4(int,OS2send,
781 SOCKET,s,
782 const char *,buf,
783 int,len,
784 int,flags)
785{
786 int ret;
787 int optlen;
788 int option;
789
790 if(!fWSAInitialized) {
791 WSASetLastError(WSANOTINITIALISED);
792 return SOCKET_ERROR;
793 }
794 else
795 if(WSAIsBlocking()) {
796 WSASetLastError(WSAEINPROGRESS);
797 return SOCKET_ERROR;
798 }
799 // check if the socket is a raw socket and has the IP_HDRINCL switch
800 // if this is the case, we overwrite the IP header length field with
801 // the actual length because some apps tend to put garbage in there
802 // and rely on Windows to correct this
803 optlen = sizeof(option);
804 option = 0;
805 ret = getsockopt(s, IPPROTO_IP, IP_HDRINCL_OS2, (char *)&option, &optlen);
806 if(ret == 0 && option != FALSE) {
807 *(u_short *)&buf[2] = len;
808 }
809
810#ifdef DUMP_PACKETS
811 dprintf2(("Packet length %d", len));
812 for(int i=0;i<(len+7)/8;i++) {
813 dprintf2(("%02x %02x %02x %02x %02x %02x %02x %02x %c %c %c %c %c %c %c %c", buf[i*8], buf[i*8+1], buf[i*8+2], buf[i*8+3], buf[i*8+4], buf[i*8+5], buf[i*8+6], buf[i*8+7], buf[i*8], buf[i*8+1], buf[i*8+2], buf[i*8+3], buf[i*8+4], buf[i*8+5], buf[i*8+6], buf[i*8+7]));
814 }
815#endif
816 ret = send(s, (char *)buf, len, flags);
817
818 if(ret == SOCKET_ERROR) {
819 if(wsaErrno() == WSAEWOULDBLOCK) {
820 struct timeval tv;
821 int optlen = sizeof(tv);
822 ret = getsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, &optlen);
823 if(ret == 0 && (tv.tv_sec > 0 || tv.tv_usec > 0)) {
824 dprintf(("WSAEWOULDBLOCK: send timeout set to %ds%dus -> return WSAETIMEDOUT", tv.tv_sec, tv.tv_usec));
825 WSASetLastError(WSAETIMEDOUT);
826 }
827 else WSASetLastError(WSAEWOULDBLOCK);
828 ret = SOCKET_ERROR;
829 }
830 else WSASetLastError(wsaErrno());
831 }
832 else WSASetLastError(NO_ERROR);
833
834 //Reset FD_WRITE event flagfor WSAAsyncSelect thread if one was created for this socket
835 EnableAsyncEvent(s, FD_WRITE);
836 return ret;
837}
838//******************************************************************************
839//******************************************************************************
840ODINFUNCTION6(int,OS2sendto,
841 SOCKET,s,
842 const char *,buf,
843 int,len,
844 int,flags,
845 const struct sockaddr *,to,
846 int,tolen)
847{
848 int ret;
849 int optlen;
850 int option;
851
852 if(!fWSAInitialized) {
853 WSASetLastError(WSANOTINITIALISED);
854 return SOCKET_ERROR;
855 }
856 else
857 if(WSAIsBlocking()) {
858 WSASetLastError(WSAEINPROGRESS);
859 return SOCKET_ERROR;
860 }
861 //NOTE: do not check to & tolen; they are allowed to be NULL/0
862
863 // check if the socket is a raw socket and has the IP_HDRINCL switch
864 // if this is the case, we overwrite the IP header length field with
865 // the actual length because some apps tend to put garbage in there
866 // and rely on Windows to correct this
867 optlen = sizeof(option);
868 option = 0;
869 ret = getsockopt(s, IPPROTO_IP, IP_HDRINCL_OS2, (char *)&option, &optlen);
870 if(ret == 0 && option != FALSE) {
871 *(u_short *)&buf[2] = len;
872 }
873 if(to) {
874 dprintf(("sending to %s", inet_ntoa(((sockaddr_in*)to)->sin_addr)));
875 }
876#ifdef DUMP_PACKETS
877 dprintf2(("Packet length %d", len));
878 for(int i=0;i<(len+7)/8;i++) {
879 dprintf2(("%02x %02x %02x %02x %02x %02x %02x %02x %c %c %c %c %c %c %c %c", buf[i*8], buf[i*8+1], buf[i*8+2], buf[i*8+3], buf[i*8+4], buf[i*8+5], buf[i*8+6], buf[i*8+7], buf[i*8], buf[i*8+1], buf[i*8+2], buf[i*8+3], buf[i*8+4], buf[i*8+5], buf[i*8+6], buf[i*8+7]));
880 }
881#endif
882 ret = sendto(s, (char *)buf, len, flags, (struct sockaddr *)to, tolen);
883
884 if(ret == SOCKET_ERROR) {
885 if(wsaErrno() == WSAEWOULDBLOCK) {
886 struct timeval tv;
887 int optlen = sizeof(tv);
888 ret = getsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, &optlen);
889 if(ret == 0 && (tv.tv_sec > 0 || tv.tv_usec > 0)) {
890 dprintf(("WSAEWOULDBLOCK: sendto timeout set to %ds%dus -> return WSAETIMEDOUT", tv.tv_sec, tv.tv_usec));
891 WSASetLastError(WSAETIMEDOUT);
892 }
893 else WSASetLastError(WSAEWOULDBLOCK);
894 ret = SOCKET_ERROR;
895 }
896 else WSASetLastError(wsaErrno());
897 }
898 else WSASetLastError(NO_ERROR);
899
900 //Reset FD_WRITE event flag for WSAAsyncSelect thread if one was created for this socket
901 EnableAsyncEvent(s, FD_WRITE);
902 return ret;
903}
904//******************************************************************************
905//******************************************************************************
906ODINFUNCTION5(int,OS2select,
907 int,nfds,
908 ws_fd_set *,readfds,
909 ws_fd_set *,writefds,
910 ws_fd_set *,exceptfds,
911 const struct timeval *,timeout)
912{
913 int ret, i, j;
914 int *sockets, *socktmp;
915 int nrread, nrwrite, nrexcept;
916 ULONG ttimeout;
917
918 WSASetLastError(NO_ERROR);
919
920 if(!fWSAInitialized) {
921 WSASetLastError(WSANOTINITIALISED);
922 return SOCKET_ERROR;
923 }
924 else
925 if(WSAIsBlocking()) {
926 WSASetLastError(WSAEINPROGRESS);
927 return SOCKET_ERROR;
928 }
929 else {
930 nrread = nrwrite = nrexcept = 0;
931 if(readfds) {
932 nrread += readfds->fd_count;
933 }
934 if(writefds) {
935 nrwrite += writefds->fd_count;
936 }
937 if(exceptfds) {
938 nrexcept += exceptfds->fd_count;
939 }
940#if 0
941 if(nrread + nrwrite + nrexcept == 0) {
942 dprintf(("ERROR: nrread + nrwrite + nrexcept == 0"));
943 WSASetLastError(WSAEINVAL);
944 return SOCKET_ERROR;
945 }
946#endif
947 if(timeout != NULL && (timeout->tv_sec < 0 || timeout->tv_usec < 0)) {
948 dprintf(("ERROR: timeout->tv_sec < 0 || timeout->tv_usec < 0"));
949 WSASetLastError(WSAEINVAL);
950 return SOCKET_ERROR;
951 }
952 if(timeout == NULL) {
953 ttimeout = -1L; // no timeout
954 }
955 else ttimeout = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
956
957 sockets = (int *)malloc(sizeof(int) * (nrread+nrwrite+nrexcept));
958 if(readfds && nrread) {
959 memcpy(&sockets[0], readfds->fd_array, nrread * sizeof(SOCKET));
960 }
961 if(writefds && nrwrite) {
962 memcpy(&sockets[nrread], writefds->fd_array, nrwrite * sizeof(SOCKET));
963 }
964 if(exceptfds && nrexcept) {
965 memcpy(&sockets[nrread+nrwrite], exceptfds->fd_array, nrexcept * sizeof(SOCKET));
966 }
967
968 ret = select(sockets, nrread, nrwrite, nrexcept, ttimeout);
969
970 if(ret == SOCKET_ERROR)
971 {
972 if(readfds != NULL)
973 readfds->fd_count = 0;
974
975 if(writefds != NULL)
976 writefds->fd_count = 0;
977
978 if(exceptfds != NULL)
979 exceptfds->fd_count = 0;
980
981 WSASetLastError(wsaErrno());
982 free(sockets);
983 return SOCKET_ERROR;
984 }
985
986 if(ret != 0) {
987 socktmp = sockets;
988 if(readfds != NULL) {
989 j = 0;
990 for(i=0;i<nrread;i++) {
991 if(socktmp[i] != -1) {
992 readfds->fd_array[j] = socktmp[i];
993 dprintf(("Socket %d read pending", socktmp[i]));
994 j++;
995 }
996 }
997 readfds->fd_count = j;
998 socktmp += nrread;
999 }
1000
1001 if(writefds != NULL) {
1002 j = 0;
1003 for(i=0;i<nrwrite;i++) {
1004 if(socktmp[i] != -1) {
1005 writefds->fd_array[j] = socktmp[i];
1006 dprintf(("Socket %d write pending", socktmp[i]));
1007 j++;
1008 }
1009 }
1010 writefds->fd_count = j;
1011 socktmp += nrwrite;
1012 }
1013 if(exceptfds != NULL) {
1014 j = 0;
1015 for(i=0;i<nrexcept;i++) {
1016 if(socktmp[i] != -1) {
1017 exceptfds->fd_array[j] = socktmp[i];
1018 j++;
1019 }
1020 }
1021 exceptfds->fd_count = j;
1022 }
1023 }
1024 else {
1025 if(readfds != NULL)
1026 readfds->fd_count = 0;
1027
1028 if(writefds != NULL)
1029 writefds->fd_count = 0;
1030
1031 if(exceptfds != NULL)
1032 exceptfds->fd_count = 0;
1033 }
1034 free(sockets);
1035 }
1036 return ret;
1037}
1038#ifdef DEBUG_LOGGING
1039//******************************************************************************
1040//******************************************************************************
1041char *debugsockopt(int optname)
1042{
1043 switch(optname) {
1044 case SO_DONTLINGER:
1045 return "SO_DONTLINGER";
1046 case SO_LINGER:
1047 return "SO_LINGER";
1048 case SO_REUSEADDR:
1049 return "SO_REUSEADDR";
1050 case SO_SNDTIMEO:
1051 return "SO_SNDTIMEO";
1052 case SO_RCVTIMEO:
1053 return "SO_RCVTIMEO";
1054 case SO_SNDBUF:
1055 return "SO_SNDBUF";
1056 case SO_RCVBUF:
1057 return "SO_RCVBUF";
1058 case SO_BROADCAST:
1059 return "SO_BROADCAST";
1060 case SO_DEBUG:
1061 return "SO_DEBUG";
1062 case SO_KEEPALIVE:
1063 return "SO_KEEPALIVE";
1064 case SO_DONTROUTE:
1065 return "SO_DONTROUTE";
1066 case SO_OOBINLINE:
1067 return "SO_OOBINLINE";
1068 case SO_TYPE:
1069 return "SO_TYPE";
1070 case SO_ERROR:
1071 return "SO_ERROR";
1072 case SO_SNDLOWAT:
1073 return "SO_SNDLOWAT";
1074 case SO_RCVLOWAT:
1075 return "SO_RCVLOWAT";
1076 case SO_USELOOPBACK:
1077 return "SO_USELOOPBACK";
1078 case SO_ACCEPTCONN:
1079 return "SO_ACCEPTCONN";
1080 default:
1081 return "unknown option";
1082 }
1083}
1084#endif
1085//******************************************************************************
1086//******************************************************************************
1087ODINFUNCTION5(int,OS2setsockopt,
1088 SOCKET,s,
1089 int,level,
1090 int,optname,
1091 const char *,optval,
1092 int,optlen)
1093{
1094 struct ws_linger *yy;
1095 struct linger xx;
1096 int ret, val;
1097 ULONG size;
1098 char *safeoptval;
1099
1100 if(!fWSAInitialized) {
1101 dprintf(("WSA not initialized"));
1102 WSASetLastError(WSANOTINITIALISED);
1103 return SOCKET_ERROR;
1104 }
1105 else
1106 if(WSAIsBlocking()) {
1107 dprintf(("WSA is blocking"));
1108 WSASetLastError(WSAEINPROGRESS);
1109 return SOCKET_ERROR;
1110 }
1111 //SvL: The 16 bits TCP/IP stack doesn't like high addresses, so copy
1112 // the option value(s) on the stack.
1113 safeoptval = (char *)alloca(optlen);
1114 if(safeoptval == NULL) {
1115 DebugInt3();
1116 WSASetLastError(WSAEFAULT);
1117 return SOCKET_ERROR;
1118 }
1119 memcpy(safeoptval, optval, optlen);
1120 optval = safeoptval;
1121
1122 if (level == SOL_SOCKET)
1123 {
1124 switch(optname)
1125 {
1126 case SO_DONTLINGER:
1127 case SO_LINGER:
1128 if(optlen < (int)sizeof(ws_linger))
1129 {
1130 dprintf(("SOL_SOCKET, SO_LINGER, optlen too small"));
1131 WSASetLastError(WSAEFAULT);
1132 return SOCKET_ERROR;
1133 }
1134 yy = (struct ws_linger *)optval;
1135 dprintf(("%s: onoff %x linger %x", (optname == SO_DONTLINGER) ? "SO_DONTLINGER" : "SO_LINGER", (int)yy->l_onoff, (int)yy->l_linger));
1136 xx.l_onoff = (optname == SO_DONTLINGER) ? !yy->l_onoff : yy->l_onoff;
1137 xx.l_linger = yy->l_linger;
1138
1139 ret = setsockopt(s,level,optname,(char *)&xx, sizeof(xx));
1140 break;
1141 case SO_SNDBUF:
1142 case SO_RCVBUF:
1143 if(optlen < (int)sizeof(int))
1144 {
1145 dprintf(("SOL_SOCKET, SO_RCVBUF, optlen too small"));
1146 WSASetLastError(WSAEFAULT);
1147 return SOCKET_ERROR;
1148 }
1149
1150 size = *(ULONG *)optval;
1151tryagain:
1152 ret = setsockopt(s,level,optname, (char *)&size, sizeof(ULONG));
1153 if(ret == SOCKET_ERROR && wsaErrno() == WSAENOBUFS && size > 4096) {
1154 int newsize = (size > 65535) ? 63*1024 : (size-1024);
1155 dprintf(("setsockopt: change size from %d to %d", size, newsize));
1156 //SvL: Limit send & receive buffer length to 64k
1157 // (only happens with 16 bits tcpip stack?)
1158 size = newsize;
1159 goto tryagain;
1160 }
1161 break;
1162
1163 case SO_SNDTIMEO:
1164 case SO_RCVTIMEO:
1165 {
1166 if(optlen < (int)sizeof(int))
1167 {
1168 dprintf(("SO_RCVTIMEO, SO_SNDTIMEO, optlen too small"));
1169 WSASetLastError(WSAEFAULT);
1170 return SOCKET_ERROR;
1171 }
1172 // convert "int" to "struct timeval"
1173 struct timeval tv;
1174 tv.tv_sec = (*(int *)optval) / 1000;
1175 tv.tv_usec = ((*(int *)optval) % 1000) * 1000;
1176 if(optname == SO_SNDTIMEO) {
1177 dprintf(("SO_SNDTIMEO: int val %x sec %d, usec %d", *(int *)optval, tv.tv_sec, tv.tv_usec));
1178 }
1179 else dprintf(("SO_RCVTIMEO: int val %x sec %d, usec %d", *(int *)optval, tv.tv_sec, tv.tv_usec));
1180
1181 ret = setsockopt(s, level, optname, (char *)&tv, sizeof(tv) );
1182 break;
1183 }
1184
1185 case SO_REUSEADDR:
1186 if(optlen < (int)sizeof(int)) {
1187 dprintf(("SO_REUSEADDR, optlen too small"));
1188 WSASetLastError(WSAEFAULT);
1189 return SOCKET_ERROR;
1190 }
1191 dprintf(("option SO_REUSEADDR value %d", *(int *)optval));
1192 ret = setsockopt(s, level, SO_REUSEADDR, (char *)optval, optlen);
1193 if(ret) {
1194 dprintf(("setsockopt SO_REUSEADDR failed!!"));
1195 }
1196 ret = setsockopt(s, level, SO_REUSEPORT_OS2, (char *)optval, optlen);
1197 if(ret) {
1198 dprintf(("setsockopt SO_REUSEPORT failed!!"));
1199 }
1200 break;
1201
1202 case SO_BROADCAST:
1203 case SO_DEBUG:
1204 case SO_KEEPALIVE:
1205 case SO_DONTROUTE:
1206 case SO_OOBINLINE:
1207 case SO_ERROR:
1208 case SO_SNDLOWAT:
1209 case SO_RCVLOWAT:
1210 case SO_ACCEPTCONN:
1211 case SO_USELOOPBACK:
1212 if(optlen < (int)sizeof(int)) {
1213 dprintf(("%s optlen too small", debugsockopt(optname)));
1214 WSASetLastError(WSAEFAULT);
1215 return SOCKET_ERROR;
1216 }
1217 dprintf(("option %s = %x", debugsockopt(optname), *(int *)optval));
1218 ret = setsockopt(s, level, optname, (char *)optval, optlen);
1219 break;
1220 default:
1221 dprintf(("setsockopt: SOL_SOCKET, unknown option %x", optname));
1222 WSASetLastError(WSAENOPROTOOPT);
1223 return SOCKET_ERROR;
1224 }
1225 }
1226 else
1227 if(level == IPPROTO_TCP)
1228 {
1229 if(optname == TCP_NODELAY) {
1230 if(optlen < (int)sizeof(int)) {
1231 dprintf(("IPPROTO_TCP, TCP_NODELAY, optlen too small"));
1232 WSASetLastError(WSAEFAULT);
1233 return SOCKET_ERROR;
1234 }
1235 dprintf(("IPPROTO_TCP, TCP_NODELAY 0x%x", *optval));
1236 ret = setsockopt(s, level, optname, (char *)optval, optlen);
1237 }
1238 else {
1239 dprintf(("setsockopt: IPPROTO_TCP, unknown option %x", optname));
1240 WSASetLastError(WSAENOPROTOOPT);
1241 return SOCKET_ERROR;
1242 }
1243 }
1244 else
1245 if (level == IPPROTO_IP)
1246 {
1247 switch (optname)
1248 {
1249 case IP_MULTICAST_IF:
1250 case WS2_IPPROTO_OPT(IP_MULTICAST_IF_WS2):
1251 {
1252 if (optlen < sizeof(in_addr))
1253 {
1254 dprintf(("IPPROTO_IP, IP_MULTICAST_IP, optlen too small"));
1255 WSASetLastError(WSAEFAULT);
1256 return SOCKET_ERROR;
1257 }
1258 //TODO convert common interface names!
1259 ret = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF_OS2, (char *)optval, optlen);
1260 break;
1261 }
1262
1263 case IP_ADD_MEMBERSHIP:
1264 case WS2_IPPROTO_OPT(IP_ADD_MEMBERSHIP_WS2):
1265 if (optlen < sizeof(struct ip_mreq))
1266 {
1267 dprintf(("IPPROTO_IP, IP_ADD_MEMBERSHIP, optlen too small"));
1268 WSASetLastError(WSAEFAULT);
1269 return SOCKET_ERROR;
1270 }
1271 ret = setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP_OS2, (char *)optval, optlen);
1272 break;
1273
1274 case IP_DROP_MEMBERSHIP:
1275 case WS2_IPPROTO_OPT(IP_DROP_MEMBERSHIP_WS2):
1276 if (optlen < sizeof(struct ip_mreq))
1277 {
1278 dprintf(("IPPROTO_IP, IP_DROP_MEMBERSHIP, optlen too small"));
1279 WSASetLastError(WSAEFAULT);
1280 return SOCKET_ERROR;
1281 }
1282 ret = setsockopt(s, IPPROTO_IP, IP_DROP_MEMBERSHIP_OS2, (char *)optval, optlen);
1283 break;
1284
1285 case IP_MULTICAST_LOOP:
1286 case WS2_IPPROTO_OPT(IP_MULTICAST_LOOP_WS2):
1287 {
1288 u_int flLoop;
1289 if (optlen < sizeof(u_int))
1290 {
1291 dprintf(("IPPROTO_IP, IP_MULTICAST_LOOP/IP_MULTICAST_TTL, optlen too small"));
1292 WSASetLastError(WSAEFAULT);
1293 return SOCKET_ERROR;
1294 }
1295 flLoop = (*optval == 0) ? 0 : 1;
1296 dprintf(("IP_MULTICAST_LOOP %d", *optval));
1297 ret = setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP_OS2, (char *)&flLoop, sizeof(u_char));
1298 break;
1299 }
1300
1301 case IP_MULTICAST_TTL:
1302 case WS2_IPPROTO_OPT(IP_MULTICAST_TTL_WS2):
1303 if (optlen < sizeof(u_int))
1304 {
1305 dprintf(("IPPROTO_IP, IP_MULTICAST_TTL, optlen too small"));
1306 WSASetLastError(WSAEFAULT);
1307 return SOCKET_ERROR;
1308 }
1309 dprintf(("IP_MULTICAST_TTL %d", *optval));
1310 ret = setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL_OS2, (char *)optval, sizeof(u_char));
1311 break;
1312
1313 case IP_TTL:
1314 case WS2_IPPROTO_OPT(IP_TTL_WS2):
1315 if (optlen < sizeof(u_int))
1316 {
1317 dprintf(("IPPROTO_IP, IP_TTL_WS2, optlen too small"));
1318 WSASetLastError(WSAEFAULT);
1319 return SOCKET_ERROR;
1320 }
1321 dprintf(("IPPROTO_IP, IP_TTL 0x%x", *optval));
1322 ret = setsockopt(s, IPPROTO_IP, IP_TTL_OS2, (char *)optval, optlen);
1323 break;
1324
1325 case IP_TOS:
1326 case WS2_IPPROTO_OPT(IP_TOS_WS2):
1327 if (optlen < sizeof(u_int))
1328 {
1329 dprintf(("IPPROTO_IP, IP_TOS_WS2, optlen too small"));
1330 WSASetLastError(WSAEFAULT);
1331 return SOCKET_ERROR;
1332 }
1333 dprintf(("IPPROTO_IP, IP_TOS 0x%x", *optval));
1334 ret = setsockopt(s, IPPROTO_IP, IP_TOS_OS2, (char *)optval, optlen);
1335 break;
1336
1337 case WS2_IPPROTO_OPT(IP_HDRINCL_WS2):
1338 if (optlen < sizeof(u_int))
1339 {
1340 dprintf(("IPPROTO_IP, IP_HDRINCL_WS2, optlen too small"));
1341 WSASetLastError(WSAEFAULT);
1342 return SOCKET_ERROR;
1343 }
1344 val = *optval;
1345 dprintf(("IPPROTO_IP, IP_HDRINCL 0x%x", val));
1346 ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL_OS2, (char *)&val, optlen);
1347 break;
1348
1349 case IP_DONTFRAGMENT:
1350 case WS2_IPPROTO_OPT(IP_DONTFRAGMENT_WS2):
1351 //MSDN says these options are silently ignored
1352 dprintf(("IPPROTO_IP: IP_DONTFRAGMENT ignored"));
1353 ret = 0;
1354 break;
1355
1356 default:
1357 dprintf(("setsockopt: IPPROTO_IP, unknown option %x", optname));
1358 WSASetLastError(WSAENOPROTOOPT);
1359 return SOCKET_ERROR;
1360 }
1361 }
1362 else {
1363 dprintf(("unknown level code!"));
1364 WSASetLastError(WSAEINVAL);
1365 return SOCKET_ERROR;
1366 }
1367
1368 if(ret == SOCKET_ERROR) {
1369 WSASetLastError(wsaErrno());
1370 }
1371 else WSASetLastError(NO_ERROR);
1372 return ret;
1373}
1374//******************************************************************************
1375//******************************************************************************
1376ODINFUNCTION5(int,OS2getsockopt,
1377 SOCKET, s,
1378 int, level,
1379 int, optname,
1380 char *, optval,
1381 int *,optlen)
1382{
1383 struct ws_linger *yy;
1384 struct linger xx;
1385 int ret;
1386 int size, options;
1387
1388 if(!fWSAInitialized) {
1389 WSASetLastError(WSANOTINITIALISED);
1390 return SOCKET_ERROR;
1391 }
1392 else
1393 if(WSAIsBlocking()) {
1394 WSASetLastError(WSAEINPROGRESS);
1395 return SOCKET_ERROR;
1396 }
1397 if (level == SOL_SOCKET) {
1398 switch(optname) {
1399 case SO_DONTLINGER:
1400 case SO_LINGER:
1401 if(optlen == NULL || *optlen < sizeof(ws_linger)) {
1402 WSASetLastError(WSAEFAULT);
1403 return SOCKET_ERROR;
1404 }
1405 size = sizeof(xx);
1406 ret = getsockopt(s,level,optname,(char *)&xx, &size);
1407 yy = (struct ws_linger *)optval;
1408 yy->l_onoff = (optname == SO_DONTLINGER) ? !xx.l_onoff : xx.l_onoff;
1409 yy->l_linger = xx.l_linger;
1410 *optlen = size;
1411 break;
1412
1413 case SO_REUSEADDR:
1414 if(optlen == NULL || *optlen < sizeof(int)) {
1415 WSASetLastError(WSAEFAULT);
1416 return SOCKET_ERROR;
1417 }
1418 ret = getsockopt(s, level, SO_REUSEADDR, (char *)optval, optlen);
1419 dprintf(("getsockopt SO_REUSEADDR returned %d", *(int *)optval, optname));
1420 break;
1421 break;
1422
1423 case SO_SNDTIMEO:
1424 case SO_RCVTIMEO:
1425 {
1426 if(optlen == NULL || *optlen < sizeof(int))
1427 {
1428 dprintf(("SO_RCVTIMEO, SO_SNDTIMEO, optlen too small"));
1429 WSASetLastError(WSAEFAULT);
1430 return SOCKET_ERROR;
1431 }
1432 struct timeval tv;
1433 int size = sizeof(tv);
1434 ret = getsockopt(s, level, optname, (char *)&tv, &size );
1435
1436 // convert "struct timeval" to "int"
1437 *(int *)optval = (tv.tv_sec * 1000) + tv.tv_usec/1000;
1438 if(optname == SO_SNDTIMEO) {
1439 dprintf(("SO_SNDTIMEO: int val %x sec %d, usec %d", *(int *)optval, tv.tv_sec, tv.tv_usec));
1440 }
1441 else dprintf(("SO_RCVTIMEO: int val %x sec %d, usec %d", *(int *)optval, tv.tv_sec, tv.tv_usec));
1442
1443 break;
1444 }
1445
1446 case SO_SNDBUF:
1447 case SO_RCVBUF:
1448 case SO_BROADCAST:
1449 case SO_DEBUG:
1450 case SO_KEEPALIVE:
1451 case SO_DONTROUTE:
1452 case SO_OOBINLINE:
1453 case SO_TYPE:
1454 case SO_ERROR:
1455 case SO_SNDLOWAT:
1456 case SO_RCVLOWAT:
1457 case SO_USELOOPBACK:
1458 if(optlen == NULL || *optlen < sizeof(int)) {
1459 WSASetLastError(WSAEFAULT);
1460 return SOCKET_ERROR;
1461 }
1462 ret = getsockopt(s, level, optname, (char *)optval, optlen);
1463 dprintf(("getsockopt %s returned %d", debugsockopt(optname), *(int *)optval));
1464 break;
1465
1466 case SO_ACCEPTCONN:
1467 if(optlen == NULL || *optlen < sizeof(int)) {
1468 WSASetLastError(WSAEFAULT);
1469 return SOCKET_ERROR;
1470 }
1471 size = sizeof(options);
1472 ret = getsockopt(s, SOL_SOCKET, SO_OPTIONS, (char *)&options, &size);
1473 if(ret != SOCKET_ERROR) {
1474 *(BOOL *)optval = (options & SO_ACCEPTCONN) == SO_ACCEPTCONN;
1475 *optlen = sizeof(BOOL);
1476 dprintf(("SO_ACCEPTCONN returned %d", *(BOOL *)optval));
1477 }
1478 break;
1479 default:
1480 dprintf(("getsockopt: unknown option %x", optname));
1481 WSASetLastError(WSAENOPROTOOPT);
1482 return SOCKET_ERROR;
1483 }
1484 }
1485 else
1486 if(level == IPPROTO_TCP) {
1487 if(optname == TCP_NODELAY) {
1488 if(optlen == NULL || *optlen < sizeof(int)) {
1489 WSASetLastError(WSAEFAULT);
1490 return SOCKET_ERROR;
1491 }
1492 ret = getsockopt(s, level, optname, (char *)optval, optlen);
1493 }
1494 else {
1495 dprintf(("getsockopt: unknown option %x", optname));
1496 WSASetLastError(WSAENOPROTOOPT);
1497 return SOCKET_ERROR;
1498 }
1499 }
1500 else
1501 if(level == IPPROTO_IP) {
1502 switch (optname)
1503 {
1504 case IP_MULTICAST_IF:
1505 case WS2_IPPROTO_OPT(IP_MULTICAST_IF_WS2):
1506 {
1507 if (*optlen < sizeof(in_addr))
1508 {
1509 dprintf(("IPPROTO_IP, IP_MULTICAST_IP, optlen too small"));
1510 WSASetLastError(WSAEFAULT);
1511 return SOCKET_ERROR;
1512 }
1513 //TODO convert common interface names!
1514 ret = getsockopt(s, IPPROTO_IP, IP_MULTICAST_IF_OS2, (char *)optval, optlen);
1515 break;
1516 }
1517
1518 case IP_ADD_MEMBERSHIP:
1519 case WS2_IPPROTO_OPT(IP_ADD_MEMBERSHIP_WS2):
1520 if (*optlen < sizeof(struct ip_mreq))
1521 {
1522 dprintf(("IPPROTO_IP, IP_ADD_MEMBERSHIP, optlen too small"));
1523 WSASetLastError(WSAEFAULT);
1524 return SOCKET_ERROR;
1525 }
1526 ret = getsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP_OS2, (char *)optval, optlen);
1527 break;
1528
1529 case IP_DROP_MEMBERSHIP:
1530 case WS2_IPPROTO_OPT(IP_DROP_MEMBERSHIP_WS2):
1531 if (*optlen < sizeof(struct ip_mreq))
1532 {
1533 dprintf(("IPPROTO_IP, IP_DROP_MEMBERSHIP, optlen too small"));
1534 WSASetLastError(WSAEFAULT);
1535 return SOCKET_ERROR;
1536 }
1537 ret = getsockopt(s, IPPROTO_IP, IP_DROP_MEMBERSHIP_OS2, (char *)optval, optlen);
1538 break;
1539
1540 case IP_MULTICAST_LOOP_WS2: //for buggy applications that intended to call ws_32.getsockopt
1541 case IP_MULTICAST_LOOP:
1542 case WS2_IPPROTO_OPT(IP_MULTICAST_LOOP_WS2):
1543 {
1544 if (*optlen < sizeof(u_int))
1545 {
1546 dprintf(("IPPROTO_IP, IP_MULTICAST_LOOP/IP_MULTICAST_TTL, optlen too small"));
1547 WSASetLastError(WSAEFAULT);
1548 return SOCKET_ERROR;
1549 }
1550 memset(optval, 0, *optlen);
1551 ret = getsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP_OS2, (char *)optval, optlen);
1552 break;
1553 }
1554
1555 case IP_MULTICAST_TTL:
1556 case WS2_IPPROTO_OPT(IP_MULTICAST_TTL_WS2):
1557 if (*optlen < sizeof(u_int))
1558 {
1559 dprintf(("IPPROTO_IP, IP_MULTICAST_TTL, optlen too small"));
1560 WSASetLastError(WSAEFAULT);
1561 return SOCKET_ERROR;
1562 }
1563 memset(optval, 0, *optlen);
1564 ret = getsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL_OS2, (char *)optval, optlen);
1565 dprintf(("getsockopt IP_MULTICAST_TTL_OS2 returned %d, size %d", (int)*optval, *optlen));
1566 break;
1567
1568 case IP_TTL:
1569 case WS2_IPPROTO_OPT(IP_TTL_WS2):
1570 if (*optlen < sizeof(u_int))
1571 {
1572 dprintf(("IPPROTO_IP, IP_TTL_WS2, optlen too small"));
1573 WSASetLastError(WSAEFAULT);
1574 return SOCKET_ERROR;
1575 }
1576 memset(optval, 0, *optlen);
1577 ret = getsockopt(s, IPPROTO_IP, IP_TTL_OS2, (char *)optval, optlen);
1578 break;
1579
1580 case IP_TOS:
1581 case WS2_IPPROTO_OPT(IP_TOS_WS2):
1582 if (*optlen < sizeof(u_int))
1583 {
1584 dprintf(("IPPROTO_IP, IP_TOS_WS2, optlen too small"));
1585 WSASetLastError(WSAEFAULT);
1586 return SOCKET_ERROR;
1587 }
1588 ret = getsockopt(s, IPPROTO_IP, IP_TOS_OS2, (char *)optval, optlen);
1589 break;
1590
1591 case WS2_IPPROTO_OPT(IP_HDRINCL_WS2):
1592 if (*optlen < sizeof(u_int))
1593 {
1594 dprintf(("IPPROTO_IP, IP_HDRINCL_WS2, optlen too small"));
1595 WSASetLastError(WSAEFAULT);
1596 return SOCKET_ERROR;
1597 }
1598 ret = getsockopt(s, IPPROTO_IP, IP_HDRINCL_OS2, (char *)optval, optlen);
1599 if(ret == 0) {
1600 ret = (ret != FALSE) ? TRUE : FALSE;
1601 }
1602 break;
1603
1604 case IP_DONTFRAGMENT:
1605 case WS2_IPPROTO_OPT(IP_DONTFRAGMENT_WS2):
1606 //MSDN says these options are silently ignored
1607 if (*optlen < sizeof(u_int))
1608 {
1609 dprintf(("IP_DONTFRAGMENT, IP_DONTFRAGMENT_WS2, optlen too small"));
1610 WSASetLastError(WSAEFAULT);
1611 return SOCKET_ERROR;
1612 }
1613 dprintf(("IPPROTO_IP: IP_DONTFRAGMENT ignored"));
1614 *optlen = sizeof(u_int);
1615 *(int *)optval = 0;
1616 ret = 0;
1617 break;
1618
1619
1620 default:
1621 dprintf(("getsockopt: IPPROTO_IP, unknown option %x", optname));
1622 WSASetLastError(WSAENOPROTOOPT);
1623 return SOCKET_ERROR;
1624 }
1625 }
1626 else {
1627 WSASetLastError(WSAEINVAL);
1628 return SOCKET_ERROR;
1629 }
1630
1631 if(ret == SOCKET_ERROR) {
1632 WSASetLastError(wsaErrno());
1633 }
1634 else WSASetLastError(NO_ERROR);
1635 return ret;
1636}
1637//******************************************************************************
1638//******************************************************************************
1639/* Database function prototypes */
1640//******************************************************************************
1641//******************************************************************************
1642ODINFUNCTION2(int,OS2gethostname,
1643 char *,name,
1644 int,namelen)
1645{
1646 int ret;
1647
1648 ret = gethostname(name, namelen);
1649 if(ret == NULL) {
1650 dprintf(("gethostname returned %s", name));
1651 WSASetLastError(NO_ERROR);
1652 return 0;
1653 }
1654 WSASetLastError((errno == EINVAL) ? WSAEFAULT : wsaErrno());
1655 return SOCKET_ERROR;
1656}
1657//******************************************************************************
1658//******************************************************************************
1659ODINFUNCTION3(ws_hostent *,OS2gethostbyaddr,
1660 const char *,addr,
1661 int,len,
1662 int,type)
1663{
1664 LPWSINFO pwsi = WINSOCK_GetIData();
1665
1666 if( pwsi )
1667 {
1668 struct hostent* host;
1669 if( (host = gethostbyaddr((char *)addr, len, type)) != NULL ) {
1670 if( WS_dup_he(pwsi, host) ) {
1671 WSASetLastError(NO_ERROR);
1672 return pwsi->he;
1673 }
1674 else WSASetLastError(WSAENOBUFS);
1675 }
1676 else WSASetLastError((h_errno < 0) ? wsaErrno() : wsaHerrno());
1677 }
1678 else WSASetLastError(WSANOTINITIALISED);
1679 return NULL;
1680}
1681//******************************************************************************
1682//NOTE: This function can possibly block for a very long time
1683// I.e. start ISDNPM without dialing in. gethostbyname will query
1684// each name server and retry several times (60+ seconds per name server)
1685//
1686static struct ws_hostent localhost;
1687static DWORD localhost_address;
1688static DWORD localhost_addrlist[2] = {(DWORD)&localhost_address, 0};
1689static DWORD localhost_aliaslist[1] = {0};
1690//******************************************************************************
1691ODINFUNCTION1(ws_hostent *,OS2gethostbyname,
1692 const char *,name)
1693{
1694 LPWSINFO pwsi = WINSOCK_GetIData();
1695
1696 if( pwsi )
1697 {
1698 struct hostent* host;
1699 char localhostname[256];
1700
1701 dprintf(("gethostbyname %s", name));
1702 if (!gethostname(localhostname, sizeof(localhostname)))
1703 {
1704 /*
1705 * This is a fast non-blocking path for the hostname of this machine.
1706 * It's probably not 100% correct though..
1707 */
1708 if (!strcmp(name, localhostname))
1709 {
1710 /*
1711 * Lookup lan0 address, and move on to lo address if that fails.
1712 */
1713 sock_init(); /* ??? */
1714 int s = socket(PF_INET, SOCK_STREAM, 0);
1715 if (s >= 0)
1716 {
1717 struct ifreq ifr = {0};
1718 strcpy(ifr.ifr_name, "lan0");
1719 int rc = ioctl(s, SIOCGIFADDR, (char*)&ifr, sizeof(ifr));
1720 if (rc == -1)
1721 {
1722 strcpy(ifr.ifr_name, "lo");
1723 rc = ioctl(s, SIOCGIFADDR, (char*)&ifr, sizeof(ifr));
1724 }
1725 soclose(s);
1726
1727 if (rc != -1)
1728 {
1729 /* ASSUMES: family is AF_INET */
1730 /* Doesn't work with aliases on lan0. */
1731 struct sockaddr_in *addr = (struct sockaddr_in *)&ifr.ifr_addr;
1732
1733 localhost_address = *(unsigned long *)&addr->sin_addr;
1734 localhost.h_name = "localhost"; /* This is what the old workaround did. */
1735 localhost.h_addrtype = AF_INET;
1736 localhost.h_length = 4;
1737 localhost.h_addr_list = (char **)&localhost_addrlist[0];
1738 localhost.h_aliases = (char **)&localhost_aliaslist[0];
1739 WSASetLastError(NO_ERROR);
1740 return &localhost;
1741 }
1742 }
1743
1744 /*
1745 * bail out..
1746 */
1747 strcpy(localhostname, "localhost");
1748 name = localhostname;
1749 dprintf(("using localhost"));
1750 }
1751 }
1752
1753 host = gethostbyname( (char*) name);
1754
1755 if( host != NULL )
1756 {
1757 if( WS_dup_he(pwsi, host) )
1758 {
1759 WSASetLastError(NO_ERROR);
1760 return pwsi->he;
1761 }
1762 else
1763 WSASetLastError(WSAENOBUFS);
1764 }
1765 else
1766 WSASetLastError((h_errno < 0) ? wsaErrno() : wsaHerrno());
1767 }
1768 else
1769 WSASetLastError(WSANOTINITIALISED);
1770
1771 return NULL;
1772}
1773//******************************************************************************
1774//******************************************************************************
1775ODINFUNCTION2(struct ws_servent *,OS2getservbyport,
1776 int, port,
1777 const char *, proto)
1778{
1779 LPWSINFO pwsi = WINSOCK_GetIData();
1780
1781 if( pwsi )
1782 {
1783 struct servent* serv;
1784 if( (serv = getservbyport(port, (char *)proto)) != NULL ) {
1785 if( WS_dup_se(pwsi, serv) ) {
1786 WSASetLastError(NO_ERROR);
1787 return pwsi->se;
1788 }
1789 else WSASetLastError(WSAENOBUFS);
1790 }
1791 else WSASetLastError(WSANO_DATA);
1792 }
1793 else WSASetLastError(WSANOTINITIALISED);
1794 return NULL;
1795}
1796//******************************************************************************
1797//******************************************************************************
1798ODINFUNCTION2(struct ws_servent *,OS2getservbyname,
1799 const char *, name,
1800 const char *, proto)
1801{
1802 LPWSINFO pwsi = WINSOCK_GetIData();
1803
1804 if( pwsi )
1805 {
1806 struct servent *serv;
1807 if( (serv = getservbyname((char *)name, (char *)proto)) != NULL ) {
1808 if( WS_dup_se(pwsi, serv) ) {
1809 WSASetLastError(NO_ERROR);
1810 return pwsi->se;
1811 }
1812 else WSASetLastError(WSAENOBUFS);
1813 }
1814 else WSASetLastError(WSANO_DATA);
1815 }
1816 else WSASetLastError(WSANOTINITIALISED);
1817 return NULL;
1818}
1819//******************************************************************************
1820//******************************************************************************
1821ODINFUNCTION1(struct ws_protoent *,OS2getprotobynumber,
1822 int,number)
1823{
1824 LPWSINFO pwsi = WINSOCK_GetIData();
1825
1826 if( pwsi )
1827 {
1828 struct protoent* proto;
1829 if( (proto = getprotobynumber(number)) != NULL ) {
1830 if( WS_dup_pe(pwsi, proto) ) {
1831 WSASetLastError(NO_ERROR);
1832 return pwsi->pe;
1833 }
1834 else WSASetLastError(WSAENOBUFS);
1835 }
1836 else WSASetLastError(WSANO_DATA);
1837 }
1838 else WSASetLastError(WSANOTINITIALISED);
1839 return NULL;
1840}
1841//******************************************************************************
1842//******************************************************************************
1843ODINFUNCTION1(struct ws_protoent *,OS2getprotobyname,
1844 const char *,name)
1845{
1846 LPWSINFO pwsi = WINSOCK_GetIData();
1847
1848 if( pwsi )
1849 {
1850 struct protoent * proto;
1851 if( (proto = getprotobyname((char *)name)) != NULL ) {
1852 if(WS_dup_pe(pwsi, proto)) {
1853 WSASetLastError(NO_ERROR);
1854 return pwsi->pe;
1855 }
1856 else WSASetLastError(WSAENOBUFS);
1857 }
1858 else WSASetLastError((h_errno < 0) ? wsaErrno() : wsaHerrno());
1859 }
1860 else WSASetLastError(WSANOTINITIALISED);
1861 return NULL;
1862}
1863//******************************************************************************
1864//******************************************************************************
Note: See TracBrowser for help on using the repository browser.