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