Check for SYS/GL during library init. Reason is that
[AROS.git] / workbench / network / stacks / AROSTCP / bsdsocket / api / amiga_generic.c
blobab8dfbe273948714da1f19a7b64d65bc5fdad2dc
1 /*
2 * Copyright (C) 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>
3 * Helsinki University of Technology, Finland.
4 * All rights reserved.
5 * Copyright (C) 2005 - 2007 The AROS Dev Team
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
19 * MA 02111-1307, USA.
23 #include <conf.h>
25 #include <aros/asmcall.h>
26 #include <aros/libcall.h>
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/socketvar.h>
31 #include <sys/kernel.h>
32 #include <sys/ioctl.h>
33 #include <sys/protosw.h>
34 #include <sys/malloc.h>
35 #include <sys/synch.h>
37 #include <sys/time.h>
38 #include <sys/errno.h>
40 #include <sys/socket.h>
41 #include <net/route.h>
43 #include <kern/amiga_includes.h>
45 #include <api/amiga_api.h>
46 #include <api/amiga_libcallentry.h>
47 #include <api/allocdatabuffer.h>
49 #include <api/apicalls.h>
51 #include <net/if_protos.h>
53 #include <bsdsocket/socketbasetags.h>
55 #include <kern/uipc_domain_protos.h>
56 #include <kern/uipc_socket_protos.h>
57 #include <kern/uipc_socket2_protos.h>
59 /* Local protos */
60 static int selscan(struct SocketBase *p,
61 fd_set *in, fd_set *ou, fd_set *ex, fd_mask *obits,
62 int nfd, int *retval, int *selitemcount_p);
63 void selenter(struct SocketBase * p, struct newselitem ** hdr);
64 static void unselect(register struct newselbuf * sb);
65 void selwakeup(struct newselitem **hdr);
66 static int soo_select(struct socket *so, int which, struct SocketBase *p);
67 static int countSockets(struct SocketBase * libPtr, struct socket * so);
70 * itimerfix copied from bsdss/server/kern/kern_time.c. since fields
71 * in struct timeval in amiga are ULONGs, values less than zero need
72 * not be checked. the second check, timeval less than resolution of
73 * the clock is not needed in amiga...hmm, is removed also.
75 static inline int itimerfix(struct timeval *tv)
77 if (tv->tv_sec > 100000000 || tv->tv_usec >= 1000000)
78 return (EINVAL);
79 /* if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick)
80 tv->tv_usec = tick;
81 */ return (0);
85 * ffs() copied directly from bsdss/server/kern/subr_xxx.c
87 static inline int ffs(int mask)
89 register int bit;
91 if (!mask)
92 return(0);
93 for (bit = 1;; ++bit) {
94 if (mask&0x01)
95 return(bit);
96 mask >>= 1;
98 /* NOT REACHED */
103 * Ioctl system call
106 LONG __IoctlSocket(LONG fdes, ULONG cmd, caddr_t data, struct SocketBase *libPtr)
108 register int error;
109 register u_int size;
110 struct socket *so;
113 * Note: Syscall semaphore is essential here if two processes can access
114 * the same socket. (can it be changed to spl_? ?)
116 CHECK_TASK();
117 DSYSCALLS(log(LOG_DEBUG,"IoctlSocket(%ld, 0x%08lx, 0x%08lx) called", fdes, cmd, *(ULONG *)data);)
118 ObtainSyscallSemaphore(libPtr);
120 if (error = getSock(libPtr, fdes, &so))
121 goto Return;
124 * Interpret high order word to get size of the user data area
126 size = IOCPARM_LEN(cmd);
127 if (size == 0 || size > IOCPARM_MAX) {
128 error = ENOTTY;
129 goto Return;
131 if (!(cmd & IOC_IN) && cmd & IOC_OUT)
133 * Zero the buffer so the user always
134 * gets back something deterministic.
136 bzero(data, size);
138 switch (cmd) {
139 case FIOCLEX:
140 case FIONCLEX: /* should this return error ???? */
141 goto Return;
143 case FIOSETOWN:
144 case SIOCSPGRP:
146 * data is a struct Task **, find corresponding SocketBase * and set owner
148 so->so_pgid = FindSocketBase(*(struct Task **)data);
149 goto Return;
151 case FIOGETOWN:
152 case SIOCGPGRP:
153 if (so->so_pgid)
154 *(struct Task **)data = so->so_pgid->thisTask;
155 else
156 *(struct Task **)data = NULL;
157 goto Return;
159 case FIONBIO:
160 if (*(int *)data)
161 so->so_state |= SS_NBIO;
162 else
163 so->so_state &= ~SS_NBIO;
164 goto Return;
166 case FIOASYNC:
167 if (*(int *)data) {
168 so->so_state |= SS_ASYNC;
169 so->so_rcv.sb_flags |= SB_ASYNC;
170 so->so_snd.sb_flags |= SB_ASYNC;
171 } else {
172 so->so_state &= ~SS_ASYNC;
173 so->so_rcv.sb_flags &= ~SB_ASYNC;
174 so->so_snd.sb_flags &= ~SB_ASYNC;
176 goto Return;
178 case FIONREAD:
179 *(int *)data = so->so_rcv.sb_cc;
180 goto Return;
182 case SIOCATMARK:
183 *(int *)data = (so->so_state&SS_RCVATMARK) != 0;
184 goto Return;
188 * Interface/routing/protocol specific ioctls:
189 * interface and routing ioctls should have a
190 * different entry since a socket's unnecessary -- not really,
191 * ifioctl needs the socket (?)
193 if ((IOCGROUP(cmd) & 0XDF) == 'I') {
194 error = (ifioctl(so, cmd, data));
195 goto Return;
197 if (IOCGROUP(cmd) == 'r') {
198 error = (rtioctl(cmd, data));
199 goto Return;
201 error = ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
202 (struct mbuf *)(long)cmd, (struct mbuf *)data, (struct mbuf *)0));
204 Return:
205 ReleaseSyscallSemaphore(libPtr);
206 DOPTERR(if (error) log(LOG_ERR,"IoctlSocket(): error %ld on command 0x%08lx", error, cmd);)
207 API_STD_RETURN(error, 0);
210 AROS_LH3(LONG, IoctlSocket,
211 AROS_LHA(LONG, fdes, D0),
212 AROS_LHA(ULONG, cmd, D1),
213 AROS_LHA(caddr_t, data, A0),
214 struct SocketBase *, libPtr, 19, UL)
216 AROS_LIBFUNC_INIT
217 return __IoctlSocket(fdes, cmd, data, libPtr);
218 AROS_LIBFUNC_EXIT
224 * Semaphore to prevent select buffers from simultaneous modifications
226 struct SignalSemaphore select_semaphore = { };
228 struct newselbuf {
229 int s_state;
230 #define SB_CLEAR 0 /* wait condition cleared */
231 #define SB_WILLWAIT 1 /* will wait if not cleared */
232 #define SB_WAITING 2 /* waiting - wake up */
233 int s_count;
234 struct newselitem {
235 struct newselitem * si_next; /* next selbuf in item chain */
236 struct newselitem ** si_prev; /* back pointer */
237 struct newselbuf * si_selbuf; /* 'thread' waiting */
238 } s_item[0]; /* selitems are allocated at select when right
239 number of descriptors are known */
242 void select_init(void)
244 InitSemaphore(&select_semaphore);
248 * symbolic names FREAD and FWRITE aren'n needed anywhere else if only
249 * socket descriptors are in use.
251 #define FREAD 0x1
252 #define FWRITE 0x2
255 * Select(), selscan(), selenter(), selwakeup() and unselect() are taken from
256 * ../server/kern/sys_generic.h in bsdss distribution. soo_select() is
257 * taken from ../server/kern/sys_socket.h, same distribution.
261 * Althrough the fd_set is used as the type of the masks, the size
262 * of the fd_set is not fixed, and is indeed calculated from nfds.
264 LONG __WaitSelect(ULONG nfds, fd_set *readfds, fd_set *writefds, fd_set *exeptfds,
265 struct timeval *timeout, ULONG *sigmp, struct SocketBase *libPtr)
267 fd_mask * obits;
268 u_int obitsize; /* in bytes */
269 int error, retval;
270 int selitemcount;
271 ULONG sigmask = sigmp ? *sigmp : 0;
273 struct newselbuf * newselbuf;
275 CHECK_TASK();
277 if (nfds > libPtr->dTableSize)
278 nfds = libPtr->dTableSize; /* forgiving; slightly wrong */
280 if (timeout && itimerfix(timeout)) {
281 error = EINVAL;
282 goto Return;
286 * We use selscan twice each time around the loop.
287 * The first time, we actually put ourself on device chains.
288 * The second time, we make a "fast" check for a true condition.
289 * selenter does nothing and we don't need to use unselect.
290 * We only need to zero obits once because if selscan
291 * turns on a bit it returns non-zero and we stop.
293 * The "fast" scan is also done before the loop is ever entered.
295 * We need to allocate some temporary buffers for output bit masks
296 * and, later for selitems. The amount of selitems needed is
297 * calculated during the first selscan -- when selenter does nothing
300 obitsize = howmany(nfds, NFDBITS) * sizeof (fd_mask);
301 if (allocDataBuffer(&libPtr->selitems, 3 * obitsize) == FALSE) {
302 error = ENOMEM;
303 goto Return;
305 obits = (fd_mask *)libPtr->selitems.db_Addr;
307 aligned_bzero((caddr_t)obits, 3 * obitsize);
310 * We make a first pass to check for conditions
311 * which are already true. Clearing uu_sb
312 * will keep selenter from doing anything.
314 libPtr->p_sb = 0;
315 error = selscan(libPtr, readfds, writefds, exeptfds,
316 obits, nfds, &retval, &selitemcount);
319 * Check if the 'real' loop should be entered.
321 if (!error && !retval) {
322 if (timeout == NULL || timeout->tv_secs != 0L || timeout->tv_micro != 0L) {
325 * Send timeout if there is any.
327 if (timeout)
328 tsleep_send_timeout(libPtr, timeout);
331 * Now, make sure there is room for all the selitems...
333 if (allocDataBuffer(&libPtr->selitems,
334 3 * obitsize + sizeof (struct newselbuf) +
335 selitemcount * sizeof(struct newselitem)) == FALSE) {
336 error = ENOMEM;
337 goto Return;
340 * We need to clear obits again _if_ the memory area for it has
341 * changed.
343 if ((fd_mask *)libPtr->selitems.db_Addr != obits) {
344 obits = (fd_mask *)libPtr->selitems.db_Addr;
345 aligned_bzero((caddr_t)obits, 3 * obitsize);
347 newselbuf = (struct newselbuf *)((caddr_t)obits + (3 * obitsize));
349 while (TRUE) {
352 * Now we get serious about blocking.
353 * selenter will put us on device chains.
354 * We don't need select_lock here because
355 * no other thread can get at selbuf yet.
358 newselbuf->s_state = SB_WILLWAIT;
359 newselbuf->s_count = 0;
360 libPtr->p_sb = newselbuf;
362 error = selscan(libPtr, readfds, writefds, exeptfds,
363 obits, nfds, &retval, &selitemcount);
364 if (error || retval) {
365 ObtainSemaphore(&select_semaphore);
366 unselect(newselbuf);
367 ReleaseSemaphore(&select_semaphore);
368 break;
372 * If the state is already SB_CLEAR, then a selwakeup
373 * slipped in after the selscan.
376 ObtainSemaphore(&select_semaphore);
377 if (newselbuf->s_state == SB_CLEAR) {
378 unselect(newselbuf);
379 ReleaseSemaphore(&select_semaphore);
381 else {
382 newselbuf->s_state = SB_WAITING;
383 tsleep_enter(libPtr, (caddr_t)newselbuf, "select");
384 ReleaseSemaphore(&select_semaphore);
385 /* ReleaseSemaphore(&syscall_semaphore); don't have this */
387 error = tsleep_main(libPtr, sigmask);
389 /* ObtainSemaphore(&syscall_semaphore); see above */
390 ObtainSemaphore(&select_semaphore);
391 unselect(newselbuf);
392 ReleaseSemaphore(&select_semaphore);
394 if (error != 0) {
396 * The break at the end of this block means that selscan will NOT
397 * be done after this. This provides faster response to the
398 * used defined signals.
400 * Note also that the semantics of the tsleep_abort_timeout() has
401 * changed; it is now accepted to call it even after the timeout
402 * has expired.
404 if (error == ERESTART || error == EWOULDBLOCK)
405 error = 0;
407 break; /* do not scan now */
412 * Scan for true conditions. Clearing uu_sb
413 * will keep selenter from doing anything.
415 libPtr->p_sb = 0;
416 error = selscan(libPtr, readfds, writefds, exeptfds,
417 obits, nfds, &retval, &selitemcount);
418 if (error || retval)
419 break;
420 } /* while (TRUE) */
422 if (timeout) /* abort the timeout if any */
423 tsleep_abort_timeout(libPtr, timeout);
427 Return:
428 libPtr->p_sb = 0;
430 #define putbits(name, x) \
431 if (name) { \
432 aligned_bcopy(((caddr_t)obits) + (x * obitsize), \
433 (caddr_t)name, obitsize); \
436 if (error == 0) {
437 if (sigmp)
438 *sigmp &= SetSignal(0L, sigmask);
439 /* ULONG sigs = SetSignal(0L, sigmask);
440 if (sigmp)
441 *sigmp &= sigs;
442 SetSignal(0L,libPtr->sigIntrMask);*/
444 putbits(readfds, 0);
445 putbits(writefds, 1);
446 putbits(exeptfds, 2);
448 #undef putbits
450 API_STD_RETURN(error, retval);
453 AROS_LH6(LONG, WaitSelect,
454 AROS_LHA(ULONG, nfds, D0),
455 AROS_LHA(fd_set *, readfds, A0),
456 AROS_LHA(fd_set *, writefds, A1),
457 AROS_LHA(fd_set *, exeptfds, A2),
458 AROS_LHA(struct timeval *, timeout, A3),
459 AROS_LHA(ULONG *, sigmp, D1),
460 struct SocketBase *, libPtr, 21, UL)
462 AROS_LIBFUNC_INIT
463 DSYSCALLS(log(LOG_DEBUG,"WaitSelect(%lu, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx) called", nfds, readfds, writefds, exeptfds, timeout, sigmp);)
464 return __WaitSelect(nfds, readfds, writefds, exeptfds, timeout, sigmp, libPtr);
465 AROS_LIBFUNC_EXIT
468 AROS_LH1(LONG, GetSocketEvents,
469 AROS_LHA(ULONG *,eventsp, A0),
470 struct SocketBase *, libPtr, 50, UL)
472 AROS_LIBFUNC_INIT
473 struct soevent *se;
474 struct socket *so;
475 int i;
477 ObtainSemaphore(&libPtr->EventLock);
478 se = (struct soevent *)RemHead((struct List *)&libPtr->EventList);
479 ReleaseSemaphore(&libPtr->EventLock);
480 if (se) {
481 *eventsp = se->events;
482 DEVENTS(log(LOG_DEBUG,"GetSocketEvents(): events 0x%08lx for socket 0x%08lx libPtr = 0x%08lx", se->events, se->socket, libPtr);)
483 so = se->socket;
484 bsd_free(se, NULL);
485 for (i = 0; i < libPtr->dTableSize; i++)
486 if (libPtr->dTable[i] == so)
487 return i;
488 DEVENTS(log(LOG_CRIT,"GetSocketEvents(): unreferenced socket 0x%08lx libPtr = 0x%08lx", so, libPtr);)
490 DEVENTS(else log (LOG_DEBUG,"GetSocketEvents(): no events pending libPtr = 0x%08lx", libPtr);)
491 return -1;
492 AROS_LIBFUNC_EXIT
496 * Althrough the fd_set is used as the type of the masks, the size
497 * of the fd_set is not fixed, and is indeed calculated from nfd.
499 static int
500 selscan(struct SocketBase *p,
501 fd_set * in,
502 fd_set * ou,
503 fd_set * ex,
504 fd_mask * obits,
505 int nfd,
506 int * retval,
507 int * selitemcount_p)
509 register int which, i, j, selitemcount = 0;
510 register fd_mask bits;
511 register fd_set * cbits;
512 struct socket *so;
513 int flag;
514 int n = 0;
515 int error = 0;
516 u_int obitsize = howmany(nfd, NFDBITS); /* in longwords */
518 for (which = 0; which < 3; which++) {
519 switch (which) {
521 case 0:
522 flag = FREAD;
523 cbits = in;
524 break;
525 case 1:
526 flag = FWRITE;
527 cbits = ou;
528 break;
529 case 2:
530 flag = 0;
531 cbits = ex;
532 break;
534 if (cbits != NULL) {
535 for (i = 0; i < nfd; i += NFDBITS) {
536 bits = cbits->fds_bits[i/NFDBITS];
537 while ((j = ffs(bits)) && i + --j < nfd) {
538 bits &= ~(1 << j);
539 so = p->dTable[i + j];
540 if (so == NULL) {
541 error = EBADF;
542 break;
544 selitemcount++;
545 if (soo_select(so, flag, p)) {
546 FD_SET(i + j, (fd_set *)
547 (obits + (which * obitsize)));
548 n++;
554 *retval = n;
555 *selitemcount_p = selitemcount;
556 return (error);
560 * Add a select event to the current select buffer.
561 * Chain all select buffers that are waiting for
562 * the same event.
564 void selenter(struct SocketBase * p,
565 struct newselitem ** hdr)
567 register struct newselbuf *sb = p->p_sb;
569 if (sb) {
570 register struct newselitem **sip = hdr;
571 register struct newselitem *si;
573 ObtainSemaphore(&select_semaphore);
575 /* initialize this select item */
576 si = &sb->s_item[sb->s_count++];
577 si->si_selbuf = sb;
579 /* and add it to the device chain */
580 if (si->si_next = *sip)
581 si->si_next->si_prev = &si->si_next;
582 *(si->si_prev = sip) = si;
584 ReleaseSemaphore(&select_semaphore);
588 static void
589 unselect(register struct newselbuf * sb)
591 int i;
594 * We unchain the select items.
595 * This assumes select_lock is held.
598 for (i = 0; i < sb->s_count; i++) {
599 register struct newselitem *si = &sb->s_item[i];
602 * We remove this item from its device chain.
603 * If selwakeup already got to it, then this is a nop.
606 *si->si_prev = si->si_next;
611 * Wakeup all threads waiting on the same select event.
612 * Do not clear the other select events that each thread
613 * is waiting on; thread will do that itself.
615 void selwakeup(struct newselitem **hdr)
617 register struct newselitem **sip;
618 register struct newselitem *si;
620 ObtainSemaphore(&select_semaphore);
622 for (sip = hdr; (si = *sip) != 0; sip = &si->si_next) {
623 register struct newselbuf *sb;
624 int old_state;
626 /* for when unselect tries to dequeue this item */
627 si->si_prev = &si->si_next;
629 /* check for wakeup */
630 sb = si->si_selbuf;
631 old_state = sb->s_state;
632 sb->s_state = SB_CLEAR;
633 if (old_state == SB_WAITING)
634 wakeup((caddr_t)sb);
637 /* clear the device chain */
638 *(struct newselitem **)hdr = 0;
639 ReleaseSemaphore(&select_semaphore);
642 static int
643 soo_select(struct socket *so,
644 int which,
645 struct SocketBase *p)
647 register spl_t s = splnet();
649 switch (which) {
651 case FREAD:
652 if (soreadable(so)) {
653 splx(s);
654 return (1);
656 sbselqueue(&so->so_rcv, p);
657 break;
659 case FWRITE:
660 if (sowriteable(so)) {
661 splx(s);
662 return (1);
664 sbselqueue(&so->so_snd, p);
665 break;
667 case 0:
668 if (so->so_oobmark ||
669 (so->so_state & SS_RCVATMARK)) {
670 splx(s);
671 return (1);
673 sbselqueue(&so->so_rcv, p);
674 break;
676 splx(s);
677 return (0);
681 * countSockets() counts how many references ONE task (SocketBase) have to a
682 * socket
685 static int
686 countSockets(struct SocketBase * libPtr, struct socket * so)
688 int i, count = 0;
690 for (i = 0; i < libPtr->dTableSize; i++)
691 if (libPtr->dTable[i] == so)
692 count++;
694 return count;
697 LONG __CloseSocket(LONG fd, struct SocketBase *libPtr)
699 register int error;
700 struct socket *so;
701 struct soevent *se;
703 CHECK_TASK();
704 ObtainSyscallSemaphore(libPtr);
707 * Check from used sockets bitmask if this socket is in use
709 if (! FD_ISSET(fd, (fd_set *)(libPtr->dTable + libPtr->dTableSize))) {
710 error = EBADF;
711 goto Return;
715 * If the link library cannot free the fd, then we cannot do it either.
717 if (libPtr->fdCallback)
718 if (error = AROS_UFC2(int, libPtr->fdCallback,
719 AROS_UFCA(int, fd, D0),
720 AROS_UFCA(int, FDCB_FREE, D1)))
721 goto Return;
723 FD_CLR(fd, (fd_set *)(libPtr->dTable + libPtr->dTableSize));
725 if (error = getSock(libPtr, fd, &so)) {
726 // error = ENOTSOCK; /* well, bit set, but socket == NULL */
727 error = 0; /* ignore silently */
728 goto Return;
730 if (so->so_pgid == libPtr && countSockets(libPtr, so) == 1)
731 so->so_pgid = NULL; /* not ours any more */
734 * Decrease the reference count of a socket (AmiTCP addition) and return if
735 * not zero.
737 if (--so->so_refcnt <= 0) {
738 error = soclose(so);
739 /* Remove all events associated with this socket */
740 ObtainSemaphore(&libPtr->EventLock);
741 for (se = (struct soevent *)libPtr->EventList.mlh_Head; se->node.mln_Succ; se = (struct soevent *)se->node.mln_Succ)
743 if (se->socket == so) {
744 Remove((struct Node *)se);
745 bsd_free(se, NULL);
748 ReleaseSemaphore(&libPtr->EventLock);
752 * now clear socket from descriptor table. Socket usage bitmask has been
753 * cleared earlier
755 libPtr->dTable[fd] = NULL;
757 Return:
758 ReleaseSyscallSemaphore(libPtr);
759 API_STD_RETURN(error, 0);
762 AROS_LH1(LONG, CloseSocket,
763 AROS_LHA(LONG, fd, D0),
764 struct SocketBase *, libPtr,20, UL)
766 AROS_LIBFUNC_INIT
767 DSYSCALLS(log(LOG_DEBUG,"CloseSocket(%ld) called", fd);)
768 return __CloseSocket(fd, libPtr);
769 AROS_LIBFUNC_EXIT
772 struct SocketNode {
773 struct MinNode sn_Node;
774 LONG sn_Id;
775 struct socket * sn_Socket;
779 * checkId() checks that there are no released sockets w/ given id.
780 * used from function makeId().
783 static LONG checkId(int id)
785 struct Node * sn;
787 Forbid();
788 for (sn = releasedSocketList.lh_Head; sn->ln_Succ; sn = sn->ln_Succ)
789 if (((struct SocketNode *)sn)->sn_Id == id) {
790 Permit();
791 return EINVAL;
793 Permit();
794 return 0;
797 #define FIRSTUNIQUEID 65536
800 * makeId() gets next unique id for socket to be released if *id is -1
801 * otherwise calls checkId for given *id.
802 * used from functions ReleaseSocket() and ReleaseCopyOfSocket().
804 static LONG makeId(LONG id)
806 static LONG uniqueId = FIRSTUNIQUEID;
808 if (id == -1) {
809 do {
810 uniqueId += sizeof (void *);
811 if (uniqueId < 0)
812 uniqueId = FIRSTUNIQUEID;
813 } while (checkId(uniqueId) != 0);
815 return uniqueId;
817 else {
818 if (checkId(id) == 0)
819 return id;
820 else
821 return -1; /* error */
825 /*LONG SAVEDS ReleaseSocket(
826 REG(d0, LONG fd),
827 REG(d1, LONG id),
828 REG(a6, struct SocketBase *libPtr))*/
829 AROS_LH2(LONG, ReleaseSocket,
830 AROS_LHA(LONG, fd, D0),
831 AROS_LHA(LONG, id, D1),
832 struct SocketBase *,libPtr, 25, UL)
834 AROS_LIBFUNC_INIT
835 struct SocketNode *sn;
836 struct socket *so;
837 int error = 0;
839 CHECK_TASK();
840 DSYSCALLS(log(LOG_DEBUG,"ReleaseSocket(%ld, %ld) called", fd, id);)
841 if ((ULONG)id >= FIRSTUNIQUEID && (id = makeId(id)) == -1) {
842 error = EINVAL;
843 goto Return;
846 if ((error = getSock(libPtr, fd, &so)) != 0)
847 goto Return;
849 if ((sn = AllocMem(sizeof (struct SocketNode), MEMF_PUBLIC)) == NULL) {
850 error = ENOMEM;
851 goto Return;
854 * Tell the link library that the fd is free
856 if (libPtr->fdCallback)
857 if (error = AROS_UFC2(int, libPtr->fdCallback,
858 AROS_UFCA(int, fd, D0),
859 AROS_UFCA(int, FDCB_FREE, D1)))
861 FreeMem(sn, sizeof (struct SocketNode));
862 goto Return;
865 /*if (so->so_pgid == libPtr && countSockets(libPtr, so) == 1)
866 so->so_pgid = NULL;*/ /* not ours any more */
867 sn->sn_Id = id;
868 sn->sn_Socket = so;
869 libPtr->dTable[fd] = NULL;
870 FD_CLR(fd, (fd_set *)(libPtr->dTable + libPtr->dTableSize));
872 Forbid();
873 AddTail(&releasedSocketList, (struct Node *)sn);
874 Permit();
876 Return: API_STD_RETURN(error, id);
877 AROS_LIBFUNC_EXIT
880 /*LONG SAVEDS ReleaseCopyOfSocket(
881 REG(d0, LONG fd),
882 REG(d1, LONG id),
883 REG(a6, struct SocketBase *libPtr))*/
884 AROS_LH2(LONG, ReleaseCopyOfSocket,
885 AROS_LHA(LONG, fd, D0),
886 AROS_LHA(LONG, id, D1),
887 struct SocketBase *, libPtr, 26, UL)
889 AROS_LIBFUNC_INIT
890 struct SocketNode *sn;
891 struct socket *so;
892 int error = 0;
894 CHECK_TASK();
895 DSYSCALLS(log(LOG_DEBUG,"ReleaseCopyOfSocket(%ld, %ld) called", fd, id);)
896 if ((ULONG)id >= FIRSTUNIQUEID && (id = makeId(id)) == -1) {
897 error = EINVAL;
898 goto Return;
901 if ((error = getSock(libPtr, fd, &so)) != 0)
902 goto Return;
904 if ((sn = AllocMem(sizeof (struct SocketNode), MEMF_PUBLIC)) == NULL) {
905 error = ENOMEM;
906 goto Return;
908 /* so_pgid left intact */
909 sn->sn_Id = id;
910 sn->sn_Socket = so;
911 so->so_refcnt++;
912 Forbid();
913 AddTail(&releasedSocketList, (struct Node *)sn);
914 Permit();
916 Return: API_STD_RETURN(error, id);
917 AROS_LIBFUNC_EXIT
920 /*LONG SAVEDS ObtainSocket(
921 REG(d0, LONG id),
922 REG(d1, LONG domain),
923 REG(d2, LONG type),
924 REG(d3, LONG protocol),
925 REG(a6, struct SocketBase *libPtr))*/
926 AROS_LH4(LONG, ObtainSocket,
927 AROS_LHA(LONG, id, D0),
928 AROS_LHA(LONG, domain, D1),
929 AROS_LHA(LONG, type, D2),
930 AROS_LHA(LONG, protocol, D3),
931 struct SocketBase *, libPtr, 24, UL)
933 AROS_LIBFUNC_INIT
934 struct protosw *prp;
935 struct Node * sn;
936 int error = 0;
937 LONG fd;
939 CHECK_TASK();
940 DSYSCALLS(log(LOG_DEBUG,"ObtainSocket(%ld, %ld, %ld, %ld) called", id, domain, type, protocol);)
941 if (domain == 0) {
942 if (id < FIRSTUNIQUEID) {
943 error = EPFNOSUPPORT;
944 goto Return;
947 else {
948 if (protocol)
949 prp = pffindproto(domain, protocol, type);
950 else
951 prp = pffindtype(domain, type);
952 if (prp == 0)
953 error = EPROTONOSUPPORT;
954 if (prp->pr_type != type)
955 error = EPROTOTYPE;
956 if (error)
957 goto Return;
960 if ((error = sdFind(libPtr, &fd)) != 0)
961 goto Return;
964 * Tell the link library about the new fd
966 if (libPtr->fdCallback)
967 if (error = AROS_UFC2(int, libPtr->fdCallback,
968 AROS_UFCA(int, fd, D0),
969 AROS_UFCA(int, FDCB_ALLOC, D1)))
970 goto Return;
972 Forbid();
973 for (sn = releasedSocketList.lh_Head; sn->ln_Succ; sn = sn->ln_Succ)
974 if (((struct SocketNode *)sn)->sn_Id == id) {
975 if (prp != ((struct SocketNode *)sn)->sn_Socket->so_proto)
976 continue;
977 Remove(sn);
978 Permit();
979 libPtr->dTable[fd] = ((struct SocketNode *)sn)->sn_Socket;
980 // ((struct SocketNode *)sn)->sn_Socket->so_pgid = libPtr;
981 FD_SET(fd, (fd_set *)(libPtr->dTable + libPtr->dTableSize));
982 FreeMem(sn, sizeof (struct SocketNode));
983 goto Return;
985 /* here if sdFind succeeded but search of socket failed */
986 Permit();
989 * Free the just allocated fd
991 if (libPtr->fdCallback)
992 AROS_UFC2(int, libPtr->fdCallback,
993 AROS_UFCA(int, fd, D0),
994 AROS_UFCA(int, FDCB_FREE, D1));
996 error = EWOULDBLOCK;
998 Return: API_STD_RETURN(error, fd);
999 AROS_LIBFUNC_EXIT
1002 /*LONG SAVEDS Dup2Socket(
1003 REG(d0, LONG fd1),
1004 REG(d1, LONG fd2),
1005 REG(a6, struct SocketBase *libPtr))*/
1006 AROS_LH2(LONG, Dup2Socket,
1007 AROS_LHA(LONG, fd1, D0),
1008 AROS_LHA(LONG, fd2, D1),
1009 struct SocketBase *, libPtr, 44, UL)
1011 AROS_LIBFUNC_INIT
1012 LONG newfd;
1013 int error = 0;
1014 struct socket *so;
1016 CHECK_TASK();
1017 DSYSCALLS(log(LOG_DEBUG,"Dup2Socket(%ld, %ld) called", fd1, fd2);)
1018 ObtainSyscallSemaphore(libPtr); /*many tasks may have access to the socket */
1020 if (fd1 == -1)
1021 so = NULL;
1022 else if ((error = getSock(libPtr, fd1, &so)))
1023 goto Return;
1025 if (fd2 == -1)
1026 if ((error = sdFind(libPtr, &newfd)))
1027 goto Return;
1028 else
1029 fd2 = newfd;
1030 else {
1031 if ((ULONG)fd2 >= libPtr->dTableSize) {
1032 error = EBADF;
1033 goto Return;
1035 if (libPtr->dTable[fd2] != NULL)
1036 __CloseSocket(fd2, libPtr);
1038 * Check if the fd is free on the link library
1040 if (libPtr->fdCallback)
1041 if (error = AROS_UFC2(int, libPtr->fdCallback,
1042 AROS_UFCA(int, fd2, D0),
1043 AROS_UFCA(int, FDCB_CHECK, D1)))
1044 goto Return;
1048 * Tell the link library about the new fd
1050 if (libPtr->fdCallback)
1051 if (error = AROS_UFC2(int, libPtr->fdCallback,
1052 AROS_UFCA(int, fd2, D0),
1053 AROS_UFCA(int, FDCB_ALLOC, D1)))
1054 goto Return;
1056 FD_SET(fd2, (fd_set *)(libPtr->dTable + libPtr->dTableSize));
1058 if (so != NULL) {
1059 so->so_refcnt++;
1060 libPtr->dTable[fd2] = so;
1063 Return:
1064 ReleaseSyscallSemaphore(libPtr);
1065 API_STD_RETURN(error, fd2);
1066 AROS_LIBFUNC_EXIT