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