|
|
1.1 root 1: /*
2: * UAE - The Un*x Amiga Emulator
3: *
4: * bsdsocket.library emulation - Win32 OS-dependent part
5: *
6: * Copyright 1997,98 Mathias Ortmann
7: *
8: */
9:
10: #include <windows.h>
11: #include <winsock.h>
12:
13: #include "sysconfig.h"
14: #include "sysdeps.h"
15:
16: #include <stddef.h>
17:
18: #include "config.h"
19: #include "options.h"
20: #include "include/memory.h"
21: #include "custom.h"
22: #include "readcpu.h"
23: #include "newcpu.h"
24: #include "autoconf.h"
25: #include "bsdsocket.h"
26:
27: CRITICAL_SECTION csSigQueueLock;
28:
29: DWORD threadid;
30:
31: #define THREAD(func,arg) CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)func,(LPVOID)arg,0,&threadid)
32:
33: #define SETERRNO seterrno(sb,WSAGetLastError()-WSABASEERR)
34: #define SETHERRNO setherrno(sb,WSAGetLastError()-WSABASEERR)
35: #define WAITSIGNAL waitsig(sb)
36:
37: #define SETSIGNAL addtosigqueue(sb,0)
38: #define CANCELSIGNAL cancelsig(sb)
39:
40: #define BEGINBLOCKING if (sb->ftable[sd-1] & SF_BLOCKING) sb->ftable[sd-1] |= SF_BLOCKINGINPROGRESS
41: #define ENDBLOCKING sb->ftable[sd-1] &= ~SF_BLOCKINGINPROGRESS
42:
43: static WSADATA wsbData;
44:
45: int PASCAL WSAEventSelect(SOCKET,HANDLE,long);
46:
47: #define MAX_SELECT_THREADS 64
48: static HANDLE hThreads[MAX_SELECT_THREADS];
49: uae_u32 *threadargs[MAX_SELECT_THREADS];
50: static HANDLE hEvents[MAX_SELECT_THREADS];
51:
52: static HANDLE hConnectThread;
53: static HANDLE hConnectEvent, hConnectEventReply;
54: static void thread_connect(void);
55:
56: int init_socket_layer(void)
57: {
58: SOCKET dummy;
59: DWORD lasterror;
60:
61: if (WSAStartup(2, &wsbData))
62: {
63: lasterror = WSAGetLastError();
64:
65: if (lasterror == WSAVERNOTSUPPORTED) write_log("Please upgrade to WinSock2.\n");
66: else write_log("bsdsocket: ERROR: Unable to initialize Windows socket layer! Error code: %d\n",lasterror);
67: return 0;
68: }
69:
70: InitializeCriticalSection(&csSigQueueLock);
71:
72: // make sure WSP/NSPStartup gets called from within the regular stack
73: // (Windows 95/98 need this)
74: if ((dummy = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) != INVALID_SOCKET) closesocket(dummy);
75: else write_log("bsdsocket: ERROR: WSPStartup/NSPStartup failed! Error code: %d\n",WSAGetLastError());
76:
77: if (hConnectThread == NULL)
78: {
79: hConnectThread = THREAD(thread_connect,NULL);
80: hConnectEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
81: hConnectEventReply = CreateEvent(NULL,FALSE,FALSE,NULL);
82: }
83:
84: return 1;
85: }
86:
87: void deinit_socket_layer(void)
88: {
89: WSACleanup();
90: }
91:
92: void locksigqueue(void)
93: {
94: EnterCriticalSection(&csSigQueueLock);
95: }
96:
97: void unlocksigqueue(void)
98: {
99: LeaveCriticalSection(&csSigQueueLock);
100: }
101:
102: // Asynchronous completion notification
103:
104: // We use window messages posted to hAmigaWnd in the range from 0xb000 to 0xb000+MAXPENDINGASYNC*2
105: // Socket events cause even-numbered messages, task events odd-numbered messages
106: // Message IDs are allocated on a round-robin basis and deallocated by the main thread.
107:
108: // WinSock tends to choke on WSAAsyncCancelMessage(s,w,m,0,0) called too often with an event pending
109:
110: // @@@ Enabling all socket event messages for every socket by default and basing things on that would
111: // be cleaner (and allow us to write a select() emulation that doesn't need to be kludge-aborted).
112: // However, the latency of the message queue is too high for that at the moment (setting up a dummy
113: // window from a separate thread would fix that).
114:
115: // Blocking sockets with asynchronous event notification are currently not safe to use.
116:
117: struct socketbase *asyncsb[MAXPENDINGASYNC];
118: SOCKET asyncsock[MAXPENDINGASYNC];
119: uae_u32 asyncsd[MAXPENDINGASYNC];
120: int asyncindex;
121:
122: int host_sbinit(SB)
123: {
124: sb->sockAbort = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
125:
126: if (sb->sockAbort == INVALID_SOCKET) return 0;
127: if ((sb->hEvent = CreateEvent(NULL,FALSE,FALSE,NULL)) == NULL) return 0;
128:
129: sb->mtable = calloc(sb->dtablesize,sizeof(*sb->mtable));
130:
131: return 1;
132: }
133:
134: void host_closesocketquick(int s)
135: {
136: BOOL true = 1;
137:
138: setsockopt((SOCKET)s,SOL_SOCKET,SO_DONTLINGER,(char *)&true,sizeof(true));
139: closesocket((SOCKET)s);
140: }
141:
142: void host_sbcleanup(SB)
143: {
144: int i;
145:
146: for (i = 0; i < MAXPENDINGASYNC; i++) if (asyncsb[i] == sb) asyncsb[i] = NULL;
147:
148: if (sb->hEvent != NULL) CloseHandle(sb->hEvent);
149: if (sb->hAsyncTask) WSACancelAsyncRequest(sb->hAsyncTask);
150:
151: for (i = sb->dtablesize; i--; )
152: {
153: if (sb->dtable[i] != (int)INVALID_SOCKET) host_closesocketquick(sb->dtable[i]);
154:
155: if (sb->mtable[i]) asyncsb[(sb->mtable[i]-0xb000)/2] = NULL;
156: }
157:
158: closesocket(sb->sockAbort);
159:
160: free(sb->mtable);
161: }
162:
163: void host_sbreset(void)
164: {
165: memset(asyncsb,0,sizeof asyncsb);
166: memset(asyncsock,0,sizeof asyncsock);
167: memset(asyncsd,0,sizeof asyncsd);
168: memset(threadargs,0,sizeof threadargs);
169: }
170:
171: void sockmsg(unsigned int msg, unsigned long wParam, unsigned long lParam)
172: {
173: SB;
174: unsigned int index;
175: int sdi;
176:
177: index = (msg-0xb000)/2;
178: sb = asyncsb[index];
179:
180: if (!(msg & 1))
181: {
182: // is this one really for us?
183: if ((SOCKET)wParam != asyncsock[index])
184: {
185: // cancel socket event
186: WSAAsyncSelect((SOCKET)wParam,hAmigaWnd,0,0);
187: return;
188: }
189:
190: sdi = asyncsd[index]-1;
191:
192: // asynchronous socket event?
193: if (sb && !(sb->ftable[sdi] & SF_BLOCKINGINPROGRESS) && sb->mtable[sdi])
194: {
195: long wsbevents = WSAGETSELECTEVENT(lParam);
196: int fmask = 0;
197:
198: // regular socket event?
199: if (wsbevents & FD_READ) fmask = REP_READ;
200: else if (wsbevents & FD_WRITE) fmask = REP_WRITE;
201: else if (wsbevents & FD_OOB) fmask = REP_OOB;
202: else if (wsbevents & FD_ACCEPT) fmask = REP_ACCEPT;
203: else if (wsbevents & FD_CONNECT) fmask = REP_CONNECT;
204: else if (wsbevents & FD_CLOSE) fmask = REP_CLOSE;
205:
206: // error?
207: if (WSAGETSELECTERROR(lParam)) fmask |= REP_ERROR;
208:
209: // notify
210: if (sb->ftable[sdi] & fmask) sb->ftable[sdi] |= fmask<<8;
211:
212: addtosigqueue(sb,1);
213: return;
214: }
215: }
216:
217: locksigqueue();
218:
219: if (sb != NULL)
220: {
221: if (msg & 1)
222: {
223: // is this one really for us?
224: if (sb->hAsyncTask != (void *)~0L && (void *)wParam != sb->hAsyncTask)
225: {
226: unlocksigqueue();
227: return;
228: }
229: }
230:
231: asyncsb[index] = NULL;
232:
233: if (WSAGETASYNCERROR(lParam))
234: {
235: seterrno(sb,WSAGETASYNCERROR(lParam)-WSABASEERR);
236: if (sb->sb_errno >= 1001 && sb->sb_errno <= 1005) setherrno(sb,sb->sb_errno-1000);
237: else if (sb->sb_errno == 55) // ENOBUFS
238: write_log("bsdsocket: ERROR: Buffer overflow - %d bytes requested\n",WSAGETASYNCBUFLEN(lParam));
239: }
240: else seterrno(sb,0);
241:
242: if (msg & 1) sb->hAsyncTask = 0;
243:
244: SETSIGNAL;
245: }
246:
247: unlocksigqueue();
248: }
249:
250: static unsigned int allocasyncmsg(SB,uae_u32 sd,SOCKET s)
251: {
252: int i;
253:
254: locksigqueue();
255:
256: for (i = asyncindex+1; i != asyncindex; i++)
257: {
258: if (i == MAXPENDINGASYNC) i = 0;
259:
260: if (!asyncsb[i])
261: {
262: asyncsb[i] = sb;
263: if (++asyncindex == MAXPENDINGASYNC) asyncindex = 0;
264: unlocksigqueue();
265:
266: if (s == INVALID_SOCKET)
267: {
268: sb->hAsyncTask = (void *)~0L; // set wildcard value to prevent race condition
269: return i*2+0xb001;
270: }
271: else
272: {
273: asyncsd[i] = sd;
274: asyncsock[i] = s;
275: return i*2+0xb000;
276: }
277: }
278: }
279:
280: unlocksigqueue();
281:
282: seterrno(sb,12); // ENOMEM
283: write_log("bsdsocket: ERROR: Async operation completion table overflow\n");
284:
285: return 0;
286: }
287:
288: static void cancelasyncmsg(unsigned int wMsg)
289: {
290: SB;
291:
292: wMsg = (wMsg-0xb000)/2;
293:
294: sb = asyncsb[wMsg];
295:
296: if (sb != NULL)
297: {
298: asyncsb[wMsg] = NULL;
299: CANCELSIGNAL;
300: }
301: }
302:
303: void sockabort(SB)
304: {
305: locksigqueue();
306:
307: if (sb->hAsyncTask)
308: {
309: if (WSACancelAsyncRequest(sb->hAsyncTask)) write_log("bsdsocket: ERROR: WSACancelAsyncRequest() failed with error code %d\n",WSAGetLastError());
310: sb->hAsyncTask = 0;
311: }
312:
313: unlocksigqueue();
314: }
315:
316: // address cleaning
317: static void prephostaddr(SOCKADDR_IN *addr)
318: {
319: addr->sin_family = AF_INET;
320: }
321:
322: static void prepamigaaddr(struct sockaddr *realpt, int len)
323: {
324: // little endian address family value to the byte sin_family member
325: ((char *)realpt)[1] = *((char *)realpt);
326:
327: // set size of address
328: *((char *)realpt) = len;
329: }
330:
331: int host_socket(SB, int af, int type, int protocol)
332: {
333: int sd;
334: SOCKET s;
335: unsigned long nonblocking = 1;
336:
337: TRACE(("socket(%d,%d,%d) -> ",af,type,protocol));
338:
339: if ((s = socket(af,type,protocol)) == INVALID_SOCKET)
340: {
341: SETERRNO;
342: TRACE(("failed (%d)\n",sb->sb_errno));
343: return -1;
344: }
345: else sd = getsd(sb,(int)s);
346:
347: sb->ftable[sd-1] = SF_BLOCKING;
348: ioctlsocket(s,FIONBIO,&nonblocking);
349: TRACE(("%d\n",sd));
350:
351: return sd;
352: }
353:
354: uae_u32 host_bind(SB, uae_u32 sd, uae_u32 name, uae_u32 namelen)
355: {
356: char buf[MAXADDRLEN];
357: uae_u32 success = 0;
358: SOCKET s;
359:
360: TRACE(("bind(%d,0x%lx,%d) -> ",sd,name,namelen));
361: s = getsock(sb, sd);
362:
363: if (s != INVALID_SOCKET)
364: {
365: if (namelen <= sizeof buf)
366: {
367: memcpy(buf,get_real_address(name),namelen);
368:
369: // some Amiga programs set this field to bogus values
370: prephostaddr((SOCKADDR_IN *)buf);
371:
372: if ((success = bind(s,(struct sockaddr *)buf,namelen)) != 0)
373: {
374: SETERRNO;
375: TRACE(("failed (%d)\n",sb->sb_errno));
376: }
377: else TRACE(("OK\n"));
378: }
379: else write_log("bsdsocket: ERROR: Excessive namelen (%d) in bind()!\n",namelen);
380: }
381:
382: return success;
383: }
384:
385: uae_u32 host_listen(SB, uae_u32 sd, uae_u32 backlog)
386: {
387: SOCKET s;
388: uae_u32 success = -1;
389:
390: TRACE(("listen(%d,%d) -> ",sd,backlog));
391: s = getsock(sb, sd);
392:
393: if (s != INVALID_SOCKET)
394: {
395: if ((success = listen(s,backlog)) != 0)
396: {
397: SETERRNO;
398: TRACE(("failed (%d)\n",sb->sb_errno));
399: }
400: else TRACE(("OK\n"));
401: }
402:
403: return success;
404: }
405:
406: void host_accept(SB, uae_u32 sd, uae_u32 name, uae_u32 namelen)
407: {
408: struct sockaddr *rp_name;
409: int hlen;
410: SOCKET s, s2;
411: int success = 0;
412: unsigned int wMsg;
413:
414: rp_name = (struct sockaddr *)get_real_address(name);
415: hlen = get_long(namelen);
416: TRACE(("accept(%d,%d,%d) -> ",sd,name,hlen));
417:
418: s = (SOCKET)getsock(sb,(int)sd);
419:
420: if (s != INVALID_SOCKET)
421: {
422: BEGINBLOCKING;
423:
424: s2 = accept(s,rp_name,&hlen);
425:
426: if (s2 == INVALID_SOCKET)
427: {
428: SETERRNO;
429:
430: if (sb->ftable[sd-1] & SF_BLOCKING && sb->sb_errno == WSAEWOULDBLOCK-WSABASEERR)
431: {
432: if ((wMsg = allocasyncmsg(sb,sd,s)) != 0)
433: {
434: WSAAsyncSelect(s,hAmigaWnd,wMsg,FD_ACCEPT);
435:
436: WAITSIGNAL;
437:
438: cancelasyncmsg(wMsg);
439:
440: if (sb->eintr)
441: {
442: TRACE(("[interrupted]\n"));
443: ENDBLOCKING;
444: return;
445: }
446:
447: s2 = accept(s,rp_name,&hlen);
448:
449: if (s2 == INVALID_SOCKET)
450: {
451: SETERRNO;
452:
453: if (sb->sb_errno == WSAEWOULDBLOCK-WSABASEERR) write_log("bsdsocket: ERRRO: accept() would block despite FD_ACCEPT message\n");
454: }
455: }
456: }
457: }
458:
459: if (s2 == INVALID_SOCKET)
460: {
461: sb->resultval = -1;
462: TRACE(("failed (%d)\n",sb->sb_errno));
463: }
464: else
465: {
466: sb->resultval = getsd(sb, s2);
467: sb->ftable[sb->resultval-1] = sb->ftable[sd-1]; // new socket inherits the old socket's properties
468:
469: prepamigaaddr(rp_name,hlen);
470: put_long(namelen,hlen);
471: TRACE(("%d/%d\n",sb->resultval,hlen));
472: }
473:
474: ENDBLOCKING;
475: }
476: }
477:
478: // Windows 9x workaround... Microsoft blows chunks.
479: volatile SOCKET connect_s;
480: volatile uae_u32 connect_name, connect_namelen;
481: struct socketbase *connect_sb;
482:
483: static void thread_connect(void)
484: {
485: char buf[MAXADDRLEN];
486: SB;
487:
488: for (;;)
489: {
490: WaitForSingleObject(hConnectEvent,INFINITE);
491:
492: if ((sb = connect_sb) != NULL)
493: {
494: memcpy(buf,get_real_address(connect_name),connect_namelen);
495: prephostaddr((SOCKADDR_IN *)buf);
496:
497: if ((sb->resultval = connect(connect_s,(struct sockaddr *)buf,connect_namelen)) != 0) SETERRNO;
498:
499: connect_sb = NULL;
500: SetEvent(hConnectEventReply);
501: }
502: }
503: }
504:
505: void host_connect(SB, uae_u32 sd, uae_u32 name, uae_u32 namelen)
506: {
507: SOCKET s;
508: int success = 0;
509: unsigned int wMsg;
510:
511: TRACE(("connect(%d,0x%lx,%d) -> ",sd,name,namelen));
512:
513: s = (SOCKET)getsock(sb,(int)sd);
514:
515: if (s != INVALID_SOCKET)
516: {
517: if (namelen <= MAXADDRLEN)
518: {
519: if ((wMsg = allocasyncmsg(sb,sd,s)) != 0)
520: {
521: WSAAsyncSelect(s,hAmigaWnd,wMsg,FD_CONNECT);
522:
523: BEGINBLOCKING;
524:
525: connect_s = s;
526: connect_name = name;
527: connect_namelen = namelen;
528: connect_sb = sb;
529: SetEvent(hConnectEvent);
530: WaitForSingleObject(hConnectEventReply,INFINITE);
531:
532: if (sb->resultval)
533: {
534: if (sb->sb_errno == WSAEWOULDBLOCK-WSABASEERR)
535: {
536: if (sb->ftable[sd-1] & SF_BLOCKING)
537: {
538: seterrno(sb,0);
539:
540: WAITSIGNAL;
541:
542: if (sb->eintr)
543: {
544: // Destroy socket to cancel abort, replace it with fake socket to enable proper closing.
545: // This is in accordance with BSD behaviour.
546: closesocket(s);
547: sb->dtable[sd-1] = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
548: }
549: }
550: else seterrno(sb,36); // EINPROGRESS
551: }
552: }
553:
554: ENDBLOCKING;
555:
556: cancelasyncmsg(wMsg);
557: }
558: }
559: else write_log("bsdsock: WARNING: Excessive namelen (%d) in connect()!\n",namelen);
560: }
561:
562: TRACE(("%d\n",sb->sb_errno));
563: }
564:
565: // @@@ move sendto() to an extra thread to make UDP-based apps work under Windows 9x
566: void host_sendto(SB, uae_u32 sd, uae_u32 msg, uae_u32 len, uae_u32 flags, uae_u32 to, uae_u32 tolen)
567: {
568: SOCKET s;
569: char *realpt;
570: unsigned int wMsg;
571: char buf[MAXADDRLEN];
572:
573: #ifdef TRACING_ENABLED
574: if (to) TRACE(("sendto(%d,0x%lx,%d,0x%lx,0x%lx,%d) -> ",sd,msg,len,flags,to,tolen))
575: else TRACE(("send(%d,0x%lx,%d,%d) -> ",sd,msg,len,flags));
576: #endif
577:
578: s = getsock(sb,sd);
579:
580: if (s != INVALID_SOCKET)
581: {
582: realpt = get_real_address(msg);
583:
584: if (to)
585: {
586: if (tolen > sizeof buf) write_log("bsdsocket: WARNING: Target address in sendto() too large (%d)!\n",tolen);
587: else
588: {
589: memcpy(buf,get_real_address(to),tolen);
590: // some Amiga software sets this field to bogus values
591: prephostaddr((SOCKADDR_IN *)buf);
592: }
593: }
594:
595: BEGINBLOCKING;
596:
597: for (;;)
598: {
599: sb->resultval = to ? sendto(s,realpt,len,flags,(struct sockaddr *)buf,tolen) : send(s,realpt,len,flags);
600:
601: if (sb->resultval == -1)
602: {
603: SETERRNO;
604: if (sb->sb_errno != WSAEWOULDBLOCK-WSABASEERR || !(sb->ftable[sd-1] & SF_BLOCKING)) break;
605: }
606: else
607: {
608: realpt += sb->resultval;
609: len -= sb->resultval;
610:
611: if (len <= 0) break;
612: else continue;
613: }
614:
615: if ((wMsg = allocasyncmsg(sb,sd,s)) != 0)
616: {
617: WSAAsyncSelect(s,hAmigaWnd,wMsg,FD_WRITE);
618:
619: WAITSIGNAL;
620:
621: cancelasyncmsg(wMsg);
622:
623: if (sb->eintr)
624: {
625: TRACE(("[interrupted]\n"));
626: return;
627: }
628: }
629: else break;
630: }
631:
632: ENDBLOCKING;
633: }
634: else sb->resultval = -1;
635:
636: #ifdef TRACING_ENABLED
637: if (sb->resultval == -1) TRACE(("failed (%d)\n",sb->sb_errno))
638: else TRACE(("%d\n",sb->resultval));
639: #endif
640: }
641:
642: void host_recvfrom(SB, uae_u32 sd, uae_u32 msg, uae_u32 len, uae_u32 flags, uae_u32 addr, uae_u32 addrlen)
643: {
644: SOCKET s;
645: char *realpt;
646: struct sockaddr *rp_addr = NULL;
647: int hlen;
648: char buf[MAXADDRLEN];
649: unsigned int wMsg;
650:
651: #ifdef TRACING_ENABLED
652: if (addr) TRACE(("recvfrom(%d,0x%lx,%d,0x%lx,0x%lx,0x%lx) -> ",sd,msg,len,flags,addr,addrlen))
653: else TRACE(("recv(%d,0x%lx,%d,0x%lx) -> ",sd,msg,len,flags));
654: #endif
655:
656: s = getsock(sb,sd);
657:
658: if (s != INVALID_SOCKET)
659: {
660: realpt = get_real_address(msg);
661:
662: if (addr)
663: {
664: hlen = get_long(addrlen);
665: rp_addr = (struct sockaddr *)get_real_address(addr);
666: }
667:
668: BEGINBLOCKING;
669:
670: for (;;)
671: {
672: sb->resultval = addr ? recvfrom(s,realpt,len,flags,rp_addr,&hlen) : recv(s,realpt,len,flags);
673:
674: if (sb->resultval == -1)
675: {
676: SETERRNO;
677:
678: if (sb->sb_errno == WSAEWOULDBLOCK-WSABASEERR && sb->ftable[sd-1] & SF_BLOCKING)
679: {
680: if ((wMsg = allocasyncmsg(sb,sd,s)) != 0)
681: {
682: WSAAsyncSelect(s,hAmigaWnd,wMsg,FD_READ);
683:
684: WAITSIGNAL;
685:
686: cancelasyncmsg(wMsg);
687:
688: if (sb->eintr)
689: {
690: TRACE(("[interrupted]\n"));
691: return;
692: }
693: }
694: else break;
695: }
696: else break;
697: }
698: else break;
699: }
700:
701: ENDBLOCKING;
702:
703: if (addr)
704: {
705: prepamigaaddr(rp_addr,hlen);
706: put_long(addrlen,hlen);
707: }
708: }
709: else sb->resultval = -1;
710:
711: #ifdef TRACING_ENABLED
712: if (sb->resultval == -1) TRACE(("failed (%d)\n",sb->sb_errno))
713: else TRACE(("%d\n",sb->resultval));
714: #endif
715: }
716:
717: uae_u32 host_shutdown(SB, uae_u32 sd, uae_u32 how)
718: {
719: SOCKET s;
720:
721: TRACE(("shutdown(%d,%d) -> ",sd,how));
722:
723: s = getsock(sb,sd);
724:
725: if (s != INVALID_SOCKET)
726: {
727: if (shutdown(s,how))
728: {
729: SETERRNO;
730: TRACE(("failed (%d)\n",sb->sb_errno));
731: }
732: else
733: {
734: TRACE(("OK\n"));
735: return 0;
736: }
737: }
738:
739: return -1;
740: }
741:
742: void host_setsockopt(SB, uae_u32 sd, uae_u32 level, uae_u32 optname, uae_u32 optval, uae_u32 len)
743: {
744: SOCKET s;
745: char buf[MAXADDRLEN];
746:
747: TRACE(("setsockopt(%d,%d,0x%lx,0x%lx,%d) -> ",sd,(short)level,optname,optval,len));
748:
749: s = getsock(sb,sd);
750:
751: if (s != INVALID_SOCKET)
752: {
753: if (len > sizeof buf)
754: {
755: write_log("bsdsocket: WARNING: Excessive optlen in setsockopt() (%d)\n",len);
756: len = sizeof buf;
757: }
758:
759: if (level == SOL_SOCKET && optname == SO_LINGER)
760: {
761: ((LINGER *)buf)->l_onoff = get_long(optval);
762: ((LINGER *)buf)->l_linger = get_long(optval+4);
763: }
764: else
765: {
766: if (len == 4) *(long *)buf = get_long(optval);
767: else if (len == 2) *(short *)buf = get_word(optval);
768: else write_log("bsdsocket: ERROR: Unknown optlen (%d) in setsockopt(%d,%d)\n",level,optname);
769: }
770:
771: // handle SO_EVENTMASK
772: if (level == 0xffff && optname == 0x2001)
773: {
774: long wsbevents = 0;
775: uae_u32 eventflags = get_long(optval);
776:
777: sb->ftable[sd-1] = (sb->ftable[sd-1] & ~REP_ALL) | (eventflags & REP_ALL);
778:
779: if (eventflags & REP_ACCEPT) wsbevents |= FD_ACCEPT;
780: if (eventflags & REP_CONNECT) wsbevents |= FD_CONNECT;
781: if (eventflags & REP_OOB) wsbevents |= FD_OOB;
782: if (eventflags & REP_READ) wsbevents |= FD_READ;
783: if (eventflags & REP_WRITE) wsbevents |= FD_WRITE;
784: if (eventflags & REP_CLOSE) wsbevents |= FD_CLOSE;
785:
786: if (sb->mtable[sd-1] || (sb->mtable[sd-1] = allocasyncmsg(sb,sd,s)))
787: {
788: WSAAsyncSelect(s,hAmigaWnd,sb->mtable[sd-1],wsbevents);
789: sb->resultval = 0;
790: }
791: else sb->resultval = -1;
792: }
793: else sb->resultval = setsockopt(s,level,optname,buf,len);
794:
795: if (!sb->resultval)
796: {
797: TRACE(("OK\n"));
798: return;
799: }
800: else SETERRNO;
801:
802: TRACE(("failed (%d)\n",sb->sb_errno));
803: }
804: }
805:
806: uae_u32 host_getsockopt(SB, uae_u32 sd, uae_u32 level, uae_u32 optname, uae_u32 optval, uae_u32 optlen)
807: {
808: SOCKET s;
809: char buf[MAXADDRLEN];
810: int len = sizeof(buf);
811:
812: TRACE(("getsockopt(%d,%d,0x%lx,0x%lx,0x%lx) -> ",sd,(short)level,optname,optval,optlen));
813:
814: s = getsock(sb,sd);
815:
816: if (s != INVALID_SOCKET)
817: {
818: if (!getsockopt(s,level,optname,buf,&len))
819: {
820: if (level == SOL_SOCKET && optname == SO_LINGER)
821: {
822: put_long(optval,((LINGER *)buf)->l_onoff);
823: put_long(optval+4,((LINGER *)buf)->l_linger);
824: }
825: else
826: {
827: if (len == 4) put_long(optval,*(long *)buf);
828: else if (len == 2) put_word(optval,*(short *)buf);
829: else write_log("bsdsocket: ERROR: Unknown optlen (%d) in setsockopt(%d,%d)\n",level,optname);
830: }
831:
832: // put_long(optlen,len); // some programs pass the actual ength instead of a pointer to the length, so...
833: TRACE(("OK (%d,%d)\n",len,*(long *)buf));
834: return 0;
835: }
836: else
837: {
838: SETERRNO;
839: TRACE(("failed (%d)\n",sb->sb_errno));
840: }
841: }
842:
843: return -1;
844: }
845:
846: uae_u32 host_getsockname(SB, uae_u32 sd, uae_u32 name, uae_u32 namelen)
847: {
848: SOCKET s;
849: int len;
850: struct sockaddr *rp_name;
851:
852: len = get_long(namelen);
853:
854: TRACE(("getsockname(%d,0x%lx,%d) -> ",sd,name,len));
855:
856: s = getsock(sb,sd);
857:
858: if (s != INVALID_SOCKET)
859: {
860: rp_name = (struct sockaddr *)get_real_address(name);
861:
862: if (getsockname(s,rp_name,&len))
863: {
864: SETERRNO;
865: TRACE(("failed (%d)\n",sb->sb_errno));
866: }
867: else
868: {
869: TRACE(("%d\n",len));
870: prepamigaaddr(rp_name,len);
871: put_long(namelen,len);
872: return 0;
873: }
874: }
875:
876: return -1;
877: }
878:
879: uae_u32 host_getpeername(SB, uae_u32 sd, uae_u32 name, uae_u32 namelen)
880: {
881: SOCKET s;
882: int len;
883: struct sockaddr *rp_name;
884:
885: len = get_long(namelen);
886:
887: TRACE(("getpeername(%d,0x%lx,%d) -> ",sd,name,len));
888:
889: s = getsock(sb,sd);
890:
891: if (s != INVALID_SOCKET)
892: {
893: rp_name = (struct sockaddr *)get_real_address(name);
894:
895: if (getpeername(s,rp_name,&len))
896: {
897: SETERRNO;
898: TRACE(("failed (%d)\n",sb->sb_errno));
899: }
900: else
901: {
902: TRACE(("%d\n",len));
903: prepamigaaddr(rp_name,len);
904: put_long(namelen,len);
905: return 0;
906: }
907: }
908:
909: return -1;
910: }
911:
912: uae_u32 host_IoctlSocket(SB, uae_u32 sd, uae_u32 request, uae_u32 arg)
913: {
914: SOCKET s;
915: uae_u32 data;
916: int success = SOCKET_ERROR;
917:
918: TRACE(("IoctlSocket(%d,0x%lx,0x%lx) ",sd,request,arg));
919:
920: s = getsock(sb,sd);
921:
922: if (s != INVALID_SOCKET)
923: {
924: switch (request)
925: {
926: case FIONBIO:
927: TRACE(("[FIONBIO] -> "));
928: if (get_long(arg))
929: {
930: TRACE(("nonblocking\n"));
931: sb->ftable[sd-1] &= ~SF_BLOCKING;
932: }
933: else
934: {
935: TRACE(("blocking\n"));
936: sb->ftable[sd-1] |= SF_BLOCKING;
937: }
938: success = 0;
939: break;
940: case FIONREAD:
941: ioctlsocket(s,request,(u_long *)&data);
942: TRACE(("[FIONREAD] -> %d\n",data));
943: put_long(arg,data);
944: success = 0;
945: break;
946: case FIOASYNC:
947: if (get_long(arg))
948: {
949: sb->ftable[sd-1] |= REP_ALL;
950:
951: TRACE(("[FIOASYNC] -> enabled\n"));
952: if (sb->mtable[sd-1] || (sb->mtable[sd-1] = allocasyncmsg(sb,sd,s)))
953: {
954: WSAAsyncSelect(s,hAmigaWnd,sb->mtable[sd-1],FD_ACCEPT | FD_CONNECT | FD_OOB | FD_READ | FD_WRITE | FD_CLOSE);
955: success = 0;
956: break;
957: }
958: }
959: else write_log(("bsdsocket: WARNING: FIOASYNC disabling unsupported.\n"));
960:
961: success = -1;
962: break;
963: default:
964: write_log("bsdsocket: WARNING: Unknown IoctlSocket request: 0x%08lx\n",request);
965: seterrno(sb,22); // EINVAL
966: }
967: }
968:
969: return success;
970: }
971:
972: int host_CloseSocket(SB, int sd)
973: {
974: unsigned int wMsg;
975: SOCKET s;
976:
977: TRACE(("CloseSocket(%d) -> ",sd));
978:
979: s = getsock(sb,sd);
980:
981: if (s != INVALID_SOCKET)
982: {
983: if (sb->mtable[sd-1])
984: {
985: asyncsb[(sb->mtable[sd-1]-0xb000)/2] = NULL;
986: sb->mtable[sd-1] = 0;
987: }
988:
989: BEGINBLOCKING;
990:
991: for (;;)
992: {
993: if (!closesocket(s))
994: {
995: releasesock(sb,sd);
996: TRACE(("OK\n"));
997: return 0;
998: }
999:
1000: SETERRNO;
1001:
1002: if (sb->sb_errno != WSAEWOULDBLOCK-WSABASEERR || !(sb->ftable[sd-1] & SF_BLOCKING)) break;
1003:
1004: if ((wMsg = allocasyncmsg(sb,sd,s)) != 0)
1005: {
1006: WSAAsyncSelect(s,hAmigaWnd,wMsg,FD_CLOSE);
1007:
1008: WAITSIGNAL;
1009:
1010: cancelasyncmsg(wMsg);
1011:
1012: if (sb->eintr)
1013: {
1014: TRACE(("[interrupted]\n"));
1015: break;
1016: }
1017: }
1018: else break;
1019: }
1020:
1021: ENDBLOCKING;
1022: }
1023:
1024: TRACE(("failed (%d)\n",sb->sb_errno));
1025:
1026: return -1;
1027: }
1028:
1029: // For the sake of efficiency, we do not malloc() the fd_sets here.
1030: // 64 sockets should be enough for everyone.
1031: static void makesocktable(SB, uae_u32 fd_set_amiga, struct fd_set *fd_set_win, int nfds, SOCKET addthis)
1032: {
1033: int i, j, maxbit;
1034: uae_u32 currlong, mask;
1035: SOCKET s;
1036:
1037: if (addthis != INVALID_SOCKET)
1038: {
1039: *fd_set_win->fd_array = addthis;
1040: fd_set_win->fd_count = 1;
1041: }
1042: else fd_set_win->fd_count = 0;
1043:
1044: if (!fd_set_amiga)
1045: {
1046: fd_set_win->fd_array[fd_set_win->fd_count] = INVALID_SOCKET;
1047: return;
1048: }
1049:
1050: if (nfds > sb->dtablesize)
1051: {
1052: write_log("bsdsock: ERROR: select()ing more sockets (%d) than socket descriptors available (%d)!\n",nfds,sb->dtablesize);
1053: nfds = sb->dtablesize;
1054: }
1055:
1056: for (j = 0; ; j += 32, fd_set_amiga += 4)
1057: {
1058: currlong = get_long(fd_set_amiga);
1059:
1060: mask = 1;
1061:
1062: for (i = 0; i < 32; i++, mask <<= 1)
1063: {
1064: if (i+j > nfds)
1065: {
1066: fd_set_win->fd_array[fd_set_win->fd_count] = INVALID_SOCKET;
1067: return;
1068: }
1069:
1070: if (currlong & mask)
1071: {
1072: s = getsock(sb,j+i);
1073:
1074: if (s != INVALID_SOCKET)
1075: {
1076: fd_set_win->fd_array[fd_set_win->fd_count++] = s;
1077:
1078: if (fd_set_win->fd_count >= FD_SETSIZE)
1079: {
1080: write_log("bsdsock: ERROR: select()ing more sockets (%d) than the hard-coded fd_set limit (%d) - please report\n",nfds,FD_SETSIZE);
1081: return;
1082: }
1083: }
1084: }
1085: }
1086: }
1087:
1088: fd_set_win->fd_array[fd_set_win->fd_count] = INVALID_SOCKET;
1089: }
1090:
1091: static void makesockbitfield(SB, uae_u32 fd_set_amiga, struct fd_set *fd_set_win, int nfds)
1092: {
1093: int n, i, j, val, mask;
1094: SOCKET currsock;
1095:
1096: for (n = 0; n < nfds; n += 32)
1097: {
1098: val = 0;
1099: mask = 1;
1100:
1101: for (i = 0; i < 32; i++, mask <<= 1)
1102: {
1103: if ((n || i) && (currsock = sb->dtable[n+i-1]) != INVALID_SOCKET)
1104: {
1105: for (j = fd_set_win->fd_count; j--; )
1106: {
1107: if (fd_set_win->fd_array[j] == currsock)
1108: {
1109: val |= mask;
1110: break;
1111: }
1112: }
1113: }
1114: }
1115:
1116: put_long(fd_set_amiga,val);
1117: }
1118: }
1119:
1120: static void fd_zero(uae_u32 fdset, uae_u32 nfds)
1121: {
1122: unsigned int i;
1123:
1124: for (i = 0; i < nfds; i += 32, fdset += 4) put_long(fdset,0);
1125: }
1126:
1127: // This seems to be the only way of implementing a cancelable WinSock2 select() call... sigh.
1128: static void thread_WaitSelect(uae_u32 index)
1129: {
1130: long nfds;
1131: uae_u32 readfds, writefds, exceptfds;
1132: uae_u32 timeout;
1133: uae_u32 sigmp;
1134: struct fd_set readsocks, writesocks, exceptsocks;
1135: struct timeval tv;
1136: uae_u32 *args;
1137:
1138: SB;
1139:
1140: for (;;)
1141: {
1142: WaitForSingleObject(hEvents[index],INFINITE);
1143:
1144: if ((args = threadargs[index]) != NULL)
1145: {
1146: sb = (struct socketbase *)*args;
1147: nfds = args[1];
1148: readfds = args[2];
1149: writefds = args[3];
1150: exceptfds = args[4];
1151: timeout = args[5];
1152:
1153: // construct descriptor tables
1154: makesocktable(sb,readfds,&readsocks,nfds,sb->sockAbort);
1155: if (writefds) makesocktable(sb,writefds,&writesocks,nfds,INVALID_SOCKET);
1156: if (exceptfds) makesocktable(sb,exceptfds,&exceptsocks,nfds,INVALID_SOCKET);
1157:
1158: if (timeout)
1159: {
1160: tv.tv_sec = get_long(timeout);
1161: tv.tv_usec = get_long(timeout+4);
1162: TRACE(("(timeout: %d.%06d) ",tv.tv_sec,tv.tv_usec))
1163: }
1164:
1165: TRACE(("-> "));
1166:
1167: sb->resultval = select(nfds+1,&readsocks,writefds ? &writesocks : NULL,exceptfds ? &exceptsocks : NULL,timeout ? &tv : 0);
1168: sb->needAbort = 0;
1169:
1170: if (sb->resultval == SOCKET_ERROR)
1171: {
1172: SETERRNO;
1173: TRACE(("failed (%d) - ",sb->sb_errno));
1174: if (readfds) fd_zero(readfds,nfds);
1175: if (writefds) fd_zero(writefds,nfds);
1176: if (exceptfds) fd_zero(exceptfds,nfds);
1177: }
1178: else
1179: {
1180: if (readfds) makesockbitfield(sb,readfds,&readsocks,nfds);
1181: if (writefds) makesockbitfield(sb,writefds,&writesocks,nfds);
1182: if (exceptfds) makesockbitfield(sb,exceptfds,&exceptsocks,nfds);
1183: }
1184:
1185: SETSIGNAL;
1186:
1187: threadargs[index] = NULL;
1188: SetEvent(sb->hEvent);
1189: }
1190: }
1191: }
1192:
1193: void __stdcall host_WaitSelect(SB, uae_u32 nfds, uae_u32 readfds, uae_u32 writefds, uae_u32 exceptfds, uae_u32 timeout, uae_u32 sigmp)
1194: {
1195: uae_u32 sigs, wssigs;
1196: int i;
1197:
1198: wssigs = sigmp ? get_long(sigmp) : 0;
1199:
1200: TRACE(("WaitSelect(%d,0x%lx,0x%lx,0x%lx,0x%lx,0x%lx) ",nfds,readfds,writefds,exceptfds,timeout,wssigs));
1201:
1202: if (!readfds && !writefds && !exceptfds && !timeout && !wssigs)
1203: {
1204: sb->resultval = 0;
1205: TRACE(("-> [ignored]\n"))
1206: return;
1207: }
1208:
1209: if (wssigs)
1210: {
1211: m68k_dreg(regs,0) = 0;
1212: m68k_dreg(regs,1) = wssigs;
1213: sigs = CallLib(get_long(4),-0x132) & wssigs; // SetSignal()
1214:
1215: if (sigs)
1216: {
1217: TRACE(("-> [preempted by signals 0x%08lx]\n",sigs & wssigs));
1218: put_long(sigmp,sigs & wssigs);
1219: fd_zero(readfds,nfds);
1220: fd_zero(writefds,nfds);
1221: fd_zero(exceptfds,nfds);
1222: sb->resultval = 0;
1223: seterrno(sb,0);
1224: return;
1225: }
1226: }
1227:
1228: ResetEvent(sb->hEvent);
1229:
1230: sb->needAbort = 1;
1231:
1232: for (i = 0; i < MAX_SELECT_THREADS; i++) if (hThreads[i] && !threadargs[i]) break;
1233:
1234: if (i >= MAX_SELECT_THREADS)
1235: {
1236: for (i = 0; i < MAX_SELECT_THREADS; i++) if (!hThreads[i])
1237: {
1238: if ((hEvents[i] = CreateEvent(NULL,FALSE,FALSE,NULL)) == NULL || (hThreads[i] = THREAD(thread_WaitSelect,i)) == NULL)
1239: {
1240: hThreads[i] = 0;
1241: write_log("bsdsocket: ERROR: Thread/Event creation failed - error code: %d\n",GetLastError());
1242: seterrno(sb,12); // ENOMEM
1243: sb->resultval = -1;
1244: return;
1245: }
1246:
1247: // this should improve responsiveness
1248: SetThreadPriority(hThreads[i],THREAD_PRIORITY_TIME_CRITICAL);
1249: break;
1250: }
1251: }
1252:
1253: if (i >= MAX_SELECT_THREADS) write_log("bsdsocket: ERROR: Too many select()s\n");
1254: else
1255: {
1256: SOCKET newsock = INVALID_SOCKET;
1257:
1258: threadargs[i] = (uae_u32 *)&sb;
1259:
1260: SetEvent(hEvents[i]);
1261:
1262: m68k_dreg(regs,0) = (((uae_u32)1)<<sb->signal)|sb->eintrsigs|wssigs;
1263: sigs = CallLib(get_long(4),-0x13e); // Wait()
1264:
1265: if (sb->needAbort)
1266: {
1267: if ((newsock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) == INVALID_SOCKET)
1268: write_log("bsdsocket: ERROR: Cannot create socket: %d\n",WSAGetLastError());
1269:
1270: closesocket(sb->sockAbort);
1271: }
1272:
1273: WaitForSingleObject(sb->hEvent,INFINITE);
1274:
1275: CANCELSIGNAL;
1276:
1277: if (newsock != INVALID_SOCKET) sb->sockAbort = newsock;
1278:
1279: put_long(sigmp,sigs & wssigs);
1280:
1281: if (sigs & sb->eintrsigs)
1282: {
1283: TRACE(("[interrupted]\n"));
1284: sb->resultval = -1;
1285: seterrno(sb,4); // EINTR
1286: }
1287: else if (sigs & wssigs)
1288: {
1289: TRACE(("[interrupted by signals 0x%08lx]\n",sigs & wssigs));
1290: sb->resultval = 0;
1291: seterrno(sb,0);
1292: }
1293: else TRACE(("%d\n",sb->resultval));
1294: }
1295: }
1296:
1297: uae_u32 host_Inet_NtoA(SB, uae_u32 in)
1298: {
1299: char *addr;
1300: struct in_addr ina;
1301: uae_u32 scratchbuf;
1302:
1303: *(uae_u32 *)&ina = htonl(in);
1304:
1305: TRACE(("Inet_NtoA(%lx) -> ",in));
1306:
1307: if ((addr = inet_ntoa(ina)) != NULL)
1308: {
1309: scratchbuf = m68k_areg(regs,6)+offsetof(struct UAEBSDBase,scratchbuf);
1310: strncpyha(scratchbuf,addr,SCRATCHBUFSIZE);
1311: TRACE(("%s\n",addr));
1312: return scratchbuf;
1313: }
1314: else SETERRNO;
1315:
1316: TRACE(("failed (%d)\n",sb->sb_errno));
1317:
1318: return 0;
1319: }
1320:
1321: uae_u32 host_inet_addr(uae_u32 cp)
1322: {
1323: uae_u32 addr;
1324: char *cp_rp;
1325:
1326: cp_rp = get_real_address(cp);
1327:
1328: addr = htonl(inet_addr(cp_rp));
1329:
1330: TRACE(("inet_addr(%s) -> 0x%08lx\n",cp_rp,addr));
1331:
1332: return addr;
1333: }
1334:
1335: void host_gethostbynameaddr(SB, uae_u32 name, uae_u32 namelen, long addrtype)
1336: {
1337: HOSTENT *h;
1338: int size, numaliases = 0, numaddr = 0;
1339: uae_u32 aptr, asize;
1340: char *name_rp;
1341: int i;
1342: uae_u32 addr;
1343: uae_u32 *addr_list[2];
1344:
1345: char buf[MAXGETHOSTSTRUCT];
1346: unsigned int wMsg = 0;
1347:
1348: name_rp = get_real_address(name);
1349:
1350: if (addrtype == -1)
1351: {
1352: TRACE(("gethostbyname(%s) -> ",name_rp));
1353:
1354: // workaround for numeric host "names"
1355: if ((addr = inet_addr(name_rp)) != INADDR_NONE)
1356: {
1357: seterrno(sb,0);
1358: ((HOSTENT *)buf)->h_name = name_rp;
1359: ((HOSTENT *)buf)->h_aliases = NULL;
1360: ((HOSTENT *)buf)->h_addrtype = AF_INET;
1361: ((HOSTENT *)buf)->h_length = 4;
1362: ((HOSTENT *)buf)->h_addr_list = (char **)&addr_list;
1363: addr_list[0] = &addr;
1364: addr_list[1] = NULL;
1365:
1366: goto kludge;
1367: }
1368: }
1369: else
1370: {
1371: TRACE(("gethostbyaddr(0x%lx,0x%lx,%ld) -> ",name,namelen,addrtype));
1372: }
1373:
1374: if ((wMsg = allocasyncmsg(sb,0,INVALID_SOCKET)) != 0)
1375: {
1376: if ((sb->hAsyncTask = addrtype == -1 ? WSAAsyncGetHostByName(hAmigaWnd,wMsg,name_rp,buf,sizeof buf) : WSAAsyncGetHostByAddr(hAmigaWnd,wMsg,name_rp,namelen,addrtype,buf,sizeof buf)) != NULL)
1377: {
1378: while (sb->hAsyncTask) WAITSIGNAL;
1379:
1380: sockabort(sb);
1381:
1382: if (!sb->sb_errno)
1383: {
1384: kludge:
1385: h = (HOSTENT *)buf;
1386:
1387: // compute total size of hostent
1388: size = 28;
1389: if (h->h_name != NULL) size += strlen(h->h_name)+1;
1390:
1391: if (h->h_aliases != NULL)
1392: while (h->h_aliases[numaliases]) size += strlen(h->h_aliases[numaliases++])+5;
1393:
1394: if (h->h_addr_list != NULL)
1395: {
1396: while (h->h_addr_list[numaddr]) numaddr++;
1397: size += numaddr*(h->h_length+4);
1398: }
1399:
1400: if (sb->hostent)
1401: {
1402: m68k_areg(regs,1) = sb->hostent;
1403: m68k_dreg(regs,0) = sb->hostentsize;
1404: CallLib(get_long(4),-0xd2); // FreeMem()
1405: }
1406:
1407: m68k_dreg(regs,0) = size;
1408: m68k_dreg(regs,1) = 0;
1409: sb->hostent = CallLib(get_long(4),-0xc6); // AllocMem()
1410:
1411: if (!sb->hostent)
1412: {
1413: write_log("bsdsocket: WARNING: gethostby%s() ran out of Amiga memory (couldn't allocate %ld bytes) while returning result of lookup for '%s'\n",addrtype == -1 ? "name" : "addr",size,(char *)name);
1414: seterrno(sb,12); // ENOMEM
1415: return;
1416: }
1417:
1418: sb->hostentsize = size;
1419:
1420: aptr = sb->hostent+28+numaliases*4+numaddr*4;
1421:
1422: // transfer hostent to Amiga memory
1423: put_long(sb->hostent+4,sb->hostent+20);
1424: put_long(sb->hostent+8,h->h_addrtype);
1425: put_long(sb->hostent+12,h->h_length);
1426: put_long(sb->hostent+16,sb->hostent+24+numaliases*4);
1427:
1428: for (i = 0; i < numaliases; i++) put_long(sb->hostent+20+i*4,addstr(&aptr,h->h_aliases[i]));
1429: put_long(sb->hostent+20+numaliases*4,0);
1430: for (i = 0; i < numaddr; i++) put_long(sb->hostent+24+(numaliases+i)*4,addmem(&aptr,h->h_addr_list[i],h->h_length));
1431: put_long(sb->hostent+24+numaliases*4+numaddr*4,0);
1432: put_long(sb->hostent,aptr);
1433: addstr(&aptr,h->h_name);
1434:
1435: TRACE(("OK (%s)\n",h->h_name));
1436: seterrno(sb,0);
1437: }
1438: else
1439: {
1440: TRACE(("failed (%d/%d)\n",sb->sb_errno,sb->sb_herrno))
1441: }
1442: }
1443: else
1444: {
1445: seterrno(sb,12); // ENOMEM - well...
1446: write_log("bsdsocket: ERROR: WSAAsyncGetHostBy%s() failed - error code: %d\n",addrtype == -1 ? "Name" : "Addr",WSAGetLastError());
1447: }
1448:
1449: if (wMsg) cancelasyncmsg(wMsg);
1450: }
1451: }
1452:
1453: void host_getservbynameport(SB, uae_u32 nameport, uae_u32 proto, uae_u32 type)
1454: {
1455: SERVENT *s;
1456: int size, numaliases = 0;
1457: uae_u32 aptr, asize;
1458: char *name_rp = NULL, *proto_rp = NULL;
1459: int i;
1460:
1461: char buf[MAXGETHOSTSTRUCT];
1462: unsigned int wMsg;
1463:
1464: if (proto) proto_rp = get_real_address(proto);
1465:
1466: if (type)
1467: {
1468: TRACE(("getservbyport(%d,%s) -> ",nameport,proto_rp ? proto_rp : "NULL"));
1469: }
1470: else
1471: {
1472: name_rp = get_real_address(nameport);
1473: TRACE(("getservbyname(%s,%s) -> ",name_rp,proto_rp ? proto_rp : "NULL"));
1474: }
1475:
1476: if ((wMsg = allocasyncmsg(sb,0,INVALID_SOCKET)) != 0)
1477: {
1478: if ((sb->hAsyncTask = type ? WSAAsyncGetServByPort(hAmigaWnd,wMsg,nameport,proto_rp,buf,sizeof buf) : WSAAsyncGetServByName(hAmigaWnd,wMsg,name_rp,proto_rp,buf,sizeof buf)) != NULL)
1479: {
1480: while (sb->hAsyncTask) WAITSIGNAL;
1481:
1482: sockabort(sb);
1483:
1484: if (!sb->sb_errno)
1485: {
1486: s = (SERVENT *)buf;
1487:
1488: // compute total size of servent
1489: size = 20;
1490: if (s->s_name != NULL) size += strlen(s->s_name)+1;
1491: if (s->s_proto != NULL) size += strlen(s->s_proto)+1;
1492:
1493: if (s->s_aliases != NULL)
1494: while (s->s_aliases[numaliases]) size += strlen(s->s_aliases[numaliases++])+5;
1495:
1496: if (sb->servent)
1497: {
1498: m68k_areg(regs,1) = sb->servent;
1499: m68k_dreg(regs,0) = sb->serventsize;
1500: CallLib(get_long(4),-0xd2); // FreeMem()
1501: }
1502:
1503: m68k_dreg(regs,0) = size;
1504: m68k_dreg(regs,1) = 0;
1505: sb->servent = CallLib(get_long(4),-0xc6); // AllocMem()
1506:
1507: if (!sb->servent)
1508: {
1509: write_log("bsdsocket: WARNING: getservby%s() ran out of Amiga memory (couldn't allocate %ld bytes)\n",type ? "port" : "name",size);
1510: seterrno(sb,12); // ENOMEM
1511: return;
1512: }
1513:
1514: sb->serventsize = size;
1515:
1516: aptr = sb->servent+20+numaliases*4;
1517:
1518: // transfer servent to Amiga memory
1519: put_long(sb->servent+4,sb->servent+16);
1520: put_long(sb->servent+8,(unsigned short)htons(s->s_port));
1521:
1522: for (i = 0; i < numaliases; i++) put_long(sb->servent+16+i*4,addstr(&aptr,s->s_aliases[i]));
1523: put_long(sb->servent+16+numaliases*4,0);
1524: put_long(sb->servent,aptr);
1525: addstr(&aptr,s->s_name);
1526: put_long(sb->servent+12,aptr);
1527: addstr(&aptr,s->s_proto);
1528:
1529: TRACE(("OK (%s, %d)\n",s->s_name,(unsigned short)htons(s->s_port)));
1530: seterrno(sb,0);
1531: }
1532: else
1533: {
1534: TRACE(("failed (%d)\n",sb->sb_errno))
1535: }
1536: }
1537: else
1538: {
1539: seterrno(sb,12); // ENOMEM - well...
1540: write_log("bsdsocket: ERROR: WSAAsyncGetServBy%s() failed - error code: %d\n",type ? "Port" : "Name",WSAGetLastError());
1541: }
1542:
1543: cancelasyncmsg(wMsg);
1544: }
1545: }
1546:
1547: void host_getprotobyname(SB, uae_u32 name)
1548: {
1549: PROTOENT *p;
1550: int size, numaliases = 0;
1551: uae_u32 aptr, asize;
1552: char *name_rp;
1553: int i;
1554:
1555: char buf[MAXGETHOSTSTRUCT];
1556: unsigned int wMsg;
1557:
1558: name_rp = get_real_address(name);
1559:
1560: TRACE(("getprotobyname(%s) -> ",name_rp));
1561:
1562: if ((wMsg = allocasyncmsg(sb,0,INVALID_SOCKET)) != 0)
1563: {
1564: if ((sb->hAsyncTask = WSAAsyncGetProtoByName(hAmigaWnd,wMsg,name_rp,buf,sizeof buf)) != NULL)
1565: {
1566: while (sb->hAsyncTask) WAITSIGNAL;
1567:
1568: sockabort(sb);
1569:
1570: if (!sb->sb_errno)
1571: {
1572: p = (PROTOENT *)buf;
1573:
1574: // compute total size of protoent
1575: size = 16;
1576: if (p->p_name != NULL) size += strlen(p->p_name)+1;
1577:
1578: if (p->p_aliases != NULL)
1579: while (p->p_aliases[numaliases]) size += strlen(p->p_aliases[numaliases++])+5;
1580:
1581: if (sb->protoent)
1582: {
1583: m68k_areg(regs,1) = sb->protoent;
1584: m68k_dreg(regs,0) = sb->protoentsize;
1585: CallLib(get_long(4),-0xd2); // FreeMem()
1586: }
1587:
1588: m68k_dreg(regs,0) = size;
1589: m68k_dreg(regs,1) = 0;
1590: sb->protoent = CallLib(get_long(4),-0xc6); // AllocMem()
1591:
1592: if (!sb->protoent)
1593: {
1594: write_log("bsdsocket: WARNING: getprotobyname() ran out of Amiga memory (couldn't allocate %ld bytes) while returning result of lookup for '%s'\n",size,(char *)name);
1595: seterrno(sb,12); // ENOMEM
1596: return;
1597: }
1598:
1599: sb->protoentsize = size;
1600:
1601: aptr = sb->protoent+16+numaliases*4;
1602:
1603: // transfer protoent to Amiga memory
1604: put_long(sb->protoent+4,sb->protoent+12);
1605: put_long(sb->protoent+8,p->p_proto);
1606:
1607: for (i = 0; i < numaliases; i++) put_long(sb->protoent+12+i*4,addstr(&aptr,p->p_aliases[i]));
1608: put_long(sb->protoent+12+numaliases*4,0);
1609: put_long(sb->protoent,aptr);
1610: addstr(&aptr,p->p_name);
1611: TRACE(("OK (%s, %d)\n",p->p_name,p->p_proto));
1612: seterrno(sb,0);
1613: }
1614: else
1615: {
1616: TRACE(("failed (%d)\n",sb->sb_errno))
1617: }
1618: }
1619: else
1620: {
1621: seterrno(sb,12); // ENOMEM - well...
1622: write_log("bsdsocket: ERROR: WSAAsyncGetProtoByName() failed - error code: %d\n",WSAGetLastError());
1623: }
1624:
1625: cancelasyncmsg(wMsg);
1626: }
1627: }
1628:
1629: uae_u32 host_gethostname(uae_u32 name, uae_u32 namelen)
1630: {
1631: return gethostname(get_real_address(name),namelen);
1632: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.