|
|
1.1 ! root 1: /* ! 2: * UAE - The Un*x Amiga Emulator ! 3: * ! 4: * bsdsocket.library emulation - Unix ! 5: * ! 6: * Copyright 2000-2001 Carl Drougge <[email protected]> <[email protected]> ! 7: * Copyright 2003-2005 Richard Drummond ! 8: * Copyright 2004 Jeff Shepherd ! 9: * ! 10: * This program is free software; you can redistribute it and/or modify ! 11: * it under the terms of the GNU General Public License as published by ! 12: * the Free Software Foundation; either version 2 of the License, or ! 13: * (at your option) any later version. ! 14: * ! 15: * This program is distributed in the hope that it will be useful, ! 16: * but WITHOUT ANY WARRANTY; without even the implied warranty of ! 17: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 18: * GNU General Public License for more details. ! 19: * ! 20: * You should have received a copy of the GNU General Public License ! 21: * along with this program; if not, write to the Free Software ! 22: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ! 23: * ! 24: */ ! 25: ! 26: #include "sysconfig.h" ! 27: #include "sysdeps.h" ! 28: ! 29: #include "options.h" ! 30: #include "memory.h" ! 31: #include "custom.h" ! 32: #include "newcpu.h" ! 33: #include "autoconf.h" ! 34: #include "traps.h" ! 35: #include "threaddep/thread.h" ! 36: #include "native2amiga.h" ! 37: #include "bsdsocket.h" ! 38: ! 39: #ifdef BSDSOCKET ! 40: #include <sys/types.h> ! 41: #include <sys/socket.h> ! 42: #include <sys/select.h> ! 43: #include <sys/ioctl.h> ! 44: #ifdef HAVE_SYS_FILIO_H ! 45: # include <sys/filio.h> ! 46: #endif ! 47: #include <netinet/in.h> ! 48: #include <netinet/tcp.h> ! 49: #include <stddef.h> ! 50: #include <netdb.h> ! 51: ! 52: #include <signal.h> ! 53: #include <arpa/inet.h> ! 54: ! 55: //#define DEBUG_BSDSOCKET ! 56: #ifdef DEBUG_BSDSOCKET ! 57: #define DEBUG_LOG write_log ! 58: #else ! 59: #define DEBUG_LOG(...) do ; while(0) ! 60: #endif ! 61: ! 62: #define WAITSIGNAL waitsig (context, sb) ! 63: ! 64: /* Sigqueue is unsafe on SMP machines. ! 65: * Temporary work-around. ! 66: */ ! 67: //#define SETSIGNAL addtosigqueue (sb, 0) ! 68: #define SETSIGNAL \ ! 69: do { \ ! 70: uae_Signal (sb->ownertask, sb->sigstosend | ((uae_u32) 1) << sb->signal); \ ! 71: sb->dosignal = 1; \ ! 72: } while (0) ! 73: ! 74: ! 75: #define SETERRNO bsdsocklib_seterrno (sb,mapErrno (errno)) ! 76: #define SETHERRNO bsdsocklib_setherrno (sb, h_errno) ! 77: ! 78: ! 79: /* BSD-systems don't seem to have MSG_NOSIGNAL.. ! 80: @@@ We need to catch SIGPIPE on those systems! (?) */ ! 81: #ifndef MSG_NOSIGNAL ! 82: #define MSG_NOSIGNAL 0 ! 83: #endif ! 84: ! 85: #define S_GL_result(res) sb->resultval = (res) ! 86: ! 87: uae_u32 bsdthr_Accept_2 (SB); ! 88: uae_u32 bsdthr_Recv_2 (SB); ! 89: uae_u32 bsdthr_blockingstuff (uae_u32 (*tryfunc)(SB), SB); ! 90: uae_u32 bsdthr_SendRecvAcceptConnect (uae_u32 (*tryfunc)(SB), SB); ! 91: uae_u32 bsdthr_Send_2 (SB); ! 92: uae_u32 bsdthr_Connect_2 (SB); ! 93: uae_u32 bsdthr_WaitSelect (SB); ! 94: uae_u32 bsdthr_Wait (SB); ! 95: void clearsockabort (SB); ! 96: ! 97: static uae_sem_t sem_queue; ! 98: ! 99: /** ! 100: ** Helper functions ! 101: **/ ! 102: ! 103: /* ! 104: * Map host errno to amiga errno ! 105: */ ! 106: static int mapErrno (int e) ! 107: { ! 108: switch (e) { ! 109: case EINTR: e = 4; break; ! 110: case EDEADLK: e = 11; break; ! 111: case EAGAIN: e = 35; break; ! 112: case EINPROGRESS: e = 36; break; ! 113: case EALREADY: e = 37; break; ! 114: case ENOTSOCK: e = 38; break; ! 115: case EDESTADDRREQ: e = 39; break; ! 116: case EMSGSIZE: e = 40; break; ! 117: case EPROTOTYPE: e = 41; break; ! 118: case ENOPROTOOPT: e = 42; break; ! 119: case EPROTONOSUPPORT: e = 43; break; ! 120: case ESOCKTNOSUPPORT: e = 44; break; ! 121: case EOPNOTSUPP: e = 45; break; ! 122: case EPFNOSUPPORT: e = 46; break; ! 123: case EAFNOSUPPORT: e = 47; break; ! 124: case EADDRINUSE: e = 48; break; ! 125: case EADDRNOTAVAIL: e = 49; break; ! 126: case ENETDOWN: e = 50; break; ! 127: case ENETUNREACH: e = 51; break; ! 128: case ENETRESET: e = 52; break; ! 129: case ECONNABORTED: e = 53; break; ! 130: case ECONNRESET: e = 54; break; ! 131: case ENOBUFS: e = 55; break; ! 132: case EISCONN: e = 56; break; ! 133: case ENOTCONN: e = 57; break; ! 134: case ESHUTDOWN: e = 58; break; ! 135: case ETOOMANYREFS: e = 59; break; ! 136: case ETIMEDOUT: e = 60; break; ! 137: case ECONNREFUSED: e = 61; break; ! 138: case ELOOP: e = 62; break; ! 139: case ENAMETOOLONG: e = 63; break; ! 140: default: break; ! 141: } ! 142: return e; ! 143: } ! 144: ! 145: /* ! 146: * Map amiga (s|g)etsockopt level into native one ! 147: */ ! 148: static int mapsockoptlevel (int level) ! 149: { ! 150: switch (level) { ! 151: case 0xffff: ! 152: return SOL_SOCKET; ! 153: case 0: ! 154: return IPPROTO_IP; ! 155: case 1: ! 156: return IPPROTO_ICMP; ! 157: case 2: ! 158: return IPPROTO_IGMP; ! 159: #ifdef IPPROTO_IPIP ! 160: case 4: ! 161: return IPPROTO_IPIP; ! 162: #endif ! 163: case 6: ! 164: return IPPROTO_TCP; ! 165: case 8: ! 166: return IPPROTO_EGP; ! 167: case 12: ! 168: return IPPROTO_PUP; ! 169: case 17: ! 170: return IPPROTO_UDP; ! 171: case 22: ! 172: return IPPROTO_IDP; ! 173: #ifdef IPPROTO_TP ! 174: case 29: ! 175: return IPPROTO_TP; ! 176: #endif ! 177: case 98: ! 178: return IPPROTO_ENCAP; ! 179: default: ! 180: DEBUG_LOG ("Unknown sockopt level %d\n", level); ! 181: return level; ! 182: } ! 183: } ! 184: ! 185: /* ! 186: * Map amiga (s|g)etsockopt optname into native one ! 187: */ ! 188: static int mapsockoptname (int level, int optname) ! 189: { ! 190: switch (level) { ! 191: ! 192: case SOL_SOCKET: ! 193: switch (optname) { ! 194: case 0x0001: ! 195: return SO_DEBUG; ! 196: case 0x0002: ! 197: return SO_ACCEPTCONN; ! 198: case 0x0004: ! 199: return SO_REUSEADDR; ! 200: case 0x0008: ! 201: return SO_KEEPALIVE; ! 202: case 0x0010: ! 203: return SO_DONTROUTE; ! 204: case 0x0020: ! 205: return SO_BROADCAST; ! 206: #ifdef SO_USELOOPBACK ! 207: case 0x0040: ! 208: return SO_USELOOPBACK; ! 209: #endif ! 210: case 0x0080: ! 211: return SO_LINGER; ! 212: case 0x0100: ! 213: return SO_OOBINLINE; ! 214: #ifdef SO_REUSEPORT ! 215: case 0x0200: ! 216: return SO_REUSEPORT; ! 217: #endif ! 218: case 0x1001: ! 219: return SO_SNDBUF; ! 220: case 0x1002: ! 221: return SO_RCVBUF; ! 222: case 0x1003: ! 223: return SO_SNDLOWAT; ! 224: case 0x1004: ! 225: return SO_RCVLOWAT; ! 226: case 0x1005: ! 227: return SO_SNDTIMEO; ! 228: case 0x1006: ! 229: return SO_RCVTIMEO; ! 230: case 0x1007: ! 231: return SO_ERROR; ! 232: case 0x1008: ! 233: return SO_TYPE; ! 234: ! 235: default: ! 236: DEBUG_LOG ("Invalid setsockopt option %x for level %d\n", ! 237: optname, level); ! 238: return -1; ! 239: } ! 240: break; ! 241: ! 242: case IPPROTO_IP: ! 243: switch (optname) { ! 244: case 1: ! 245: return IP_OPTIONS; ! 246: case 2: ! 247: return IP_HDRINCL; ! 248: case 3: ! 249: return IP_TOS; ! 250: case 4: ! 251: return IP_TTL; ! 252: case 5: ! 253: return IP_RECVOPTS; ! 254: case 6: ! 255: return IP_RECVRETOPTS; ! 256: case 8: ! 257: return IP_RETOPTS; ! 258: case 9: ! 259: return IP_MULTICAST_IF; ! 260: case 10: ! 261: return IP_MULTICAST_TTL; ! 262: case 11: ! 263: return IP_MULTICAST_LOOP; ! 264: case 12: ! 265: return IP_ADD_MEMBERSHIP; ! 266: ! 267: default: ! 268: DEBUG_LOG ("Invalid setsockopt option %x for level %d\n", ! 269: optname, level); ! 270: return -1; ! 271: } ! 272: break; ! 273: ! 274: case IPPROTO_TCP: ! 275: switch (optname) { ! 276: case 1: ! 277: return TCP_NODELAY; ! 278: case 2: ! 279: return TCP_MAXSEG; ! 280: ! 281: default: ! 282: DEBUG_LOG ("Invalid setsockopt option %x for level %d\n", ! 283: optname, level); ! 284: return -1; ! 285: } ! 286: break; ! 287: ! 288: default: ! 289: DEBUG_LOG ("Unknown level %d\n", level); ! 290: return -1; ! 291: } ! 292: } ! 293: ! 294: ! 295: /* ! 296: * Map amiga (s|g)etsockopt return value into the correct form ! 297: */ ! 298: static void mapsockoptreturn(int level, int optname, uae_u32 optval, void *buf) ! 299: { ! 300: switch (level) { ! 301: ! 302: case SOL_SOCKET: ! 303: switch (optname) { ! 304: case SO_DEBUG: ! 305: case SO_ACCEPTCONN: ! 306: case SO_REUSEADDR: ! 307: case SO_KEEPALIVE: ! 308: case SO_DONTROUTE: ! 309: case SO_BROADCAST: ! 310: #ifdef SO_USELOOPBACK ! 311: case SO_USELOOPBACK: ! 312: #endif ! 313: case SO_LINGER: ! 314: case SO_OOBINLINE: ! 315: #ifdef SO_REUSEPORT ! 316: case SO_REUSEPORT: ! 317: #endif ! 318: case SO_SNDBUF: ! 319: case SO_RCVBUF: ! 320: case SO_SNDLOWAT: ! 321: case SO_RCVLOWAT: ! 322: case SO_SNDTIMEO: ! 323: case SO_RCVTIMEO: ! 324: case SO_TYPE: ! 325: put_long (optval, *(int *)buf); ! 326: break; ! 327: ! 328: case SO_ERROR: ! 329: DEBUG_LOG("New errno is %d\n", mapErrno(*(int *)buf)); ! 330: put_long (optval, mapErrno(*(int *)buf)); ! 331: break; ! 332: default: ! 333: break; ! 334: } ! 335: break; ! 336: ! 337: case IPPROTO_IP: ! 338: switch (optname) { ! 339: case IP_OPTIONS: ! 340: case IP_HDRINCL: ! 341: case IP_TOS: ! 342: case IP_TTL: ! 343: case IP_RECVOPTS: ! 344: //case IP_RECVRETOPTS: ! 345: //case IP_RETOPTS: ! 346: case IP_MULTICAST_IF: ! 347: case IP_MULTICAST_TTL: ! 348: case IP_MULTICAST_LOOP: ! 349: case IP_ADD_MEMBERSHIP: ! 350: put_long (optval, *(int *)buf); ! 351: break; ! 352: ! 353: default: ! 354: break; ! 355: } ! 356: break; ! 357: ! 358: case IPPROTO_TCP: ! 359: switch (optname) { ! 360: case TCP_NODELAY: ! 361: case TCP_MAXSEG: ! 362: put_long (optval,*(int *)buf); ! 363: break; ! 364: ! 365: default: ! 366: break; ! 367: } ! 368: break; ! 369: ! 370: default: ! 371: break; ! 372: } ! 373: } ! 374: ! 375: /* ! 376: * Map amiga (s|g)etsockopt value from amiga to the appropriate value ! 377: */ ! 378: static void mapsockoptvalue(int level, int optname, uae_u32 optval, void *buf) ! 379: { ! 380: switch (level) { ! 381: ! 382: case SOL_SOCKET: ! 383: switch (optname) { ! 384: case SO_DEBUG: ! 385: case SO_ACCEPTCONN: ! 386: case SO_REUSEADDR: ! 387: case SO_KEEPALIVE: ! 388: case SO_DONTROUTE: ! 389: case SO_BROADCAST: ! 390: #ifdef SO_USELOOPBACK ! 391: case SO_USELOOPBACK: ! 392: #endif ! 393: case SO_LINGER: ! 394: case SO_OOBINLINE: ! 395: #ifdef SO_REUSEPORT ! 396: case SO_REUSEPORT: ! 397: #endif ! 398: case SO_SNDBUF: ! 399: case SO_RCVBUF: ! 400: case SO_SNDLOWAT: ! 401: case SO_RCVLOWAT: ! 402: case SO_SNDTIMEO: ! 403: case SO_RCVTIMEO: ! 404: case SO_TYPE: ! 405: case SO_ERROR: ! 406: *((int *)buf) = get_long (optval); ! 407: break; ! 408: default: ! 409: break; ! 410: } ! 411: break; ! 412: ! 413: case IPPROTO_IP: ! 414: switch (optname) { ! 415: case IP_OPTIONS: ! 416: case IP_HDRINCL: ! 417: case IP_TOS: ! 418: case IP_TTL: ! 419: case IP_RECVOPTS: ! 420: //case IP_RECVRETOPTS: ! 421: //case IP_RETOPTS: ! 422: case IP_MULTICAST_IF: ! 423: case IP_MULTICAST_TTL: ! 424: case IP_MULTICAST_LOOP: ! 425: case IP_ADD_MEMBERSHIP: ! 426: *((int *)buf) = get_long (optval); ! 427: break; ! 428: ! 429: default: ! 430: break; ! 431: } ! 432: break; ! 433: ! 434: case IPPROTO_TCP: ! 435: switch (optname) { ! 436: case TCP_NODELAY: ! 437: case TCP_MAXSEG: ! 438: *((int *)buf) = get_long (optval); ! 439: break; ! 440: ! 441: default: ! 442: break; ! 443: } ! 444: break; ! 445: ! 446: default: ! 447: break; ! 448: } ! 449: } ! 450: ! 451: ! 452: STATIC_INLINE void fd_zero (uae_u32 fdset, uae_u32 nfds) ! 453: { ! 454: unsigned int i; ! 455: ! 456: for (i = 0; i < nfds; i += 32, fdset += 4) ! 457: put_long (fdset, 0); ! 458: } ! 459: ! 460: STATIC_INLINE int bsd_amigaside_FD_ISSET (int n, uae_u32 set) ! 461: { ! 462: uae_u32 foo = get_long (set + (n / 32)); ! 463: if (foo & (1 << (n % 32))) ! 464: return 1; ! 465: return 0; ! 466: } ! 467: ! 468: STATIC_INLINE void bsd_amigaside_FD_ZERO (uae_u32 set) ! 469: { ! 470: put_long (set, 0); ! 471: put_long (set + 4, 0); ! 472: } ! 473: ! 474: STATIC_INLINE void bsd_amigaside_FD_SET (int n, uae_u32 set) ! 475: { ! 476: set = set + (n / 32); ! 477: put_long (set, get_long (set) | (1 << (n % 32))); ! 478: } ! 479: ! 480: #ifdef DEBUG_BSDSOCKET ! 481: static void printSockAddr (struct sockaddr_in *in) ! 482: { ! 483: DEBUG_LOG ("Family %d, ", in->sin_family); ! 484: DEBUG_LOG ("Port %d,", ntohs (in->sin_port)); ! 485: DEBUG_LOG ("Address %s,", inet_ntoa (in->sin_addr)); ! 486: } ! 487: #else ! 488: #define printSockAddr(sockAddr) ! 489: #endif ! 490: ! 491: /* ! 492: * Copy a sockaddr object from amiga space to native space ! 493: */ ! 494: static int copysockaddr_a2n (struct sockaddr_in *addr, uae_u32 a_addr, unsigned int len) ! 495: { ! 496: if ((len > sizeof (struct sockaddr_in)) || (len < 8)) ! 497: return 1; ! 498: ! 499: if (a_addr == 0) ! 500: return 0; ! 501: ! 502: addr->sin_family = get_byte (a_addr + 1); ! 503: addr->sin_port = htons (get_word (a_addr + 2)); ! 504: addr->sin_addr.s_addr = htonl (get_long (a_addr + 4)); ! 505: ! 506: if (len > 8) ! 507: memcpy (&addr->sin_zero, get_real_address (a_addr + 8), len - 8); /* Pointless? */ ! 508: ! 509: return 0; ! 510: } ! 511: ! 512: /* ! 513: * Copy a sockaddr object from native space to amiga space ! 514: */ ! 515: static int copysockaddr_n2a (uae_u32 a_addr, const struct sockaddr_in *addr, unsigned int len) ! 516: { ! 517: if (len < 8) ! 518: return 1; ! 519: ! 520: if (a_addr == 0) ! 521: return 0; ! 522: ! 523: put_byte (a_addr, 0); /* Anyone use this field? */ ! 524: put_byte (a_addr + 1, addr->sin_family); ! 525: put_word (a_addr + 2, ntohs (addr->sin_port)); ! 526: put_long (a_addr + 4, ntohl (addr->sin_addr.s_addr)); ! 527: ! 528: if (len > 8) ! 529: memset (get_real_address (a_addr + 8), 0, len - 8); ! 530: ! 531: return 0; ! 532: } ! 533: ! 534: /* ! 535: * Copy a hostent object from native space to amiga space ! 536: */ ! 537: static void copyHostent (const struct hostent *hostent, SB) ! 538: { ! 539: int size = 28; ! 540: int i; ! 541: int numaddr = 0; ! 542: int numaliases = 0; ! 543: uae_u32 aptr; ! 544: ! 545: if (hostent->h_name != NULL) ! 546: size += strlen(hostent->h_name)+1; ! 547: ! 548: if (hostent->h_aliases != NULL) ! 549: while (hostent->h_aliases[numaliases]) ! 550: size += strlen(hostent->h_aliases[numaliases++]) + 5; ! 551: ! 552: if (hostent->h_addr_list != NULL) { ! 553: while (hostent->h_addr_list[numaddr]) ! 554: numaddr++; ! 555: size += numaddr*(hostent->h_length+4); ! 556: } ! 557: ! 558: aptr = sb->hostent + 28 + numaliases * 4 + numaddr * 4; ! 559: ! 560: // transfer hostent to Amiga memory ! 561: put_long (sb->hostent + 4, sb->hostent + 20); ! 562: put_long (sb->hostent + 8, hostent->h_addrtype); ! 563: put_long (sb->hostent + 12, hostent->h_length); ! 564: put_long (sb->hostent + 16, sb->hostent + 24 + numaliases*4); ! 565: ! 566: for (i = 0; i < numaliases; i++) ! 567: put_long (sb->hostent + 20 + i * 4, addstr (&aptr, hostent->h_aliases[i])); ! 568: put_long (sb->hostent + 20 + numaliases * 4, 0); ! 569: ! 570: for (i = 0; i < numaddr; i++) { ! 571: put_long (sb->hostent + 24 + (numaliases + i) * 4, ! 572: addmem (&aptr, hostent->h_addr_list[i], hostent->h_length)); ! 573: } ! 574: put_long (sb->hostent + 24 + numaliases * 4 + numaddr * 4, 0); ! 575: put_long (sb->hostent, aptr); ! 576: addstr (&aptr, hostent->h_name); ! 577: ! 578: TRACE (("OK (%s)\n",hostent->h_name)); ! 579: bsdsocklib_seterrno (sb,0); ! 580: } ! 581: ! 582: /* ! 583: * Copy a protoent object from native space to Amiga space ! 584: */ ! 585: static void copyProtoent (TrapContext *context, SB, const struct protoent *p) ! 586: { ! 587: size_t size = 16; ! 588: int numaliases = 0; ! 589: int i; ! 590: uae_u32 aptr; ! 591: ! 592: // compute total size of protoent ! 593: if (p->p_name != NULL) ! 594: size += strlen (p->p_name) + 1; ! 595: ! 596: if (p->p_aliases != NULL) ! 597: while (p->p_aliases[numaliases]) ! 598: size += strlen (p->p_aliases[numaliases++]) + 5; ! 599: ! 600: if (sb->protoent) { ! 601: uae_FreeMem (context, sb->protoent, sb->protoentsize); ! 602: } ! 603: ! 604: sb->protoent = uae_AllocMem (context, size, 0); ! 605: ! 606: if (!sb->protoent) { ! 607: write_log ("BSDSOCK: WARNING - copyProtoent() ran out of Amiga memory (couldn't allocate %d bytes)\n", size); ! 608: bsdsocklib_seterrno (sb, 12); // ENOMEM ! 609: return; ! 610: } ! 611: ! 612: sb->protoentsize = size; ! 613: ! 614: aptr = sb->protoent + 16 + numaliases * 4; ! 615: ! 616: // transfer protoent to Amiga memory ! 617: put_long (sb->protoent + 4, sb->protoent + 12); ! 618: put_long (sb->protoent + 8, p->p_proto); ! 619: ! 620: for (i = 0; i < numaliases; i++) ! 621: put_long (sb->protoent + 12 + i * 4, addstr (&aptr, p->p_aliases[i])); ! 622: put_long (sb->protoent + 12 + numaliases * 4, 0); ! 623: put_long (sb->protoent, aptr); ! 624: addstr (&aptr, p->p_name); ! 625: bsdsocklib_seterrno(sb, 0); ! 626: } ! 627: ! 628: ! 629: ! 630: uae_u32 bsdthr_WaitSelect (SB) ! 631: { ! 632: fd_set sets [3]; ! 633: int i, s, set, a_s, max; ! 634: uae_u32 a_set; ! 635: struct timeval tv; ! 636: int r; ! 637: ! 638: DEBUG_LOG ("WaitSelect: %d 0x%x 0x%x 0x%x 0x%x 0x%x\n", ! 639: sb->nfds, sb->sets [0], sb->sets [1], sb->sets [2], sb->timeout, sb->sigmp); ! 640: ! 641: if (sb->timeout) ! 642: DEBUG_LOG ("WaitSelect: timeout %d %d\n", get_long (sb->timeout), ! 643: get_long (sb->timeout + 4)); ! 644: ! 645: FD_ZERO (&sets [0]); ! 646: FD_ZERO (&sets [1]); ! 647: FD_ZERO (&sets [2]); ! 648: ! 649: /* Set up the abort socket */ ! 650: FD_SET (sb->sockabort[0], &sets[0]); ! 651: FD_SET (sb->sockabort[0], &sets[2]); ! 652: max = sb->sockabort[0]; ! 653: ! 654: for (set = 0; set < 3; set++) { ! 655: if (sb->sets [set] != 0) { ! 656: a_set = sb->sets [set]; ! 657: for (i = 0; i < sb->nfds; i++) { ! 658: if (bsd_amigaside_FD_ISSET (i, a_set)) { ! 659: s = getsock (sb, i + 1); ! 660: DEBUG_LOG ("WaitSelect: AmigaSide %d set. NativeSide %d.\n", i, s); ! 661: if (s == -1) { ! 662: write_log ("BSDSOCK: WaitSelect() called with invalid descriptor %d in set %d.\n", i, set); ! 663: } else { ! 664: FD_SET (s, &sets [set]); ! 665: if (max < s) max = s; ! 666: } ! 667: } ! 668: } ! 669: } ! 670: } ! 671: ! 672: max++; ! 673: ! 674: if (sb->timeout) { ! 675: tv.tv_sec = get_long (sb->timeout); ! 676: tv.tv_usec = get_long (sb->timeout + 4); ! 677: } ! 678: ! 679: DEBUG_LOG("Select going to select\n"); ! 680: r = select (max, &sets [0], &sets [1], &sets [2], (sb->timeout == 0) ? NULL : &tv); ! 681: DEBUG_LOG("Select returns %d, errno is %d\n", r, errno); ! 682: if( r > 0 ) { ! 683: /* Socket told us to abort */ ! 684: if (FD_ISSET (sb->sockabort[0], &sets[0])) { ! 685: /* read from the pipe to reset it */ ! 686: DEBUG_LOG ("WaitSelect aborted from signal\n"); ! 687: r = 0; ! 688: for (set = 0; set < 3; set++) ! 689: if (sb->sets [set] != 0) ! 690: bsd_amigaside_FD_ZERO (sb->sets [set]); ! 691: clearsockabort (sb); ! 692: } ! 693: else ! 694: /* This is perhaps slightly inefficient, but I don't care.. */ ! 695: for (set = 0; set < 3; set++) { ! 696: a_set = sb->sets [set]; ! 697: if (a_set != 0) { ! 698: bsd_amigaside_FD_ZERO (a_set); ! 699: for (i = 0; i < sb->nfds; i++) { ! 700: a_s = getsock (sb, i + 1); ! 701: if (a_s != -1) { ! 702: if (FD_ISSET (a_s, &sets [set])) { ! 703: DEBUG_LOG ("WaitSelect: NativeSide %d set. AmigaSide %d.\n", a_s, i); ! 704: ! 705: bsd_amigaside_FD_SET (i, a_set); ! 706: } ! 707: } ! 708: } ! 709: } ! 710: } ! 711: } else if (r == 0) { /* Timeout. I think we're supposed to clear the sets.. */ ! 712: for (set = 0; set < 3; set++) ! 713: if (sb->sets [set] != 0) ! 714: bsd_amigaside_FD_ZERO (sb->sets [set]); ! 715: } ! 716: DEBUG_LOG ("WaitSelect: %d(%d)\n", r, errno); ! 717: return r; ! 718: } ! 719: ! 720: uae_u32 bsdthr_Accept_2 (SB) ! 721: { ! 722: int foo, s, s2; ! 723: long flags; ! 724: struct sockaddr_in addr; ! 725: socklen_t hlen = sizeof (struct sockaddr_in); ! 726: ! 727: if ((s = accept (sb->s, (struct sockaddr *)&addr, &hlen)) >= 0) { ! 728: if ((flags = fcntl (s, F_GETFL)) == -1) ! 729: flags = 0; ! 730: fcntl (s, F_SETFL, flags & ~O_NONBLOCK); /* @@@ Don't do this if it's supposed to stay nonblocking... */ ! 731: s2 = getsd (sb, s); ! 732: sb->ftable[s2-1] = sb->ftable[sb->len]; /* new socket inherits the old socket's properties */ ! 733: DEBUG_LOG ("Accept: AmigaSide %d, NativeSide %d, len %d(%d)", ! 734: sb->resultval, s, &hlen, get_long (sb->a_addrlen)); ! 735: printSockAddr (&addr); ! 736: foo = get_long (sb->a_addrlen); ! 737: if (foo > 16) ! 738: put_long (sb->a_addrlen, 16); ! 739: copysockaddr_n2a (sb->a_addr, &addr, foo); ! 740: return s2 - 1; ! 741: } else { ! 742: return -1; ! 743: } ! 744: } ! 745: ! 746: uae_u32 bsdthr_Recv_2 (SB) ! 747: { ! 748: int foo; ! 749: int l, i; ! 750: if (sb->from == 0) { ! 751: foo = recv (sb->s, sb->buf, sb->len, sb->flags /*| MSG_NOSIGNAL*/); ! 752: DEBUG_LOG ("recv2, recv returns %d, errno is %d\n", foo, errno); ! 753: } else { ! 754: struct sockaddr_in addr; ! 755: socklen_t l = sizeof (struct sockaddr_in); ! 756: i = get_long (sb->fromlen); ! 757: copysockaddr_a2n (&addr, sb->from, i); ! 758: foo = recvfrom (sb->s, sb->buf, sb->len, sb->flags | MSG_NOSIGNAL, (struct sockaddr *)&addr, &l); ! 759: DEBUG_LOG ("recv2, recvfrom returns %d, errno is %d\n", foo, errno); ! 760: if (foo >= 0) { ! 761: copysockaddr_n2a (sb->from, &addr, l); ! 762: put_long (sb->fromlen, l); ! 763: } ! 764: } ! 765: return foo; ! 766: } ! 767: ! 768: uae_u32 bsdthr_Send_2 (SB) ! 769: { ! 770: if (sb->to == 0) { ! 771: return send (sb->s, sb->buf, sb->len, sb->flags | MSG_NOSIGNAL); ! 772: } else { ! 773: struct sockaddr_in addr; ! 774: int l = sizeof (struct sockaddr_in); ! 775: copysockaddr_a2n (&addr, sb->to, sb->tolen); ! 776: return sendto (sb->s, sb->buf, sb->len, sb->flags | MSG_NOSIGNAL, ! 777: (struct sockaddr *)&addr, l); ! 778: } ! 779: } ! 780: ! 781: uae_u32 bsdthr_Connect_2 (SB) ! 782: { ! 783: if (sb->action == 1) { ! 784: struct sockaddr_in addr; ! 785: int len = sizeof (struct sockaddr_in); ! 786: int retval; ! 787: copysockaddr_a2n (&addr, sb->a_addr, sb->a_addrlen); ! 788: retval = connect (sb->s, (struct sockaddr *)&addr, len); ! 789: DEBUG_LOG ("Connect returns %d, errno is %d\n", retval, errno); ! 790: /* Hack: I need to set the action to something other than ! 791: * 1 but I know action == 2 does the correct thing ! 792: */ ! 793: sb->action = 2; ! 794: if (retval == 0) { ! 795: errno = 0; ! 796: } ! 797: return retval; ! 798: } else { ! 799: int foo; ! 800: socklen_t bar; ! 801: bar = sizeof (foo); ! 802: if (getsockopt (sb->s, SOL_SOCKET, SO_ERROR, &foo, &bar) == 0) { ! 803: errno = foo; ! 804: DEBUG_LOG("Connect status is %d\n", foo); ! 805: return (foo == 0) ? 0 : -1; ! 806: } ! 807: return -1; ! 808: } ! 809: } ! 810: ! 811: uae_u32 bsdthr_SendRecvAcceptConnect (uae_u32 (*tryfunc)(SB), SB) ! 812: { ! 813: return bsdthr_blockingstuff (tryfunc, sb); ! 814: } ! 815: ! 816: uae_u32 bsdthr_blockingstuff (uae_u32 (*tryfunc)(SB), SB) ! 817: { ! 818: int done = 0, foo; ! 819: long flags; ! 820: int nonblock; ! 821: if ((flags = fcntl (sb->s, F_GETFL)) == -1) ! 822: flags = 0; ! 823: nonblock = (flags & O_NONBLOCK); ! 824: fcntl (sb->s, F_SETFL, flags | O_NONBLOCK); ! 825: while (!done) { ! 826: done = 1; ! 827: foo = tryfunc (sb); ! 828: if (foo < 0 && !nonblock) { ! 829: if ((errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINPROGRESS)) { ! 830: fd_set readset, writeset, exceptset; ! 831: int maxfd = (sb->s > sb->sockabort[0]) ? sb->s : sb->sockabort[0]; ! 832: int num; ! 833: ! 834: FD_ZERO (&readset); ! 835: FD_ZERO (&writeset); ! 836: FD_ZERO (&exceptset); ! 837: ! 838: if (sb->action == 3 || sb->action == 6) ! 839: FD_SET (sb->s, &readset); ! 840: if (sb->action == 2 || sb->action == 1 || sb->action == 4) ! 841: FD_SET (sb->s, &writeset); ! 842: FD_SET (sb->sockabort[0], &readset); ! 843: ! 844: num = select (maxfd + 1, &readset, &writeset, &exceptset, NULL); ! 845: if (num == -1) { ! 846: DEBUG_LOG ("Blocking select(%d) returns -1,errno is %d\n", sb->sockabort[0],errno); ! 847: fcntl (sb->s, F_SETFL, flags); ! 848: return -1; ! 849: } ! 850: ! 851: if (FD_ISSET (sb->sockabort[0], &readset) || FD_ISSET (sb->sockabort[0], &writeset)) { ! 852: /* reset sock abort pipe */ ! 853: /* read from the pipe to reset it */ ! 854: DEBUG_LOG ("select aborted from signal\n"); ! 855: ! 856: clearsockabort (sb); ! 857: DEBUG_LOG ("Done read\n"); ! 858: errno = EINTR; ! 859: done = 1; ! 860: } else { ! 861: done = 0; ! 862: } ! 863: } else if (errno == EINTR) ! 864: done = 1; ! 865: } ! 866: } ! 867: fcntl (sb->s, F_SETFL, flags); ! 868: return foo; ! 869: } ! 870: ! 871: ! 872: static void *bsdlib_threadfunc (void *arg) ! 873: { ! 874: struct socketbase *sb = (struct socketbase *) arg; ! 875: ! 876: DEBUG_LOG ("THREAD_START\n"); ! 877: ! 878: while (1) { ! 879: uae_sem_wait (&sb->sem); ! 880: ! 881: DEBUG_LOG ("Socket thread got action %d\n", sb->action); ! 882: ! 883: switch (sb->action) { ! 884: case 0: /* kill thread (CloseLibrary) */ ! 885: ! 886: DEBUG_LOG ("THREAD_END\n"); ! 887: ! 888: uae_sem_destroy (&sb->sem); ! 889: return NULL; ! 890: ! 891: case 1: /* Connect */ ! 892: sb->resultval = bsdthr_SendRecvAcceptConnect (bsdthr_Connect_2, sb); ! 893: break; ! 894: ! 895: /* @@@ Should check (from|to)len so it's 16.. */ ! 896: case 2: /* Send[to] */ ! 897: sb->resultval = bsdthr_SendRecvAcceptConnect (bsdthr_Send_2, sb); ! 898: break; ! 899: ! 900: case 3: /* Recv[from] */ ! 901: sb->resultval = bsdthr_SendRecvAcceptConnect (bsdthr_Recv_2, sb); ! 902: break; ! 903: ! 904: case 4: { /* Gethostbyname */ ! 905: struct hostent *tmphostent = gethostbyname ((char *)get_real_address (sb->name)); ! 906: ! 907: if (tmphostent) { ! 908: copyHostent (tmphostent, sb); ! 909: bsdsocklib_setherrno (sb, 0); ! 910: } else ! 911: SETHERRNO; ! 912: ! 913: break; ! 914: } ! 915: ! 916: case 5: /* WaitSelect */ ! 917: sb->resultval = bsdthr_WaitSelect (sb); ! 918: break; ! 919: ! 920: case 6: /* Accept */ ! 921: sb->resultval = bsdthr_SendRecvAcceptConnect (bsdthr_Accept_2, sb); ! 922: break; ! 923: ! 924: case 7: { ! 925: struct hostent *tmphostent = gethostbyaddr (get_real_address (sb->name), sb->a_addrlen, sb->flags); ! 926: ! 927: if (tmphostent) { ! 928: copyHostent (tmphostent, sb); ! 929: bsdsocklib_setherrno (sb, 0); ! 930: } else ! 931: SETHERRNO; ! 932: ! 933: break; ! 934: } ! 935: } ! 936: SETERRNO; ! 937: SETSIGNAL; ! 938: } ! 939: return NULL; /* Just to keep GCC happy.. */ ! 940: } ! 941: ! 942: ! 943: ! 944: ! 945: void host_connect (TrapContext *context, SB, uae_u32 sd, uae_u32 name, uae_u32 namelen) ! 946: { ! 947: sb->s = getsock (sb, sd + 1); ! 948: if (sb->s == -1) { ! 949: sb->resultval = -1; ! 950: bsdsocklib_seterrno (sb, 9); /* EBADF */ ! 951: return; ! 952: } ! 953: sb->a_addr = name; ! 954: sb->a_addrlen = namelen; ! 955: sb->action = 1; ! 956: ! 957: uae_sem_post (&sb->sem); ! 958: ! 959: WAITSIGNAL; ! 960: } ! 961: ! 962: void host_sendto (TrapContext *context, SB, uae_u32 sd, uae_u32 msg, uae_u32 len, uae_u32 flags, uae_u32 to, uae_u32 tolen) ! 963: { ! 964: sb->s = getsock (sb, sd + 1); ! 965: if (sb->s == -1) { ! 966: sb->resultval = -1; ! 967: bsdsocklib_seterrno (sb, 9); /* EBADF */ ! 968: return; ! 969: } ! 970: sb->buf = get_real_address (msg); ! 971: sb->len = len; ! 972: sb->flags = flags; ! 973: sb->to = to; ! 974: sb->tolen = tolen; ! 975: sb->action = 2; ! 976: ! 977: uae_sem_post (&sb->sem); ! 978: ! 979: WAITSIGNAL; ! 980: } ! 981: ! 982: void host_recvfrom (TrapContext *context, SB, uae_u32 sd, uae_u32 msg, uae_u32 len, uae_u32 flags, uae_u32 addr, uae_u32 addrlen) ! 983: { ! 984: int s = getsock (sb, sd + 1); ! 985: ! 986: DEBUG_LOG ("Recv[from](%lx, %d, %lx, %ld, %lx, %lx, %d)\n", ! 987: sb, sd, msg, len, flags, addr, addrlen); ! 988: ! 989: if (s == -1) { ! 990: sb->resultval = -1; ! 991: bsdsocklib_seterrno (sb, 9); /* EBADF */; ! 992: return; ! 993: } ! 994: ! 995: sb->s = s; ! 996: sb->buf = get_real_address (msg); ! 997: sb->len = len; ! 998: sb->flags = flags; ! 999: sb->from = addr; ! 1000: sb->fromlen= addrlen; ! 1001: sb->action = 3; ! 1002: ! 1003: uae_sem_post (&sb->sem); ! 1004: ! 1005: WAITSIGNAL; ! 1006: } ! 1007: ! 1008: void host_setsockopt (SB, uae_u32 sd, uae_u32 level, uae_u32 optname, uae_u32 optval, uae_u32 optlen) ! 1009: { ! 1010: int s = getsock (sb, sd + 1); ! 1011: int nativelevel = mapsockoptlevel (level); ! 1012: int nativeoptname = mapsockoptname(nativelevel, optname); ! 1013: void *buf; ! 1014: if (s == -1) { ! 1015: sb->resultval = -1; ! 1016: bsdsocklib_seterrno (sb, 9); /* EBADF */; ! 1017: return; ! 1018: } ! 1019: ! 1020: if (optval) { ! 1021: buf = malloc(optlen); ! 1022: mapsockoptvalue(nativelevel, nativeoptname, optval, buf); ! 1023: } else { ! 1024: buf = NULL; ! 1025: } ! 1026: sb->resultval = setsockopt (s, nativelevel, nativeoptname, buf, optlen); ! 1027: if (buf) ! 1028: free(buf); ! 1029: SETERRNO; ! 1030: ! 1031: DEBUG_LOG ("setsockopt: sock %d, level %d, 'name' %d(%d), len %d -> %d, %d\n", ! 1032: s, level, optname, nativeoptname, optlen, ! 1033: sb->resultval, errno); ! 1034: } ! 1035: ! 1036: uae_u32 host_getsockname (SB, uae_u32 sd, uae_u32 name, uae_u32 namelen) ! 1037: { ! 1038: int s; ! 1039: socklen_t len = sizeof (struct sockaddr_in); ! 1040: struct sockaddr_in addr; ! 1041: ! 1042: DEBUG_LOG ("getsockname(%d,0x%lx,%d) -> ", sd, name, len); ! 1043: ! 1044: s = getsock (sb, sd + 1); ! 1045: ! 1046: if (s != -1) { ! 1047: if (getsockname (s, (struct sockaddr *)&addr, &len)) { ! 1048: SETERRNO; ! 1049: DEBUG_LOG ("failed (%d)\n", sb->sb_errno); ! 1050: } else { ! 1051: int a_nl; ! 1052: DEBUG_LOG ("okay\n"); ! 1053: a_nl = get_long (namelen); ! 1054: copysockaddr_n2a (name, &addr, a_nl); ! 1055: if (a_nl > 16) ! 1056: put_long (namelen, 16); ! 1057: return 0; ! 1058: } ! 1059: } ! 1060: ! 1061: return -1; ! 1062: } ! 1063: ! 1064: uae_u32 host_getpeername (SB, uae_u32 sd, uae_u32 name, uae_u32 namelen) ! 1065: { ! 1066: int s; ! 1067: socklen_t len = sizeof (struct sockaddr_in); ! 1068: struct sockaddr_in addr; ! 1069: ! 1070: DEBUG_LOG ("getpeername(%d,0x%lx,%d) -> ", sd, name, len); ! 1071: ! 1072: s = getsock (sb, sd + 1); ! 1073: ! 1074: if (s != -1) { ! 1075: if (getpeername (s, (struct sockaddr *)&addr, &len)) { ! 1076: SETERRNO; ! 1077: DEBUG_LOG ("failed (%d)\n", sb->sb_errno); ! 1078: } else { ! 1079: int a_nl; ! 1080: DEBUG_LOG ("okay\n"); ! 1081: a_nl = get_long (namelen); ! 1082: copysockaddr_n2a (name, &addr, a_nl); ! 1083: if (a_nl > 16) ! 1084: put_long (namelen, 16); ! 1085: return 0; ! 1086: } ! 1087: } ! 1088: ! 1089: return -1; ! 1090: } ! 1091: ! 1092: void host_gethostbynameaddr (TrapContext *context, SB, uae_u32 name, uae_u32 namelen, long addrtype) ! 1093: { ! 1094: sb->name = name; ! 1095: sb->a_addrlen = namelen; ! 1096: sb->flags = addrtype; ! 1097: if (addrtype == -1) ! 1098: sb->action = 4; ! 1099: else ! 1100: sb->action = 7; ! 1101: ! 1102: uae_sem_post (&sb->sem); ! 1103: ! 1104: WAITSIGNAL; ! 1105: } ! 1106: ! 1107: void host_WaitSelect (TrapContext *context, SB, uae_u32 nfds, uae_u32 readfds, uae_u32 writefds, uae_u32 exceptfds, ! 1108: uae_u32 timeout, uae_u32 sigmp) ! 1109: { ! 1110: uae_u32 wssigs = (sigmp) ? get_long (sigmp) : 0; ! 1111: uae_u32 sigs; ! 1112: ! 1113: if (wssigs) { ! 1114: m68k_dreg (regs, 0) = 0; ! 1115: m68k_dreg (regs, 1) = wssigs; ! 1116: sigs = CallLib (context, get_long (4), -0x132) & wssigs; // SetSignal() ! 1117: if (sigs) { ! 1118: DEBUG_LOG ("WaitSelect preempted by signals 0x%08x\n", sigs & wssigs); ! 1119: put_long (sigmp, sigs); ! 1120: // Check for zero address -> otherwise WinUAE crashes ! 1121: if (readfds) fd_zero (readfds, nfds); ! 1122: if (writefds) fd_zero (writefds, nfds); ! 1123: if (exceptfds) fd_zero (exceptfds, nfds); ! 1124: sb->resultval = 0; ! 1125: bsdsocklib_seterrno (sb, 0); ! 1126: return; ! 1127: } ! 1128: } ! 1129: ! 1130: if (nfds == 0) { ! 1131: /* No sockets - Just wait on signals */ ! 1132: m68k_dreg (regs, 0) = wssigs; ! 1133: sigs = CallLib (context, get_long (4), -0x13e); // Wait() ! 1134: ! 1135: if (sigmp) ! 1136: put_long (sigmp, sigs & wssigs); ! 1137: ! 1138: if (readfds) fd_zero (readfds, nfds); ! 1139: if (writefds) fd_zero (writefds, nfds); ! 1140: if (exceptfds) fd_zero (exceptfds, nfds); ! 1141: sb->resultval = 0; ! 1142: return; ! 1143: } ! 1144: ! 1145: sb->nfds = nfds; ! 1146: sb->sets [0] = readfds; ! 1147: sb->sets [1] = writefds; ! 1148: sb->sets [2] = exceptfds; ! 1149: sb->timeout = timeout; ! 1150: sb->sigmp = wssigs; ! 1151: sb->action = 5; ! 1152: ! 1153: uae_sem_post (&sb->sem); ! 1154: ! 1155: m68k_dreg (regs, 0) = (((uae_u32)1) << sb->signal) | sb->eintrsigs | wssigs; ! 1156: sigs = CallLib (context, get_long (4), -0x13e); // Wait() ! 1157: ! 1158: if (sigmp) ! 1159: put_long (sigmp, sigs & (sb->eintrsigs | wssigs)); ! 1160: ! 1161: if (sigs & wssigs) { ! 1162: /* Received the signals we were waiting on */ ! 1163: DEBUG_LOG ("WaitSelect: got signal(s) %lx\n", sigs); ! 1164: ! 1165: if (!(sigs & (((uae_u32)1) << sb->signal))) { ! 1166: sockabort (sb); ! 1167: WAITSIGNAL; ! 1168: } ! 1169: ! 1170: sb->resultval = 0; ! 1171: if (readfds) fd_zero (readfds, nfds); ! 1172: if (writefds) fd_zero (writefds, nfds); ! 1173: if (exceptfds) fd_zero (exceptfds, nfds); ! 1174: ! 1175: bsdsocklib_seterrno (sb, 0); ! 1176: } else if (sigs & sb->eintrsigs) { ! 1177: /* Wait select was interrupted */ ! 1178: DEBUG_LOG ("WaitSelect: interrupted\n"); ! 1179: ! 1180: if (!(sigs & (((uae_u32)1) << sb->signal))) { ! 1181: sockabort (sb); ! 1182: WAITSIGNAL; ! 1183: } ! 1184: ! 1185: sb->resultval = -1; ! 1186: bsdsocklib_seterrno (sb, mapErrno (EINTR)); ! 1187: } ! 1188: clearsockabort(sb); ! 1189: } ! 1190: ! 1191: ! 1192: ! 1193: void host_accept (TrapContext *context, SB, uae_u32 sd, uae_u32 name, uae_u32 namelen) ! 1194: { ! 1195: sb->s = getsock (sb, sd + 1); ! 1196: if (sb->s == -1) { ! 1197: sb->resultval = -1; ! 1198: bsdsocklib_seterrno (sb, 9); /* EBADF */ ! 1199: return; ! 1200: } ! 1201: ! 1202: DEBUG_LOG ("accept(%d, %lx, %lx)\n", sb->s, name, namelen); ! 1203: sb->a_addr = name; ! 1204: sb->a_addrlen = namelen; ! 1205: sb->action = 6; ! 1206: sb->len = sd; ! 1207: ! 1208: uae_sem_post (&sb->sem); ! 1209: ! 1210: WAITSIGNAL; ! 1211: DEBUG_LOG ("Accept returns %d\n", sb->resultval); ! 1212: } ! 1213: ! 1214: int host_socket (SB, int af, int type, int protocol) ! 1215: { ! 1216: int sd; ! 1217: int s; ! 1218: ! 1219: DEBUG_LOG ("socket(%s,%s,%d) -> ",af == AF_INET ? "AF_INET" : "AF_other", ! 1220: type == SOCK_STREAM ? "SOCK_STREAM" : type == SOCK_DGRAM ? ! 1221: "SOCK_DGRAM " : "SOCK_RAW", protocol); ! 1222: ! 1223: if ((s = socket (af, type, protocol)) == -1) { ! 1224: SETERRNO; ! 1225: DEBUG_LOG ("failed (%d)\n", sb->sb_errno); ! 1226: return -1; ! 1227: } else { ! 1228: int arg = 1; ! 1229: sd = getsd (sb, s); ! 1230: setsockopt (s, SOL_SOCKET, SO_REUSEADDR, &arg, sizeof(arg)); ! 1231: } ! 1232: ! 1233: sb->ftable[sd-1] = SF_BLOCKING; ! 1234: DEBUG_LOG ("socket returns Amiga %d, NativeSide %d\n", sd - 1, s); ! 1235: return sd - 1; ! 1236: } ! 1237: ! 1238: uae_u32 host_bind (SB, uae_u32 sd, uae_u32 name, uae_u32 namelen) ! 1239: { ! 1240: uae_u32 success = 0; ! 1241: struct sockaddr_in addr; ! 1242: int len = sizeof (struct sockaddr_in); ! 1243: int s; ! 1244: ! 1245: s = getsock (sb, sd + 1); ! 1246: if (s == -1) { ! 1247: sb->resultval = -1; ! 1248: bsdsocklib_seterrno (sb, 9); /* EBADF */ ! 1249: return -1; ! 1250: } ! 1251: ! 1252: DEBUG_LOG ("bind(%d[%d],0x%lx,%d) -> ", sd, s, name, namelen); ! 1253: copysockaddr_a2n (&addr, name, namelen); ! 1254: printSockAddr (&addr); ! 1255: if ((success = bind (s, (struct sockaddr *)&addr, len)) != 0) { ! 1256: SETERRNO; ! 1257: DEBUG_LOG ("failed (%d)\n",sb->sb_errno); ! 1258: } else { ! 1259: DEBUG_LOG ("OK\n"); ! 1260: } ! 1261: return success; ! 1262: } ! 1263: ! 1264: uae_u32 host_listen (SB, uae_u32 sd, uae_u32 backlog) ! 1265: { ! 1266: int s; ! 1267: uae_u32 success = -1; ! 1268: ! 1269: DEBUG_LOG ("listen(%d,%d) -> ", sd, backlog); ! 1270: s = getsock (sb, sd + 1); ! 1271: ! 1272: if (s == -1) { ! 1273: bsdsocklib_seterrno (sb, 9); ! 1274: return -1; ! 1275: } ! 1276: ! 1277: if ((success = listen (s, backlog)) != 0) { ! 1278: SETERRNO; ! 1279: DEBUG_LOG ("failed (%d)\n", sb->sb_errno); ! 1280: } else { ! 1281: DEBUG_LOG ("OK\n"); ! 1282: } ! 1283: return success; ! 1284: } ! 1285: ! 1286: void host_getprotobyname (TrapContext *context, SB, uae_u32 name) ! 1287: { ! 1288: struct protoent *p = getprotobyname ((char *)get_real_address (name)); ! 1289: ! 1290: DEBUG_LOG ("Getprotobyname(%s)=%lx\n", get_real_address (name), p); ! 1291: ! 1292: if (p == NULL) { ! 1293: SETERRNO; ! 1294: return; ! 1295: } ! 1296: ! 1297: copyProtoent (context, sb, p); ! 1298: TRACE (("OK (%s, %d)\n", p->p_name, p->p_proto)); ! 1299: } ! 1300: ! 1301: void host_getprotobynumber (TrapContext *context, SB, uae_u32 number) ! 1302: { ! 1303: struct protoent *p = getprotobynumber(number); ! 1304: DEBUG_LOG("getprotobynumber(%d)=%lx\n", number, p); ! 1305: ! 1306: if (p == NULL) { ! 1307: SETERRNO; ! 1308: return; ! 1309: } ! 1310: ! 1311: copyProtoent (context, sb, p); ! 1312: TRACE (("OK (%s, %d)\n", p->p_name, p->p_proto)); ! 1313: } ! 1314: ! 1315: void host_getservbynameport (TrapContext *context, SB, uae_u32 name, uae_u32 proto, uae_u32 type) ! 1316: { ! 1317: struct servent *s = (type) ? ! 1318: getservbyport (name, (char *)get_real_address (proto)) : ! 1319: getservbyname ((char *)get_real_address (name), (char *)get_real_address (proto)); ! 1320: size_t size = 20; ! 1321: int numaliases = 0; ! 1322: uae_u32 aptr; ! 1323: int i; ! 1324: ! 1325: if (type) { ! 1326: DEBUG_LOG("Getservbyport(%d, %s) = %lx\n", name, get_real_address (proto), s); ! 1327: } else { ! 1328: DEBUG_LOG("Getservbyname(%s, %s) = %lx\n", get_real_address (name), get_real_address (proto), s); ! 1329: } ! 1330: ! 1331: if (s == NULL) { ! 1332: SETERRNO; ! 1333: return; ! 1334: } ! 1335: ! 1336: // compute total size of servent ! 1337: if (s->s_name != NULL) ! 1338: size += strlen (s->s_name) + 1; ! 1339: ! 1340: if (s->s_proto != NULL) ! 1341: size += strlen (s->s_proto) + 1; ! 1342: ! 1343: if (s->s_aliases != NULL) ! 1344: while (s->s_aliases[numaliases]) ! 1345: size += strlen (s->s_aliases[numaliases++]) + 5; ! 1346: ! 1347: if (sb->servent) { ! 1348: uae_FreeMem (context, sb->servent, sb->serventsize); ! 1349: } ! 1350: ! 1351: sb->servent = uae_AllocMem (context, size, 0); ! 1352: ! 1353: if (!sb->servent) { ! 1354: write_log ("BSDSOCK: WARNING - getservby%s() ran out of Amiga memory (couldn't allocate %d bytes)\n",type ? "port" : "name", size); ! 1355: bsdsocklib_seterrno (sb, 12); // ENOMEM ! 1356: return; ! 1357: } ! 1358: ! 1359: sb->serventsize = size; ! 1360: ! 1361: aptr = sb->servent + 20 + numaliases * 4; ! 1362: ! 1363: // transfer servent to Amiga memory ! 1364: put_long (sb->servent + 4, sb->servent + 16); ! 1365: put_long (sb->servent + 8, (unsigned short)htons (s->s_port)); ! 1366: ! 1367: for (i = 0; i < numaliases; i++) ! 1368: put_long (sb->servent + 16 + i * 4, addstr (&aptr, s->s_aliases[i])); ! 1369: put_long (sb->servent + 16 + numaliases * 4, 0); ! 1370: put_long (sb->servent, aptr); ! 1371: addstr (&aptr, s->s_name); ! 1372: put_long (sb->servent + 12, aptr); ! 1373: addstr (&aptr, s->s_proto); ! 1374: ! 1375: TRACE (("OK (%s, %d)\n", s->s_name, (unsigned short)htons (s->s_port))); ! 1376: bsdsocklib_seterrno (sb,0); ! 1377: } ! 1378: ! 1379: int host_sbinit (TrapContext *context, SB) ! 1380: { ! 1381: if (pipe (sb->sockabort) < 0) { ! 1382: return 0; ! 1383: } ! 1384: ! 1385: if (fcntl (sb->sockabort[0], F_SETFL, O_NONBLOCK) < 0) { ! 1386: write_log ("Set nonblock failed %d\n", errno); ! 1387: } ! 1388: ! 1389: uae_sem_init (&sb->sem, 0, 0); ! 1390: if (0) { ! 1391: write_log ("BSDSOCK: Failed to create semaphore.\n"); ! 1392: close (sb->sockabort[0]); ! 1393: close (sb->sockabort[1]); ! 1394: return 0; ! 1395: } ! 1396: ! 1397: /* Alloc hostent buffer */ ! 1398: sb->hostent = uae_AllocMem (context, 1024, 0); ! 1399: sb->hostentsize = 1024; ! 1400: ! 1401: /* @@@ The thread should be PTHREAD_CREATE_DETACHED */ ! 1402: if (uae_start_thread (bsdlib_threadfunc, (void *)sb, &sb->thread)) { ! 1403: write_log ("BSDSOCK: Failed to create thread.\n"); ! 1404: uae_sem_destroy (&sb->sem); ! 1405: close (sb->sockabort[0]); ! 1406: close (sb->sockabort[1]); ! 1407: ! 1408: return 0; ! 1409: } ! 1410: return 1; ! 1411: } ! 1412: ! 1413: void host_sbcleanup (SB) ! 1414: { ! 1415: int i; ! 1416: ! 1417: uae_thread_id thread = sb->thread; ! 1418: close (sb->sockabort[0]); ! 1419: close (sb->sockabort[1]); ! 1420: for (i = 0; i < sb->dtablesize; i++) { ! 1421: if (sb->dtable[i] != -1) { ! 1422: close(sb->dtable[i]); ! 1423: } ! 1424: } ! 1425: sb->action = 0; ! 1426: ! 1427: uae_sem_post (&sb->sem); /* destroy happens on socket thread */ ! 1428: ! 1429: /* We need to join with the socket thread to allow the thread to die ! 1430: * and clean up resources when the underlying thread layer is pthreads. ! 1431: * Ideally, this shouldn't be necessary, but, for example, when SDL uses ! 1432: * pthreads, it always creates joinable threads - and we can't do anything ! 1433: * about that. */ ! 1434: uae_wait_thread (thread); ! 1435: } ! 1436: ! 1437: void host_sbreset (void) ! 1438: { ! 1439: /* TODO */ ! 1440: } ! 1441: ! 1442: uae_u32 host_Inet_NtoA (TrapContext *context, SB, uae_u32 in) ! 1443: { ! 1444: char *addr; ! 1445: struct in_addr ina; ! 1446: uae_u32 buf; ! 1447: ! 1448: *(uae_u32 *)&ina = htonl (in); ! 1449: ! 1450: TRACE (("Inet_NtoA(%lx) -> ", in)); ! 1451: ! 1452: if ((addr = inet_ntoa(ina)) != NULL) { ! 1453: buf = m68k_areg (regs, 6) + offsetof (struct UAEBSDBase, scratchbuf); ! 1454: strncpyha_safe (buf, addr, SCRATCHBUFSIZE); ! 1455: TRACE (("%s\n", addr)); ! 1456: return buf; ! 1457: } else ! 1458: SETERRNO; ! 1459: ! 1460: TRACE (("failed (%d)\n", sb->sb_errno)); ! 1461: ! 1462: return 0; ! 1463: } ! 1464: ! 1465: uae_u32 host_inet_addr (uae_u32 cp) ! 1466: { ! 1467: uae_u32 addr; ! 1468: char *cp_rp; ! 1469: ! 1470: cp_rp = (char *)get_real_address (cp); ! 1471: ! 1472: addr = htonl (inet_addr (cp_rp)); ! 1473: ! 1474: TRACE (("inet_addr(%s) -> 0x%08lx\n", cp_rp, addr)); ! 1475: ! 1476: return addr; ! 1477: } ! 1478: ! 1479: uae_u32 host_shutdown (SB, uae_u32 sd, uae_u32 how) ! 1480: { ! 1481: SOCKET s; ! 1482: ! 1483: TRACE (("shutdown(%d,%d) -> ", sd, how)); ! 1484: s = getsock (sb, sd + 1); ! 1485: ! 1486: if (s != -1) { ! 1487: if (shutdown (s, how)) { ! 1488: SETERRNO; ! 1489: TRACE (("failed (%d)\n", sb->sb_errno)); ! 1490: } else { ! 1491: TRACE (("OK\n")); ! 1492: return 0; ! 1493: } ! 1494: } ! 1495: ! 1496: return -1; ! 1497: } ! 1498: ! 1499: int host_dup2socket (SB, int fd1, int fd2) { ! 1500: int s1, s2; ! 1501: ! 1502: TRACE (("dup2socket(%d,%d) -> ", fd1, fd2)); ! 1503: fd1++; ! 1504: ! 1505: s1 = getsock (sb, fd1); ! 1506: if (s1 != -1) { ! 1507: if (fd2 != -1) { ! 1508: if ((unsigned int) (fd2) >= (unsigned int) sb->dtablesize) { ! 1509: TRACE (("Bad file descriptor (%d)\n", fd2)); ! 1510: bsdsocklib_seterrno (sb, 9); /* EBADF */ ! 1511: } ! 1512: fd2++; ! 1513: s2 = getsock (sb, fd2); ! 1514: if (s2 != -1) { ! 1515: close (s2); ! 1516: } ! 1517: setsd (sb, fd2, dup (s1)); ! 1518: TRACE (("0(%d)\n", getsock (sb, fd2))); ! 1519: return 0; ! 1520: } else { ! 1521: fd2 = getsd (sb, 1); ! 1522: if (fd2 != -1) { ! 1523: setsd (sb, fd2, dup (s1)); ! 1524: TRACE (("%d(%d)\n", fd2, getsock (sb, fd2))); ! 1525: return (fd2 - 1); ! 1526: } else { ! 1527: TRACE(("-1\n")); ! 1528: return -1; ! 1529: } ! 1530: } ! 1531: } ! 1532: TRACE (("-1\n")); ! 1533: return -1; ! 1534: } ! 1535: ! 1536: uae_u32 host_getsockopt (SB, uae_u32 sd, uae_u32 level, uae_u32 optname, ! 1537: uae_u32 optval, uae_u32 optlen) ! 1538: { ! 1539: socklen_t len = 0; ! 1540: int r; ! 1541: int s; ! 1542: int nativelevel = mapsockoptlevel(level); ! 1543: int nativeoptname = mapsockoptname(nativelevel, optname); ! 1544: void *buf = NULL; ! 1545: s = getsock (sb, sd + 1); ! 1546: ! 1547: if (s == -1) { ! 1548: bsdsocklib_seterrno(sb, 9); /* EBADF */ ! 1549: return -1; ! 1550: } ! 1551: ! 1552: if (optlen) { ! 1553: len = get_long (optlen); ! 1554: buf = malloc(len); ! 1555: if (buf == NULL) { ! 1556: return -1; ! 1557: } ! 1558: } ! 1559: ! 1560: r = getsockopt (s, nativelevel, nativeoptname, ! 1561: optval ? buf : NULL, optlen ? &len : NULL); ! 1562: ! 1563: if (optlen) ! 1564: put_long (optlen, len); ! 1565: ! 1566: SETERRNO; ! 1567: DEBUG_LOG ("getsockopt: sock AmigaSide %d NativeSide %d, level %d, 'name' %x(%d), len %d -> %d, %d\n", ! 1568: sd, s, level, optname, nativeoptname, len, r, errno); ! 1569: ! 1570: if (optval) { ! 1571: if (r == 0) { ! 1572: mapsockoptreturn(nativelevel, nativeoptname, optval, buf); ! 1573: } ! 1574: } ! 1575: ! 1576: if (buf != NULL) ! 1577: free(buf); ! 1578: return r; ! 1579: } ! 1580: ! 1581: uae_u32 host_IoctlSocket (SB, uae_u32 sd, uae_u32 request, uae_u32 arg) ! 1582: { ! 1583: int sock = getsock (sb, sd + 1); ! 1584: int r, argval = get_long (arg); ! 1585: long flags; ! 1586: ! 1587: if (sock == -1) { ! 1588: sb->resultval = -1; ! 1589: bsdsocklib_seterrno (sb, 9); /* EBADF */ ! 1590: return -1; ! 1591: } ! 1592: ! 1593: if ((flags = fcntl (sock, F_GETFL)) == -1) { ! 1594: SETERRNO; ! 1595: return -1; ! 1596: } ! 1597: ! 1598: DEBUG_LOG ("Ioctl code is %lx, flags are %d\n", request, flags); ! 1599: ! 1600: switch (request) { ! 1601: case 0x8004667B: /* FIOGETOWN */ ! 1602: sb->ownertask = get_long (arg); ! 1603: return 0; ! 1604: ! 1605: case 0x8004667C: /* FIOSETOWN */ ! 1606: put_long (arg,sb->ownertask); ! 1607: return 0; ! 1608: case 0x8004667D: /* FIOASYNC */ ! 1609: # ifdef O_ASYNC ! 1610: r = fcntl (sock, F_SETFL, argval ? flags | O_ASYNC : flags & ~O_ASYNC); ! 1611: return r; ! 1612: # else ! 1613: /* O_ASYNC is only available on Linux and BSD systems */ ! 1614: return fcntl (sock, F_GETFL); ! 1615: # endif ! 1616: ! 1617: case 0x8004667E: /* FIONBIO */ ! 1618: r = fcntl (sock, F_SETFL, argval ? ! 1619: flags | O_NONBLOCK : flags & ~O_NONBLOCK); ! 1620: if (argval) { ! 1621: DEBUG_LOG ("nonblocking\n"); ! 1622: sb->ftable[sd-1] &= ~SF_BLOCKING; ! 1623: } else { ! 1624: DEBUG_LOG ("blocking\n"); ! 1625: sb->ftable[sd-1] |= SF_BLOCKING; ! 1626: } ! 1627: return r; ! 1628: ! 1629: case 0x4004667F: /* FIONREAD */ ! 1630: r = ioctl (sock, FIONREAD, &flags); ! 1631: if (r >= 0) { ! 1632: put_long (arg, flags); ! 1633: } ! 1634: return r; ! 1635: ! 1636: } /* end switch */ ! 1637: ! 1638: bsdsocklib_seterrno (sb, EINVAL); ! 1639: return -1; ! 1640: } ! 1641: ! 1642: int host_CloseSocket (SB, int sd) ! 1643: { ! 1644: int s = getsock (sb, sd + 1); ! 1645: int retval; ! 1646: ! 1647: if (s == -1) { ! 1648: bsdsocklib_seterrno (sb, 9); /* EBADF */ ! 1649: return -1; ! 1650: } ! 1651: ! 1652: /* ! 1653: if (checksd (sb, sd + 1) == 1) { ! 1654: return 0; ! 1655: } ! 1656: */ ! 1657: DEBUG_LOG ("CloseSocket Amiga: %d, NativeSide %d\n", sd, s); ! 1658: retval = close (s); ! 1659: SETERRNO; ! 1660: releasesock (sb, sd + 1); ! 1661: return retval; ! 1662: } ! 1663: ! 1664: void host_closesocketquick (int s) ! 1665: { ! 1666: struct linger l; ! 1667: l.l_onoff = 0; ! 1668: l.l_linger = 0; ! 1669: if (s != -1) { ! 1670: setsockopt (s, SOL_SOCKET, SO_LINGER, &l, sizeof(l)); ! 1671: close (s); ! 1672: } ! 1673: } ! 1674: ! 1675: uae_u32 host_gethostname (uae_u32 name, uae_u32 namelen) ! 1676: { ! 1677: return gethostname ((char *)get_real_address (name), namelen); ! 1678: } ! 1679: ! 1680: int init_socket_layer(void) ! 1681: { ! 1682: uae_sem_init(&sem_queue, 0, 1); ! 1683: if (0 /* @@@ */) { ! 1684: DEBUG_LOG("Can't create sem %d\n", errno); ! 1685: return 0; ! 1686: } ! 1687: ! 1688: return 1; ! 1689: } ! 1690: ! 1691: void clearsockabort (SB) ! 1692: { ! 1693: int chr; ! 1694: int num; ! 1695: ! 1696: while ((num = read (sb->sockabort[0], &chr, sizeof(chr))) >= 0) { ! 1697: DEBUG_LOG ("Sockabort got %d bytes\n", num); ! 1698: ; ! 1699: } ! 1700: } ! 1701: ! 1702: void sockabort (SB) ! 1703: { ! 1704: int chr = 1; ! 1705: DEBUG_LOG ("Sock abort!!\n"); ! 1706: write (sb->sockabort[1], &chr, sizeof (chr)); ! 1707: } ! 1708: ! 1709: void locksigqueue (void) ! 1710: { ! 1711: uae_sem_wait(&sem_queue); ! 1712: } ! 1713: ! 1714: void unlocksigqueue (void) ! 1715: { ! 1716: uae_sem_post(&sem_queue); ! 1717: } ! 1718: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.