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