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