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