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