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
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_uae.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(...) { }
60 #endif
61 
62 #define WAITSIGNAL	waitsig (context, sb)
63 #ifdef ANDROID
64 #define IPPROTO_ENCAP 98
65 #endif
66 
67 /* Sigqueue is unsafe on SMP machines.
68  * Temporary work-around.
69  */
70 //#define SETSIGNAL	addtosigqueue (sb, 0)
71 #define SETSIGNAL \
72     do { \
73 	uae_Signal (sb->ownertask, sb->sigstosend | ((uae_u32) 1) << sb->signal); \
74 	sb->dosignal = 1; \
75     } while (0)
76 
77 
78 #define SETERRNO	bsdsocklib_seterrno (sb,mapErrno (errno))
79 #define SETHERRNO	bsdsocklib_setherrno (sb, h_errno)
80 
81 
82 /* BSD-systems don't seem to have MSG_NOSIGNAL..
83    @@@ We need to catch SIGPIPE on those systems! (?) */
84 #ifndef MSG_NOSIGNAL
85 #define MSG_NOSIGNAL 0
86 #endif
87 
88 #define S_GL_result(res) sb->resultval = (res)
89 
90 uae_u32 bsdthr_Accept_2 (SB);
91 uae_u32 bsdthr_Recv_2 (SB);
92 uae_u32 bsdthr_blockingstuff (uae_u32 (*tryfunc)(SB), SB);
93 uae_u32 bsdthr_SendRecvAcceptConnect (uae_u32 (*tryfunc)(SB), SB);
94 uae_u32 bsdthr_Send_2 (SB);
95 uae_u32 bsdthr_Connect_2 (SB);
96 uae_u32 bsdthr_WaitSelect (SB);
97 uae_u32 bsdthr_Wait (SB);
98 void clearsockabort (SB);
99 
100 static uae_sem_t sem_queue;
101 
102 /**
103  ** Helper functions
104  **/
105 
106 /*
107  * Map host errno to amiga errno
108  */
mapErrno(int e)109 static int mapErrno (int e)
110 {
111     switch (e) {
112 	case EINTR:		e = 4;  break;
113 	case EDEADLK:		e = 11; break;
114 	case EAGAIN:		e = 35; break;
115 	case EINPROGRESS:	e = 36; break;
116 	case EALREADY:		e = 37; break;
117 	case ENOTSOCK:		e = 38; break;
118 	case EDESTADDRREQ:	e = 39; break;
119 	case EMSGSIZE:		e = 40; break;
120 	case EPROTOTYPE:	e = 41; break;
121 	case ENOPROTOOPT:	e = 42; break;
122 	case EPROTONOSUPPORT:	e = 43; break;
123 	case ESOCKTNOSUPPORT:	e = 44; break;
124 	case EOPNOTSUPP:	e = 45;	break;
125 	case EPFNOSUPPORT:	e = 46; break;
126 	case EAFNOSUPPORT:	e = 47; break;
127 	case EADDRINUSE:	e = 48; break;
128 	case EADDRNOTAVAIL:	e = 49; break;
129 	case ENETDOWN:		e = 50; break;
130 	case ENETUNREACH:	e = 51; break;
131 	case ENETRESET:		e = 52; break;
132 	case ECONNABORTED:	e = 53; break;
133 	case ECONNRESET:	e = 54; break;
134 	case ENOBUFS:		e = 55; break;
135 	case EISCONN:		e = 56; break;
136 	case ENOTCONN:		e = 57; break;
137 	case ESHUTDOWN:		e = 58; break;
138 	case ETOOMANYREFS:	e = 59; break;
139 	case ETIMEDOUT:		e = 60; break;
140 	case ECONNREFUSED:	e = 61; break;
141 	case ELOOP:		e = 62; break;
142 	case ENAMETOOLONG:	e = 63; break;
143 	default: break;
144     }
145     return e;
146 }
147 
148 /*
149  * Map amiga (s|g)etsockopt level into native one
150  */
mapsockoptlevel(int level)151 static int mapsockoptlevel (int level)
152 {
153     switch (level) {
154 	case 0xffff:
155 	    return SOL_SOCKET;
156 	case 0:
157 	    return IPPROTO_IP;
158 	case 1:
159 	    return IPPROTO_ICMP;
160 	case 2:
161 	    return IPPROTO_IGMP;
162 #ifdef IPPROTO_IPIP
163 	case 4:
164 	    return IPPROTO_IPIP;
165 #endif
166 	case 6:
167 	    return IPPROTO_TCP;
168 	case 8:
169 	    return IPPROTO_EGP;
170 	case 12:
171 	    return IPPROTO_PUP;
172 	case 17:
173 	    return IPPROTO_UDP;
174 	case 22:
175 	    return IPPROTO_IDP;
176 #ifdef IPPROTO_TP
177 	case 29:
178 	    return IPPROTO_TP;
179 #endif
180 	case 98:
181 	    return IPPROTO_ENCAP;
182 	default:
183 	    DEBUG_LOG ("Unknown sockopt level %d\n", level);
184 	    return level;
185     }
186 }
187 
188 /*
189  * Map amiga (s|g)etsockopt optname into native one
190  */
mapsockoptname(int level,int optname)191 static int mapsockoptname (int level, int optname)
192 {
193     switch (level) {
194 
195 	case SOL_SOCKET:
196 	    switch (optname) {
197 		case 0x0001:
198 		    return SO_DEBUG;
199 		case 0x0002:
200 		    return SO_ACCEPTCONN;
201 		case 0x0004:
202 		    return SO_REUSEADDR;
203 		case 0x0008:
204 		    return SO_KEEPALIVE;
205 		case 0x0010:
206 		    return SO_DONTROUTE;
207 		case 0x0020:
208 		    return SO_BROADCAST;
209 #ifdef SO_USELOOPBACK
210 		case 0x0040:
211 		    return SO_USELOOPBACK;
212 #endif
213 		case 0x0080:
214 		    return SO_LINGER;
215 		case  0x0100:
216 		    return SO_OOBINLINE;
217 #ifdef SO_REUSEPORT
218 		case 0x0200:
219 		    return SO_REUSEPORT;
220 #endif
221 		case 0x1001:
222 		    return SO_SNDBUF;
223 		case 0x1002:
224 		    return SO_RCVBUF;
225 		case 0x1003:
226 		    return SO_SNDLOWAT;
227 		case 0x1004:
228 		    return SO_RCVLOWAT;
229 		case 0x1005:
230 		    return SO_SNDTIMEO;
231 		case 0x1006:
232 		    return SO_RCVTIMEO;
233 		case 0x1007:
234 		    return SO_ERROR;
235 		case 0x1008:
236 		    return SO_TYPE;
237 
238 		default:
239 		    DEBUG_LOG ("Invalid setsockopt option %x for level %d\n",
240 			       optname, level);
241 		    return -1;
242 	    }
243 	    break;
244 
245 	case IPPROTO_IP:
246 	    switch (optname) {
247 		case 1:
248 		    return IP_OPTIONS;
249 		case 2:
250 		    return IP_HDRINCL;
251 		case 3:
252 		    return IP_TOS;
253 		case 4:
254 		    return IP_TTL;
255 		case 5:
256 		    return IP_RECVOPTS;
257 		case 6:
258 		    return IP_RECVRETOPTS;
259 		case 8:
260 		    return IP_RETOPTS;
261 		case 9:
262 		    return IP_MULTICAST_IF;
263 		case 10:
264 		    return IP_MULTICAST_TTL;
265 		case 11:
266 		    return IP_MULTICAST_LOOP;
267 		case 12:
268 		    return IP_ADD_MEMBERSHIP;
269 
270 		default:
271 		    DEBUG_LOG ("Invalid setsockopt option %x for level %d\n",
272 			       optname, level);
273 		    return -1;
274 	    }
275 	    break;
276 
277 	case IPPROTO_TCP:
278 	    switch (optname) {
279 		case 1:
280 		    return TCP_NODELAY;
281 		case 2:
282 		    return TCP_MAXSEG;
283 
284 		default:
285 		    DEBUG_LOG ("Invalid setsockopt option %x for level %d\n",
286 			       optname, level);
287 		    return -1;
288 	    }
289 	    break;
290 
291 	default:
292 	    DEBUG_LOG ("Unknown level %d\n", level);
293 	    return -1;
294     }
295 }
296 
297 
298 /*
299  * Map amiga (s|g)etsockopt return value into the correct form
300  */
mapsockoptreturn(int level,int optname,uae_u32 optval,void * buf)301 static void mapsockoptreturn(int level, int optname, uae_u32 optval, void *buf)
302 {
303     switch (level) {
304 
305 	case SOL_SOCKET:
306 	    switch (optname) {
307 		case SO_DEBUG:
308 		case SO_ACCEPTCONN:
309 		case SO_REUSEADDR:
310 		case SO_KEEPALIVE:
311 		case SO_DONTROUTE:
312 		case SO_BROADCAST:
313 #ifdef SO_USELOOPBACK
314 		case SO_USELOOPBACK:
315 #endif
316 		case SO_LINGER:
317 		case SO_OOBINLINE:
318 #ifdef SO_REUSEPORT
319 		case SO_REUSEPORT:
320 #endif
321 		case SO_SNDBUF:
322 		case SO_RCVBUF:
323 		case SO_SNDLOWAT:
324 		case SO_RCVLOWAT:
325 		case SO_SNDTIMEO:
326 		case SO_RCVTIMEO:
327 		case SO_TYPE:
328 		    put_long (optval, *(int *)buf);
329 		    break;
330 
331 		case SO_ERROR:
332 		    DEBUG_LOG("New errno is %d\n", mapErrno(*(int *)buf));
333 		    put_long (optval, mapErrno(*(int *)buf));
334 		    break;
335 		default:
336 		    break;
337 	    }
338 	    break;
339 
340 	case IPPROTO_IP:
341 	    switch (optname) {
342 		case IP_OPTIONS:
343 		case IP_HDRINCL:
344 		case IP_TOS:
345 		case IP_TTL:
346 		case IP_RECVOPTS:
347 		//case IP_RECVRETOPTS:
348 		//case IP_RETOPTS:
349 		case IP_MULTICAST_IF:
350 		case IP_MULTICAST_TTL:
351 		case IP_MULTICAST_LOOP:
352 		case IP_ADD_MEMBERSHIP:
353 		    put_long (optval, *(int *)buf);
354 		    break;
355 
356 		default:
357 		    break;
358 	    }
359 	    break;
360 
361 	case IPPROTO_TCP:
362 	    switch (optname) {
363 		case TCP_NODELAY:
364 		case TCP_MAXSEG:
365 		    put_long (optval,*(int *)buf);
366 		    break;
367 
368 		default:
369 		    break;
370 	    }
371 	    break;
372 
373 	default:
374 	    break;
375     }
376 }
377 
378 /*
379  * Map amiga (s|g)etsockopt value from amiga to the appropriate value
380  */
mapsockoptvalue(int level,int optname,uae_u32 optval,void * buf)381 static void mapsockoptvalue(int level, int optname, uae_u32 optval, void *buf)
382 {
383     switch (level) {
384 
385 	case SOL_SOCKET:
386 	    switch (optname) {
387 		case SO_DEBUG:
388 		case SO_ACCEPTCONN:
389 		case SO_REUSEADDR:
390 		case SO_KEEPALIVE:
391 		case SO_DONTROUTE:
392 		case SO_BROADCAST:
393 #ifdef SO_USELOOPBACK
394 		case SO_USELOOPBACK:
395 #endif
396 		case SO_LINGER:
397 		case SO_OOBINLINE:
398 #ifdef SO_REUSEPORT
399 		case SO_REUSEPORT:
400 #endif
401 		case SO_SNDBUF:
402 		case SO_RCVBUF:
403 		case SO_SNDLOWAT:
404 		case SO_RCVLOWAT:
405 		case SO_SNDTIMEO:
406 		case SO_RCVTIMEO:
407 		case SO_TYPE:
408 		case SO_ERROR:
409 		    *((int *)buf) = get_long (optval);
410 		    break;
411 		default:
412 		    break;
413 	    }
414 	    break;
415 
416 	case IPPROTO_IP:
417 	    switch (optname) {
418 		case IP_OPTIONS:
419 		case IP_HDRINCL:
420 		case IP_TOS:
421 		case IP_TTL:
422 		case IP_RECVOPTS:
423 		//case IP_RECVRETOPTS:
424 		//case IP_RETOPTS:
425 		case IP_MULTICAST_IF:
426 		case IP_MULTICAST_TTL:
427 		case IP_MULTICAST_LOOP:
428 		case IP_ADD_MEMBERSHIP:
429 		    *((int *)buf) = get_long (optval);
430 		    break;
431 
432 		default:
433 		    break;
434 	    }
435 	    break;
436 
437 	case IPPROTO_TCP:
438 	    switch (optname) {
439 		case TCP_NODELAY:
440 		case TCP_MAXSEG:
441 		    *((int *)buf) = get_long (optval);
442 		    break;
443 
444 		default:
445 		    break;
446 	    }
447 	    break;
448 
449 	default:
450 	    break;
451     }
452 }
453 
454 
fd_zero(uae_u32 fdset,uae_u32 nfds)455 STATIC_INLINE void fd_zero (uae_u32 fdset, uae_u32 nfds)
456 {
457     unsigned int i;
458 
459     for (i = 0; i < nfds; i += 32, fdset += 4)
460 		put_long (fdset, 0);
461 }
462 
bsd_amigaside_FD_ISSET(int n,uae_u32 set)463 STATIC_INLINE int bsd_amigaside_FD_ISSET (int n, uae_u32 set)
464 {
465     uae_u32 foo = get_long (set + (n / 32));
466     if (foo & (1 << (n % 32)))
467 		return 1;
468     return 0;
469 }
470 
bsd_amigaside_FD_ZERO(uae_u32 set)471 STATIC_INLINE void bsd_amigaside_FD_ZERO (uae_u32 set)
472 {
473     put_long (set, 0);
474     put_long (set + 4, 0);
475 }
476 
bsd_amigaside_FD_SET(int n,uae_u32 set)477 STATIC_INLINE void bsd_amigaside_FD_SET (int n, uae_u32 set)
478 {
479     set = set + (n / 32);
480     put_long (set, get_long (set) | (1 << (n % 32)));
481 }
482 
483 #ifdef DEBUG_BSDSOCKET
printSockAddr(struct sockaddr_in * in)484 static void printSockAddr (struct sockaddr_in *in)
485 {
486     DEBUG_LOG ("Family %d, ", in->sin_family);
487     DEBUG_LOG ("Port %d,",    ntohs (in->sin_port));
488     DEBUG_LOG ("Address %s,", inet_ntoa (in->sin_addr));
489 }
490 #else
491 #define printSockAddr(sockAddr)
492 #endif
493 
494 /*
495  * Copy a sockaddr object from amiga space to native space
496  */
copysockaddr_a2n(struct sockaddr_in * addr,uae_u32 a_addr,unsigned int len)497 static int copysockaddr_a2n (struct sockaddr_in *addr, uae_u32 a_addr, unsigned int len)
498 {
499     if ((len > sizeof (struct sockaddr_in)) || (len < 8))
500 	return 1;
501 
502     if (a_addr == 0)
503 		return 0;
504 
505     addr->sin_family      = get_byte (a_addr + 1);
506     addr->sin_port        = htons (get_word (a_addr + 2));
507     addr->sin_addr.s_addr = htonl (get_long (a_addr + 4));
508 
509     if (len > 8)
510 		memcpy (&addr->sin_zero, get_real_address (a_addr + 8), len - 8);   /* Pointless? */
511 
512     return 0;
513 }
514 
515 /*
516  * Copy a sockaddr object from native space to amiga space
517  */
copysockaddr_n2a(uae_u32 a_addr,const struct sockaddr_in * addr,unsigned int len)518 static int copysockaddr_n2a (uae_u32 a_addr, const struct sockaddr_in *addr, unsigned int len)
519 {
520     if (len < 8)
521 		return 1;
522 
523     if (a_addr == 0)
524 		return 0;
525 
526     put_byte (a_addr, 0);                       /* Anyone use this field? */
527     put_byte (a_addr + 1, addr->sin_family);
528     put_word (a_addr + 2, ntohs (addr->sin_port));
529     put_long (a_addr + 4, ntohl (addr->sin_addr.s_addr));
530 
531     if (len > 8)
532 		memset (get_real_address (a_addr + 8), 0, len - 8);
533 
534     return 0;
535 }
536 
537 /*
538  * Copy a hostent object from native space to amiga space
539  */
copyHostent(const struct hostent * hostent,SB)540 static void copyHostent (const struct hostent *hostent, SB)
541 {
542     int size = 28;
543     int i;
544     int numaddr = 0;
545     int numaliases = 0;
546     uae_u32 aptr;
547 
548     if (hostent->h_name != NULL)
549 		size += strlen(hostent->h_name)+1;
550 
551     if (hostent->h_aliases != NULL)
552 	while (hostent->h_aliases[numaliases])
553 	    size += strlen(hostent->h_aliases[numaliases++]) + 5;
554 
555     if (hostent->h_addr_list != NULL) {
556 		while (hostent->h_addr_list[numaddr])
557 		    numaddr++;
558 		size += numaddr*(hostent->h_length+4);
559     }
560 
561     aptr = sb->hostent + 28 + numaliases * 4 + numaddr * 4;
562 
563     // transfer hostent to Amiga memory
564     put_long (sb->hostent + 4, sb->hostent + 20);
565     put_long (sb->hostent + 8, hostent->h_addrtype);
566     put_long (sb->hostent + 12, hostent->h_length);
567     put_long (sb->hostent + 16, sb->hostent + 24 + numaliases*4);
568 
569     for (i = 0; i < numaliases; i++)
570 	put_long (sb->hostent + 20 + i * 4, addstr (&aptr, hostent->h_aliases[i]));
571     put_long (sb->hostent + 20 + numaliases * 4, 0);
572 
573     for (i = 0; i < numaddr; i++) {
574 		put_long (sb->hostent + 24 + (numaliases + i) * 4, addmem (&aptr, hostent->h_addr_list[i], hostent->h_length));
575     }
576     put_long (sb->hostent + 24 + numaliases * 4 + numaddr * 4, 0);
577     put_long (sb->hostent, aptr);
578     addstr (&aptr, hostent->h_name);
579 
580     BSDTRACE (("OK (%s)\n",hostent->h_name));
581     bsdsocklib_seterrno (sb,0);
582 }
583 
584 /*
585  * Copy a protoent object from native space to Amiga space
586  */
copyProtoent(TrapContext * context,SB,const struct protoent * p)587 static void copyProtoent (TrapContext *context, SB, const struct protoent *p)
588 {
589     size_t size = 16;
590     int numaliases = 0;
591     int i;
592     uae_u32 aptr;
593 
594     // compute total size of protoent
595     if (p->p_name != NULL)
596 		size += strlen (p->p_name) + 1;
597 
598     if (p->p_aliases != NULL)
599 	while (p->p_aliases[numaliases])
600 	    size += strlen (p->p_aliases[numaliases++]) + 5;
601 
602     if (sb->protoent) {
603 		uae_FreeMem (context, sb->protoent, sb->protoentsize, sb->sysbase);
604     }
605 
606     sb->protoent = uae_AllocMem (context, size, 0, sb->sysbase);
607 
608     if (!sb->protoent) {
609 		write_log ("BSDSOCK: WARNING - copyProtoent() ran out of Amiga memory (couldn't allocate %d bytes)\n", size);
610 		bsdsocklib_seterrno (sb, 12); // ENOMEM
611 		return;
612     }
613 
614     sb->protoentsize = size;
615 
616     aptr = sb->protoent + 16 + numaliases * 4;
617 
618     // transfer protoent to Amiga memory
619     put_long (sb->protoent + 4, sb->protoent + 12);
620     put_long (sb->protoent + 8, p->p_proto);
621 
622     for (i = 0; i < numaliases; i++)
623 	put_long (sb->protoent + 12 + i * 4, addstr (&aptr, p->p_aliases[i]));
624     put_long (sb->protoent + 12 + numaliases * 4, 0);
625     put_long (sb->protoent, aptr);
626     addstr (&aptr, p->p_name);
627     bsdsocklib_seterrno(sb, 0);
628 }
629 
630 
631 
bsdthr_WaitSelect(SB)632 uae_u32 bsdthr_WaitSelect (SB)
633 {
634     fd_set sets [3];
635     int i, s, set, a_s, max;
636     uae_u32 a_set;
637     struct timeval tv;
638     int r;
639 
640     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);
641 
642     if (sb->timeout)
643 	DEBUG_LOG ("WaitSelect: timeout %d %d\n", get_long (sb->timeout), 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 
bsdthr_Accept_2(SB)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)", sb->resultval, s, &hlen, get_long (sb->a_addrlen));
734 		printSockAddr (&addr);
735 		foo = get_long (sb->a_addrlen);
736 		if (foo > 16)
737 		    put_long (sb->a_addrlen, 16);
738 		copysockaddr_n2a (sb->a_addr, &addr, foo);
739 		return s2 - 1;
740     } else {
741 		return -1;
742     }
743 }
744 
bsdthr_Recv_2(SB)745 uae_u32 bsdthr_Recv_2 (SB)
746 {
747     int foo;
748     int i;
749 /* REMOVEME:
750  * nowhere used
751  */
752 #if 0
753     int l;
754 #endif
755     if (sb->from == 0) {
756 		foo = recv (sb->s, sb->buf, sb->len, sb->flags /*| MSG_NOSIGNAL*/);
757 		DEBUG_LOG ("recv2, recv returns %d, errno is %d\n", foo, errno);
758     } else {
759 		struct sockaddr_in addr;
760 		socklen_t l = sizeof (struct sockaddr_in);
761 		i = get_long (sb->fromlen);
762 		copysockaddr_a2n (&addr, sb->from, i);
763 		foo = recvfrom (sb->s, sb->buf, sb->len, sb->flags | MSG_NOSIGNAL, (struct sockaddr *)&addr, &l);
764 		DEBUG_LOG ("recv2, recvfrom returns %d, errno is %d\n", foo, errno);
765 		if (foo >= 0) {
766 		    copysockaddr_n2a (sb->from, &addr, l);
767 		    put_long (sb->fromlen, l);
768 		}
769     }
770     return foo;
771 }
772 
bsdthr_Send_2(SB)773 uae_u32 bsdthr_Send_2 (SB)
774 {
775     if (sb->to == 0) {
776 		return send (sb->s, sb->buf, sb->len, sb->flags | MSG_NOSIGNAL);
777     } else {
778 		struct sockaddr_in addr;
779 		int l = sizeof (struct sockaddr_in);
780 		copysockaddr_a2n (&addr, sb->to, sb->tolen);
781 		return sendto (sb->s, sb->buf, sb->len, sb->flags | MSG_NOSIGNAL, (struct sockaddr *)&addr, l);
782     }
783 }
784 
bsdthr_Connect_2(SB)785 uae_u32 bsdthr_Connect_2 (SB)
786 {
787     if (sb->action == 1) {
788 		struct sockaddr_in addr;
789 		int len = sizeof (struct sockaddr_in);
790 		int retval;
791 		copysockaddr_a2n (&addr, sb->a_addr, sb->a_addrlen);
792 		retval = connect (sb->s, (struct sockaddr *)&addr, len);
793 		DEBUG_LOG ("Connect returns %d, errno is %d\n", retval, errno);
794 		/* Hack: I need to set the action to something other than
795 		 * 1 but I know action == 2 does the correct thing
796 		 */
797 		sb->action = 2;
798 		if (retval == 0) {
799 		     errno = 0;
800 		}
801 		return retval;
802     } else {
803 		int foo;
804 		socklen_t bar;
805 		bar = sizeof (foo);
806 		if (getsockopt (sb->s, SOL_SOCKET, SO_ERROR, &foo, &bar) == 0) {
807 		    errno = foo;
808 		    DEBUG_LOG("Connect status is %d\n", foo);
809 		    return (foo == 0) ? 0 : -1;
810 		}
811 		return -1;
812     }
813 }
814 
bsdthr_SendRecvAcceptConnect(uae_u32 (* tryfunc)(SB),SB)815 uae_u32 bsdthr_SendRecvAcceptConnect (uae_u32 (*tryfunc)(SB), SB)
816 {
817     return bsdthr_blockingstuff (tryfunc, sb);
818 }
819 
bsdthr_blockingstuff(uae_u32 (* tryfunc)(SB),SB)820 uae_u32 bsdthr_blockingstuff (uae_u32 (*tryfunc)(SB), SB)
821 {
822     int done = 0, foo;
823     long flags;
824     int nonblock;
825     if ((flags = fcntl (sb->s, F_GETFL)) == -1)
826 	flags = 0;
827     nonblock = (flags & O_NONBLOCK);
828     fcntl (sb->s, F_SETFL, flags | O_NONBLOCK);
829     while (!done) {
830 	done = 1;
831 	foo = tryfunc (sb);
832 	if (foo < 0 && !nonblock) {
833 	    if ((errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINPROGRESS)) {
834 		fd_set readset, writeset, exceptset;
835 		int maxfd = (sb->s > sb->sockabort[0]) ? sb->s : sb->sockabort[0];
836 		int num;
837 
838 		FD_ZERO (&readset);
839 		FD_ZERO (&writeset);
840 		FD_ZERO (&exceptset);
841 
842 		if (sb->action == 3 || sb->action == 6)
843 		    FD_SET (sb->s, &readset);
844 		if (sb->action == 2 || sb->action == 1 || sb->action == 4)
845 		    FD_SET (sb->s, &writeset);
846 		FD_SET (sb->sockabort[0], &readset);
847 
848 		num = select (maxfd + 1, &readset, &writeset, &exceptset, NULL);
849 		if (num == -1) {
850 		    DEBUG_LOG ("Blocking select(%d) returns -1,errno is %d\n", sb->sockabort[0],errno);
851 		    fcntl (sb->s, F_SETFL, flags);
852 		   return -1;
853 		}
854 
855 		if (FD_ISSET (sb->sockabort[0], &readset) || FD_ISSET (sb->sockabort[0], &writeset)) {
856 		    /* reset sock abort pipe */
857 		    /* read from the pipe to reset it */
858 		    DEBUG_LOG ("select aborted from signal\n");
859 
860 		    clearsockabort (sb);
861 		    DEBUG_LOG ("Done read\n");
862 		    errno = EINTR;
863 		    done = 1;
864 		} else {
865 		    done = 0;
866 		}
867 	    } else if (errno == EINTR)
868 		done = 1;
869 	}
870     }
871     fcntl (sb->s, F_SETFL, flags);
872     return foo;
873 }
874 
875 
bsdlib_threadfunc(void * arg)876 static void *bsdlib_threadfunc (void *arg)
877 {
878     struct socketbase *sb = (struct socketbase *) arg;
879 
880     DEBUG_LOG ("THREAD_START\n");
881 
882     while (1) {
883 	uae_sem_wait (&sb->sem);
884 
885 	DEBUG_LOG ("Socket thread got action %d\n", sb->action);
886 
887 	switch (sb->action) {
888 	    case 0:       /* kill thread (CloseLibrary) */
889 
890 		DEBUG_LOG ("THREAD_END\n");
891 
892 		uae_sem_destroy (&sb->sem);
893 		return NULL;
894 
895 	    case 1:       /* Connect */
896 		sb->resultval = bsdthr_SendRecvAcceptConnect (bsdthr_Connect_2, sb);
897 		break;
898 
899 	    /* @@@ Should check (from|to)len so it's 16.. */
900 	    case 2:       /* Send[to] */
901 		sb->resultval = bsdthr_SendRecvAcceptConnect (bsdthr_Send_2, sb);
902 		break;
903 
904 	    case 3:       /* Recv[from] */
905 		sb->resultval = bsdthr_SendRecvAcceptConnect (bsdthr_Recv_2, sb);
906 		break;
907 
908 	    case 4: {     /* Gethostbyname */
909 		struct hostent *tmphostent = gethostbyname ((char *)get_real_address (sb->name));
910 
911 		if (tmphostent) {
912 		    copyHostent (tmphostent, sb);
913 		    bsdsocklib_setherrno (sb, 0);
914 		} else
915 		    SETHERRNO;
916 
917 		break;
918 	    }
919 
920 	    case 5:       /* WaitSelect */
921 		sb->resultval = bsdthr_WaitSelect (sb);
922 		break;
923 
924 	    case 6:       /* Accept */
925 		sb->resultval = bsdthr_SendRecvAcceptConnect (bsdthr_Accept_2, sb);
926 		break;
927 
928 	    case 7: {
929 		struct hostent *tmphostent = gethostbyaddr (get_real_address (sb->name), sb->a_addrlen, sb->flags);
930 
931 		if (tmphostent) {
932 		    copyHostent (tmphostent, sb);
933 		    bsdsocklib_setherrno (sb, 0);
934 		} else
935 		    SETHERRNO;
936 
937 		break;
938 	    }
939 	}
940 	SETERRNO;
941 	SETSIGNAL;
942     }
943     return NULL;        /* Just to keep GCC happy.. */
944 }
945 
946 
947 
948 
host_connect(TrapContext * context,SB,uae_u32 sd,uae_u32 name,uae_u32 namelen)949 void host_connect (TrapContext *context, SB, uae_u32 sd, uae_u32 name, uae_u32 namelen)
950 {
951     sb->s = getsock (sb, sd + 1);
952     if (sb->s == -1) {
953 		sb->resultval = -1;
954 		bsdsocklib_seterrno (sb, 9); /* EBADF */
955 		return;
956     }
957     sb->a_addr    = name;
958     sb->a_addrlen = namelen;
959     sb->action    = 1;
960 
961     uae_sem_post (&sb->sem);
962 
963     WAITSIGNAL;
964 }
965 
host_sendto(TrapContext * context,SB,uae_u32 sd,uae_u32 msg,uae_u32 len,uae_u32 flags,uae_u32 to,uae_u32 tolen)966 void host_sendto (TrapContext *context, SB, uae_u32 sd, uae_u32 msg, uae_u32 len, uae_u32 flags, uae_u32 to, uae_u32 tolen)
967 {
968     sb->s = getsock (sb, sd + 1);
969     if (sb->s == -1) {
970 		sb->resultval = -1;
971 		bsdsocklib_seterrno (sb, 9); /* EBADF */
972 		return;
973     }
974     sb->buf    = get_real_address (msg);
975     sb->len    = len;
976     sb->flags  = flags;
977     sb->to     = to;
978     sb->tolen  = tolen;
979     sb->action = 2;
980 
981     uae_sem_post (&sb->sem);
982 
983     WAITSIGNAL;
984 }
985 
host_recvfrom(TrapContext * context,SB,uae_u32 sd,uae_u32 msg,uae_u32 len,uae_u32 flags,uae_u32 addr,uae_u32 addrlen)986 void host_recvfrom (TrapContext *context, SB, uae_u32 sd, uae_u32 msg, uae_u32 len, uae_u32 flags, uae_u32 addr, uae_u32 addrlen)
987 {
988     int s = getsock (sb, sd + 1);
989 
990     DEBUG_LOG ("Recv[from](%lx, %d, %lx, %ld, %lx, %lx, %d)\n",
991 	       sb, sd, msg, len, flags, addr, addrlen);
992 
993     if (s == -1) {
994 		sb->resultval = -1;
995 		bsdsocklib_seterrno (sb, 9); /* EBADF */;
996 		return;
997     }
998 
999     sb->s      = s;
1000     sb->buf    = get_real_address (msg);
1001     sb->len    = len;
1002     sb->flags  = flags;
1003     sb->from   = addr;
1004     sb->fromlen= addrlen;
1005     sb->action = 3;
1006 
1007     uae_sem_post (&sb->sem);
1008 
1009     WAITSIGNAL;
1010 }
1011 
host_setsockopt(SB,uae_u32 sd,uae_u32 level,uae_u32 optname,uae_u32 optval,uae_u32 optlen)1012 void host_setsockopt (SB, uae_u32 sd, uae_u32 level, uae_u32 optname, uae_u32 optval, uae_u32 optlen)
1013 {
1014     int s = getsock (sb, sd + 1);
1015     int nativelevel = mapsockoptlevel (level);
1016     int nativeoptname = mapsockoptname(nativelevel, optname);
1017     void *buf;
1018     if (s == -1) {
1019 		sb->resultval = -1;
1020 		bsdsocklib_seterrno (sb, 9); /* EBADF */;
1021 		return;
1022     }
1023 
1024     if (optval) {
1025 		buf = malloc(optlen);
1026 		mapsockoptvalue(nativelevel, nativeoptname, optval, buf);
1027     } else {
1028 		buf = NULL;
1029     }
1030     sb->resultval  = setsockopt (s, nativelevel, nativeoptname, buf, optlen);
1031     xfree(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(%d,0x%lx,%d) -> ", 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(%d,0x%lx,%d) -> ", 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) %lx\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, %lx, %lx)\n", sb->s, name, namelen);
1206     sb->a_addr    = name;
1207     sb->a_addrlen = namelen;
1208     sb->action    = 6;
1209     sb->len       = sd;
1210 
1211     uae_sem_post (&sb->sem);
1212 
1213     WAITSIGNAL;
1214     DEBUG_LOG ("Accept returns %d\n", sb->resultval);
1215 }
1216 
host_socket(SB,int af,int type,int protocol)1217 int host_socket (SB, int af, int type, int protocol)
1218 {
1219     int sd;
1220     int s;
1221 
1222     DEBUG_LOG ("socket(%s,%s,%d) -> ",af == AF_INET ? "AF_INET" : "AF_other",
1223 	       type == SOCK_STREAM ? "SOCK_STREAM" : type == SOCK_DGRAM ?
1224 	       "SOCK_DGRAM " : "SOCK_RAW", protocol);
1225 
1226     if ((s = socket (af, type, protocol)) == -1)  {
1227 		SETERRNO;
1228 		DEBUG_LOG ("failed (%d)\n", sb->sb_errno);
1229 		return -1;
1230     } else {
1231 		int arg = 1;
1232 		sd = getsd (sb, s);
1233 		setsockopt (s, SOL_SOCKET, SO_REUSEADDR, &arg, sizeof(arg));
1234     }
1235 
1236     sb->ftable[sd-1] = SF_BLOCKING;
1237     DEBUG_LOG ("socket returns Amiga %d, NativeSide %d\n", sd - 1, s);
1238     return sd - 1;
1239 }
1240 
host_bind(SB,uae_u32 sd,uae_u32 name,uae_u32 namelen)1241 uae_u32 host_bind (SB, uae_u32 sd, uae_u32 name, uae_u32 namelen)
1242 {
1243     uae_u32 success = 0;
1244     struct sockaddr_in addr;
1245     int len = sizeof (struct sockaddr_in);
1246     int s;
1247 
1248     s = getsock (sb, sd + 1);
1249     if (s == -1) {
1250 		sb->resultval = -1;
1251 		bsdsocklib_seterrno (sb, 9); /* EBADF */
1252 		return -1;
1253     }
1254 
1255     DEBUG_LOG ("bind(%d[%d],0x%lx,%d) -> ", sd, s, name, namelen);
1256     copysockaddr_a2n (&addr, name, namelen);
1257     printSockAddr (&addr);
1258     if ((success = bind (s, (struct sockaddr *)&addr, len)) != 0) {
1259 		SETERRNO;
1260 		DEBUG_LOG ("failed (%d)\n",sb->sb_errno);
1261     } else {
1262 		DEBUG_LOG ("OK\n");
1263     }
1264     return success;
1265 }
1266 
host_listen(SB,uae_u32 sd,uae_u32 backlog)1267 uae_u32 host_listen (SB, uae_u32 sd, uae_u32 backlog)
1268 {
1269     int s;
1270     uae_u32 success = -1;
1271 
1272     DEBUG_LOG ("listen(%d,%d) -> ", sd, backlog);
1273     s = getsock (sb, sd + 1);
1274 
1275     if (s == -1) {
1276 		bsdsocklib_seterrno (sb, 9);
1277 		return -1;
1278     }
1279 
1280     if ((success = listen (s, backlog)) != 0) {
1281 		SETERRNO;
1282 		DEBUG_LOG ("failed (%d)\n", sb->sb_errno);
1283     } else {
1284 		DEBUG_LOG ("OK\n");
1285     }
1286     return success;
1287 }
1288 
host_getprotobyname(TrapContext * context,SB,uae_u32 name)1289 void host_getprotobyname (TrapContext *context, SB, uae_u32 name)
1290 {
1291     struct protoent *p = getprotobyname ((char *)get_real_address (name));
1292 
1293     DEBUG_LOG ("Getprotobyname(%s)=%lx\n", get_real_address (name), p);
1294 
1295     if (p == NULL) {
1296 		SETERRNO;
1297 		return;
1298     }
1299 
1300     copyProtoent (context, sb, p);
1301     BSDTRACE (("OK (%s, %d)\n", p->p_name, p->p_proto));
1302 }
1303 
host_getprotobynumber(TrapContext * context,SB,uae_u32 number)1304 void host_getprotobynumber (TrapContext *context, SB, uae_u32 number)
1305 {
1306     struct protoent *p = getprotobynumber(number);
1307     DEBUG_LOG("getprotobynumber(%d)=%lx\n", number, p);
1308 
1309     if (p == NULL) {
1310 		SETERRNO;
1311 		return;
1312     }
1313 
1314     copyProtoent (context, sb, p);
1315     BSDTRACE (("OK (%s, %d)\n", p->p_name, p->p_proto));
1316 }
1317 
host_getservbynameport(TrapContext * context,SB,uae_u32 name,uae_u32 proto,uae_u32 type)1318 void host_getservbynameport (TrapContext *context, SB, uae_u32 name, uae_u32 proto, uae_u32 type)
1319 {
1320     struct servent *s = (type) ?
1321 	getservbyport (name, (char *)get_real_address (proto)) :
1322 	getservbyname ((char *)get_real_address (name), (char *)get_real_address (proto));
1323     size_t size = 20;
1324     int numaliases = 0;
1325     uae_u32 aptr;
1326     int i;
1327 
1328     if (type) {
1329 		DEBUG_LOG("Getservbyport(%d, %s) = %lx\n", name, get_real_address (proto), s);
1330     } else {
1331 		DEBUG_LOG("Getservbyname(%s, %s) = %lx\n", get_real_address (name), get_real_address (proto), s);
1332     }
1333 
1334     if (s == NULL) {
1335 	SETERRNO;
1336 	return;
1337     }
1338 
1339     // compute total size of servent
1340     if (s->s_name != NULL)
1341 		size += strlen (s->s_name) + 1;
1342 
1343     if (s->s_proto != NULL)
1344 		size += strlen (s->s_proto) + 1;
1345 
1346     if (s->s_aliases != NULL)
1347 	while (s->s_aliases[numaliases])
1348 	    size += strlen (s->s_aliases[numaliases++]) + 5;
1349 
1350     if (sb->servent) {
1351 		uae_FreeMem (context, sb->servent, sb->serventsize, sb->sysbase);
1352     }
1353 
1354     sb->servent = uae_AllocMem (context, size, 0, sb->sysbase);
1355 
1356     if (!sb->servent) {
1357 		write_log ("BSDSOCK: WARNING - getservby%s() ran out of Amiga memory (couldn't allocate %d bytes)\n",type ? "port" : "name", size);
1358 		bsdsocklib_seterrno (sb, 12); // ENOMEM
1359 		return;
1360     }
1361 
1362     sb->serventsize = size;
1363 
1364     aptr = sb->servent + 20 + numaliases * 4;
1365 
1366     // transfer servent to Amiga memory
1367     put_long (sb->servent + 4, sb->servent + 16);
1368     put_long (sb->servent + 8, (unsigned short)htons (s->s_port));
1369 
1370     for (i = 0; i < numaliases; i++)
1371 	put_long (sb->servent + 16 + i * 4, addstr (&aptr, s->s_aliases[i]));
1372     put_long (sb->servent + 16 + numaliases * 4, 0);
1373     put_long (sb->servent, aptr);
1374     addstr (&aptr, s->s_name);
1375     put_long (sb->servent + 12, aptr);
1376     addstr (&aptr, s->s_proto);
1377 
1378     BSDTRACE (("OK (%s, %d)\n", s->s_name, (unsigned short)htons (s->s_port)));
1379     bsdsocklib_seterrno (sb,0);
1380 }
1381 
host_sbinit(TrapContext * context,SB)1382 int host_sbinit (TrapContext *context, SB)
1383 {
1384     if (pipe (sb->sockabort) < 0) {
1385 		return 0;
1386     }
1387 
1388     if (fcntl (sb->sockabort[0], F_SETFL, O_NONBLOCK) < 0) {
1389 	    write_log ("Set nonblock failed %d\n", errno);
1390     }
1391 
1392     if (uae_sem_init (&sb->sem, 0, 0)) {
1393 		write_log ("BSDSOCK: Failed to create semaphore.\n");
1394 		close (sb->sockabort[0]);
1395 		close (sb->sockabort[1]);
1396 		return 0;
1397     }
1398 
1399     /* Alloc hostent buffer */
1400     sb->hostent = uae_AllocMem (context, 1024, 0, sb->sysbase);
1401     sb->hostentsize = 1024;
1402 
1403     /* @@@ The thread should be PTHREAD_CREATE_DETACHED */
1404     if (uae_start_thread ("bsdsocket", bsdlib_threadfunc, (void *)sb, &sb->thread) == BAD_THREAD) {
1405 		write_log ("BSDSOCK: Failed to create thread.\n");
1406 		uae_sem_destroy (&sb->sem);
1407 		close (sb->sockabort[0]);
1408 		close (sb->sockabort[1]);
1409 		return 0;
1410     }
1411     return 1;
1412 }
1413 
host_sbcleanup(SB)1414 void host_sbcleanup (SB)
1415 {
1416     int i;
1417 
1418     uae_thread_id thread = sb->thread;
1419     close (sb->sockabort[0]);
1420     close (sb->sockabort[1]);
1421     for (i = 0; i < sb->dtablesize; i++) {
1422 		if (sb->dtable[i] != -1) {
1423 		    close(sb->dtable[i]);
1424 		}
1425     }
1426     sb->action = 0;
1427 
1428     uae_sem_post (&sb->sem); /* destroy happens on socket thread */
1429 
1430     /* We need to join with the socket thread to allow the thread to die
1431      * and clean up resources when the underlying thread layer is pthreads.
1432      * Ideally, this shouldn't be necessary, but, for example, when SDL uses
1433      * pthreads, it always creates joinable threads - and we can't do anything
1434      * about that. */
1435     uae_wait_thread (thread);
1436 }
1437 
host_sbreset(void)1438 void host_sbreset (void)
1439 {
1440     /* TODO */
1441 }
1442 
host_Inet_NtoA(TrapContext * context,SB,uae_u32 in)1443 uae_u32 host_Inet_NtoA (TrapContext *context, SB, uae_u32 in)
1444 {
1445     char *addr;
1446     struct in_addr ina;
1447     uae_u32 buf;
1448 
1449     *(uae_u32 *)&ina = htonl (in);
1450 
1451     BSDTRACE (("Inet_NtoA(%lx) -> ", in));
1452 
1453     if ((addr = inet_ntoa(ina)) != NULL) {
1454 		buf = m68k_areg (regs, 6) + offsetof (struct UAEBSDBase, scratchbuf);
1455 		strncpyha (buf, addr, SCRATCHBUFSIZE);
1456 		BSDTRACE (("%s\n", addr));
1457 		return buf;
1458     } else
1459 		SETERRNO;
1460 
1461     BSDTRACE (("failed (%d)\n", sb->sb_errno));
1462 
1463     return 0;
1464 }
1465 
host_inet_addr(uae_u32 cp)1466 uae_u32 host_inet_addr (uae_u32 cp)
1467 {
1468     uae_u32 addr;
1469     char *cp_rp;
1470 
1471     cp_rp = (char *)get_real_address (cp);
1472 
1473     addr = htonl (inet_addr (cp_rp));
1474 
1475     BSDTRACE (("inet_addr(%s) -> 0x%08lx\n", cp_rp, addr));
1476 
1477     return addr;
1478 }
1479 
host_shutdown(SB,uae_u32 sd,uae_u32 how)1480 uae_u32 host_shutdown (SB, uae_u32 sd, uae_u32 how)
1481 {
1482     SOCKET s;
1483 
1484     BSDTRACE (("shutdown(%d,%d) -> ", sd, how));
1485     s = getsock (sb, sd + 1);
1486 
1487     if (s != -1) {
1488 		if (shutdown (s, how)) {
1489 		    SETERRNO;
1490 		    BSDTRACE (("failed (%d)\n", sb->sb_errno));
1491 		} else {
1492 		    BSDTRACE (("OK\n"));
1493 		    return 0;
1494 		}
1495     }
1496 
1497     return -1;
1498 }
1499 
host_dup2socket(SB,int fd1,int fd2)1500 int host_dup2socket (SB, int fd1, int fd2) {
1501     int s1, s2;
1502 
1503     BSDTRACE (("dup2socket(%d,%d) -> ", fd1, fd2));
1504     fd1++;
1505 
1506     s1 = getsock (sb, fd1);
1507     if (s1 != -1) {
1508 		if (fd2 != -1) {
1509 		    if ((unsigned int) (fd2) >= (unsigned int) sb->dtablesize) {
1510 				BSDTRACE (("Bad file descriptor (%d)\n", fd2));
1511 				bsdsocklib_seterrno (sb, 9); /* EBADF */
1512 		    }
1513 		    fd2++;
1514 		    s2 = getsock (sb, fd2);
1515 		    if (s2 != -1) {
1516 				close (s2);
1517 		    }
1518 		    setsd (sb, fd2, dup (s1));
1519 		    BSDTRACE (("0(%d)\n", getsock (sb, fd2)));
1520 		    return 0;
1521 		} else {
1522 		    fd2 = getsd (sb, 1);
1523 			if (fd2 != -1) {
1524 			    setsd (sb, fd2, dup (s1));
1525 				BSDTRACE (("%d(%d)\n", fd2, getsock (sb, fd2)));
1526 			    return (fd2 - 1);
1527 			} else {
1528 				BSDTRACE(("-1\n"));
1529 				return -1;
1530 			}
1531 		}
1532     }
1533     BSDTRACE (("-1\n"));
1534     return -1;
1535 }
1536 
host_getsockopt(SB,uae_u32 sd,uae_u32 level,uae_u32 optname,uae_u32 optval,uae_u32 optlen)1537 uae_u32 host_getsockopt (SB, uae_u32 sd, uae_u32 level, uae_u32 optname,
1538 			 uae_u32 optval, uae_u32 optlen)
1539 {
1540     socklen_t len = 0;
1541     int r;
1542     int s;
1543     int nativelevel = mapsockoptlevel(level);
1544     int nativeoptname = mapsockoptname(nativelevel, optname);
1545     void *buf = NULL;
1546     s = getsock (sb, sd + 1);
1547 
1548     if (s == -1) {
1549 		bsdsocklib_seterrno(sb, 9); /* EBADF */
1550 		return -1;
1551     }
1552 
1553     if (optlen) {
1554 		len = get_long (optlen);
1555 		buf = malloc(len);
1556 		if (buf == NULL) {
1557 		   return -1;
1558 		}
1559     }
1560 
1561     r = getsockopt (s, nativelevel, nativeoptname,
1562 	optval ? buf : NULL, optlen ? &len : NULL);
1563 
1564     if (optlen)
1565 		put_long (optlen, len);
1566 
1567     SETERRNO;
1568     DEBUG_LOG ("getsockopt: sock AmigaSide %d NativeSide %d, level %d, 'name' %x(%d), len %d -> %d, %d\n",
1569 	sd, s, level, optname, nativeoptname, len, r, errno);
1570 
1571     if (optval) {
1572 		if (r == 0) {
1573 		    mapsockoptreturn(nativelevel, nativeoptname, optval, buf);
1574 		}
1575     }
1576 
1577     xfree(buf);
1578     return r;
1579 }
1580 
host_IoctlSocket(TrapContext * context,SB,uae_u32 sd,uae_u32 request,uae_u32 arg)1581 uae_u32 host_IoctlSocket (TrapContext *context, 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 
host_CloseSocket(TrapContext * context,SB,int sd)1642 int host_CloseSocket (TrapContext *context, 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 
host_closesocketquick(int s)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 
host_gethostname(uae_u32 name,uae_u32 namelen)1675 uae_u32 host_gethostname (uae_u32 name, uae_u32 namelen)
1676 {
1677     return gethostname ((char *)get_real_address (name), namelen);
1678 }
1679 
init_socket_layer(void)1680 int init_socket_layer(void)
1681 {
1682     if (uae_sem_init(&sem_queue, 0, 1) < 0) {
1683 		DEBUG_LOG("Can't create sem %d\n", errno);
1684 		return 0;
1685     }
1686 
1687     return 1;
1688 }
1689 
clearsockabort(SB)1690 void clearsockabort (SB)
1691 {
1692     int chr;
1693     int num;
1694 
1695     while ((num = read (sb->sockabort[0], &chr, sizeof(chr))) >= 0) {
1696 		DEBUG_LOG ("Sockabort got %d bytes\n", num);
1697 		;
1698     }
1699 }
1700 
sockabort(SB)1701 void sockabort (SB)
1702 {
1703     int chr = 1;
1704     DEBUG_LOG ("Sock abort!!\n");
1705     if (!write (sb->sockabort[1], &chr, sizeof (chr)))
1706 		sb->sockabort[1] = 1; // Use the crowbar...
1707 }
1708 
locksigqueue(void)1709 void locksigqueue (void)
1710 {
1711     uae_sem_wait(&sem_queue);
1712 }
1713 
unlocksigqueue(void)1714 void unlocksigqueue (void)
1715 {
1716     uae_sem_post(&sem_queue);
1717 }
1718 #endif
1719