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