2 * Copyright (C) 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>
3 * Helsinki University of Technology, Finland.
5 * Copyright (C) 2005 - 2010 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,
24 * NOTE: Exec has turned off task switching while in Open, Close, Expunge and
25 * Reserved functions (via Forbid()/Permit()) so we should not take
32 #include <aros/libcall.h>
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/syslog.h>
38 #include <kern/amiga_includes.h>
40 #include <api/amiga_api.h>
41 #include <api/allocdatabuffer.h>
42 #include <api/amiga_libcallentry.h>
43 #include <api/apicalls.h>
45 #include <kern/amiga_subr.h>
46 #include <kern/amiga_log.h>
49 /*#if sizeof (fd_mask) != 4 || sizeof (long) != 4*/
50 #error AmiTCP/IP currently depends on fd_mask and longword size of 32 bits.
54 * Semaphore to prevent simultaneous access to library functions.
56 struct SignalSemaphore syscall_semaphore
= { {0} };
61 struct Library
*MasterSocketBase
= NULL
;
62 struct Library
*MasterMiamiBase
= NULL
;
63 struct List socketBaseList
; /* list of opened socket library bases */
64 struct List garbageSocketBaseList
; /* list of libray bases not active
65 anymore (NOT YET IMPLEMENTED) */
66 struct List releasedSocketList
; /* List for sockets that are in no-one's
67 context, waiting for Obtain */
69 extern struct Task
* AROSTCP_Task
; /* reference to AmiTCP/IP task information */
70 extern f_void UserLibrary_funcTable
[];
73 * Declaration of variable to hold message format string when one
74 * task tries to use other tasks' library base pointer. moved here
75 * from amiga_libcallentry.h so it doens't generate code.
77 const char wrongTaskErrorFmt
[] =
78 "Task %ld (%s) attempted to use library base of Task %ld (%s).";
80 #if !defined(__AROS__)
82 * Instead of using exec/initializers.h we looked it as a reference
83 * and wrote InitTable by hand
87 * OFFSET needed to be casted LONG so compiler doesn't give warning
88 * about casting pointer to UWORD
91 #define OFFSET(structName, structEntry) \
92 ((LONG)(&(((struct structName *) 0)->structEntry)))
95 * original initTable of only UWORD items doesn't work, since compiler
96 * doesn't know address of SOCNAME and VSTRING at compile time, and
97 * those are broken to 2 WORDS. therefore initTable is a structure
98 * constructed by hand, and those (LONG) values are set longword aligned.
104 struct LibInitTable Library_initTable
= {
105 id_byte
, OFFSET(Node
, ln_Type
), NT_LIBRARY
, 0,
106 id_byte
, OFFSET(Library
, lib_Flags
), (LIBF_SUMUSED
|LIBF_CHANGED
), 0,
107 id_long
, OFFSET(Node
, ln_Name
), (ULONG
)SOCLIBNAME
,
108 id_word
, OFFSET(Library
, lib_Version
), VERSION
,
109 id_word
, OFFSET(Library
, lib_Revision
), REVISION
,
110 id_long
, OFFSET(Library
, lib_IdString
), (ULONG
)RELEASESTRING VSTRING
,
114 struct LibInitTable Miami_initTable
= {
115 id_byte
, OFFSET(Node
, ln_Type
), NT_LIBRARY
, 0,
116 id_byte
, OFFSET(Library
, lib_Flags
), (LIBF_SUMUSED
|LIBF_CHANGED
), 0,
117 id_long
, OFFSET(Node
, ln_Name
), (ULONG
)MIAMILIBNAME
,
118 id_word
, OFFSET(Library
, lib_Version
), MIAMI_VERSION
,
119 id_word
, OFFSET(Library
, lib_Revision
), MIAMI_REVISION
,
120 id_long
, OFFSET(Library
, lib_IdString
), (ULONG
)RELEASESTRING MIAMI_VSTRING
,
129 * API Show and Hide functions.. during these calls system is not
130 * inside Forbid()/Permit() pair
133 enum apistate api_state
= API_SCRATCH
;
136 * Setting the following variable to FALSE just before making
137 * new socket Library base prevents ELL_Expunge, the final
138 * expunging function to remove library base from memory
140 BOOL AROSTCP_FLAG_CANEXPUNGE
= FALSE
;
142 BOOL SB_Expunged
= FALSE
; /* boolean value set by ELL_Expunge */
145 AROS_LH1 (struct Library
*, Open
,
146 AROS_LHA(ULONG
, version
, D0
),
147 struct Library
*, libPtr
, 1, ELL
)
150 struct SocketBase
* newBase
;
154 #if defined(__AROS__)
155 D(bug("[AROSTCP](amiga_api.c) ELL_Open()\n[AROSTCP](amiga_api.c) ELL_Open: version=%lu, libPtr=0x%p\n", version
, libPtr
));
157 D(KPrintF("ELL_Open: version=%lu, libPtr=0x%p\n", version
, libPtr
);)
160 * One task may open socket library more than once. In that case caller
161 * receives the base it has opened already.
163 if ((newBase
= FindSocketBase(FindTask(NULL
))) != NULL
) {
164 newBase
->libNode
.lib_OpenCnt
++;
165 return (struct Library
*)newBase
;
168 * Create new library base.
169 * All fields in the base will first be initialized to zero and then
170 * modified by initializers in initTable.
172 newBase
= (struct SocketBase
*)MakeLibrary(UserLibrary_funcTable
,
173 #if !defined(__AROS__)
174 (UWORD
*)&Library_initTable
,
179 sizeof(struct SocketBase
),
181 #if defined(__AROS__)
183 ((struct Library
*)newBase
)->lib_Node
.ln_Type
= NT_LIBRARY
;
184 ((struct Library
*)newBase
)->lib_Node
.ln_Name
= (APTR
)SOCLIBNAME
;
185 ((struct Library
*)newBase
)->lib_Flags
= (LIBF_SUMUSED
|LIBF_CHANGED
);
186 ((struct Library
*)newBase
)->lib_Version
= VERSION
;
187 ((struct Library
*)newBase
)->lib_Revision
= REVISION
;
188 ((struct Library
*)newBase
)->lib_IdString
= (APTR
)RELEASESTRING VSTRING
;
190 D(bug("[AROSTCP](amiga_api.c) ELL_Open: Created user library base @ 0x%p\n", newBase
));
192 D(__log(LOG_DEBUG
,"Created user library base: 0x%p\n", newBase
);)
197 * add this newly allocated library base to our list of opened
200 AddTail(&socketBaseList
, (struct Node
*)newBase
);
203 * Modify some MASTER library base fields
205 libPtr
->lib_OpenCnt
++; /* mark us as having another opener */
206 libPtr
->lib_Flags
&= ~LIBF_DELEXP
; /* prevent delayed expunges */
209 * Initialize new library base
211 for (i
= (WORD
*)((struct Library
*)newBase
+ 1);
212 i
< (WORD
*)(newBase
+ 1);
215 newBase
->libNode
.lib_OpenCnt
= 1;
216 newBase
->errnoPtr
= (VOID
*)&newBase
->defErrno
;
217 newBase
->errnoSize
= sizeof newBase
->defErrno
;
218 newBase
->thisTask
= FindTask(NULL
);
219 newBase
->sigIntrMask
= SIGBREAKF_CTRL_C
;
221 /* initialize syslog variables */
222 #if 0 /* initialization to zero is implicit */
223 newBase
->LogTag
= NULL
; /* no tag by default, old apps print a tag already */
225 newBase
->LogFacility
= LOG_USER
;
226 newBase
->LogMask
= 0xff;
228 /* initialize resolver variables */
229 newBase
->hErrnoPtr
= &newBase
->defHErrno
;
230 newBase
->res_socket
= -1;
231 //res_init(&newBase->res_state);
233 /* Initialize events list */
234 InitSemaphore(&newBase
->EventLock
);
235 NewList((struct List
*)&newBase
->EventList
);
237 /* initialize dtable variables */
238 #if 0 /* initialization to zero is implicit */
239 newBase
->fdCallback
= NULL
;
241 newBase
->dTableSize
= FD_SETSIZE
;
242 if ((newBase
->dTable
=
243 AllocMem(newBase
->dTableSize
* sizeof (struct socket
*) +
244 ((newBase
->dTableSize
- 1) / NFDBITS
+ 1) * sizeof (fd_mask
),
245 MEMF_CLEAR
|MEMF_PUBLIC
)) != NULL
) {
247 * allocate and initialize the timer message reply port
249 newBase
->timerPort
= CreateMsgPort();
250 if (newBase
->timerPort
!= NULL
) {
252 * Disable signalling for now
254 newBase
->timerPort
->mp_Flags
= PA_IGNORE
;
256 * allocate and initialize the timerequest
258 newBase
->tsleep_timer
= (struct timerequest
*)
259 CreateIORequest(newBase
->timerPort
, sizeof(struct timerequest
));
260 if (newBase
->tsleep_timer
!= NULL
) {
261 error
= OpenDevice(TIMERNAME
, UNIT_VBLANK
,
262 (struct IORequest
*)newBase
->tsleep_timer
, 0);
265 * Initialize some fields of the IO request to common values
267 newBase
->tsleep_timer
->tr_node
.io_Command
= TR_ADDREQUEST
;
268 newBase
->tsleep_timer
->tr_node
.io_Message
.mn_Node
.ln_Type
= NT_UNKNOWN
;
269 return (struct Library
*)newBase
;
275 * There was some error if we reached here. Call Close to clean up.
278 extern ULONG
* __UL_Close(struct SocketBase
*);
285 ULONG
*__ELL_Expunge(struct Library
*libPtr
)
287 #if defined(__AROS__)
288 D(bug("[AROSTCP](amiga_api.c) __ELL_Expunge()\n"));
291 * Since every user gets her own library base, Major library base
292 * can be removed immediately after
294 if (libPtr
->lib_OpenCnt
== 0 && AROSTCP_FLAG_CANEXPUNGE
) {
298 #if 0 /* Currently done already */
300 * unlink SocketBase from System Library list
302 Remove((struct Node
*)libPtr
);
305 freestart
= (void *)((IPTR
)libPtr
- (IPTR
)libPtr
->lib_NegSize
);
306 size
= libPtr
->lib_NegSize
+ libPtr
->lib_PosSize
;
307 FreeMem(freestart
, size
);
309 return NULL
; /* no AmigaDos seglist there (for system use) */
312 * here if someone still has us open, or AmiTCP won't let us expunge yet
314 libPtr
->lib_Flags
|= LIBF_DELEXP
; /* set delayed expunge flag */
319 AROS_LH0(ULONG
*, Expunge
, struct Library
*, libPtr
, 3, ELL
)
322 #if defined(__AROS__)
323 D(bug("[AROSTCP](amiga_api.c) ELL_Expunge()\n"));
325 return __ELL_Expunge(libPtr
);
329 AROS_LH0I(LONG
, Null
, struct Library
*, libPtr
, 0, LIB
)
332 #if defined(__AROS__)
333 D(bug("[AROSTCP](amiga_api.c) ELL_Null: WARNING!!! Null() called\n"));
335 D(KPrintF("WARNING!!! Null() called\n");)
342 ULONG
*__UL_Close(struct SocketBase
*libPtr
)
349 * one task may have SocketLibrary opened more than once.
351 if (--libPtr
->libNode
.lib_OpenCnt
> 0)
354 #if defined(__AROS__)
355 D(bug("[AROSTCP](amiga_api.c) __UL_Close: Closing proc 0x%lx base 0x%lx\n", libPtr
->thisTask
, libPtr
));
357 /* Do not call __log here. If NETTRACE is calling CloseLibrary
358 __log will call back on NETTRACE which will cause hang in close
359 procedure. This was affecting normal and debug build because
360 DEBUG is always defined in conf.h */
361 /*__log(LOG_DEBUG, "Closing proc 0x%lx base 0x%lx\n",
362 libPtr->thisTask, libPtr);*/
366 * Since library base is to be closed, all sockets referenced by this
367 * library base must be closed too. Next piece of code searches for open
368 * sockets and calls CloseSocket() on our own library base. It is safe
369 * to call since Forbid() state is broken if semaphore needs to be waited.
371 * Note that the close may linger. In such case the linger time will be
372 * waited. The linger may be interrupted by any signal in sigIntrMask.
374 libPtr
->fdCallback
= NULL
; /* don't call the callback any more */
375 for (i
= 0; i
< libPtr
->dTableSize
; i
++)
376 if (libPtr
->dTable
[i
] != NULL
)
377 __CloseSocket(i
, libPtr
);
379 Remove((struct Node
*)libPtr
); /* remove this librarybase from our list
380 of opened library bases */
382 if (libPtr
->tsleep_timer
) {
383 if (libPtr
->tsleep_timer
->tr_node
.io_Device
!= NULL
) {
384 if (libPtr
->tsleep_timer
->tr_node
.io_Message
.mn_Node
.ln_Type
!= NT_UNKNOWN
) {
385 /* NC: must check if request has been used */
386 AbortIO((struct IORequest
*)(libPtr
->tsleep_timer
));
387 WaitIO((struct IORequest
*)(libPtr
->tsleep_timer
));
389 CloseDevice((struct IORequest
*)libPtr
->tsleep_timer
);
391 DeleteIORequest((struct IORequest
*)libPtr
->tsleep_timer
);
393 if (libPtr
->timerPort
)
394 DeleteMsgPort(libPtr
->timerPort
);
396 freeDataBuffer(&libPtr
->selitems
);
397 freeDataBuffer(&libPtr
->hostents
);
398 freeDataBuffer(&libPtr
->netents
);
399 freeDataBuffer(&libPtr
->protoents
);
400 freeDataBuffer(&libPtr
->servents
);
403 FreeMem(libPtr
->dTable
, libPtr
->dTableSize
* sizeof (struct socket
*) +
404 ((libPtr
->dTableSize
- 1) / NFDBITS
+ 1) * sizeof (fd_mask
));
406 res_cleanup_db(&libPtr
->res_state
);
408 freestart
= (void *)((IPTR
)libPtr
- (IPTR
)libPtr
->libNode
.lib_NegSize
);
409 size
= libPtr
->libNode
.lib_NegSize
+ libPtr
->libNode
.lib_PosSize
;
410 bzero(freestart
, size
);
411 FreeMem(freestart
, size
);
413 MasterSocketBase
->lib_OpenCnt
--;
415 * If no more libraries are open and delayed expunge is asked,
416 * ELL_expunge() is called.
418 if (MasterSocketBase
->lib_OpenCnt
== 0 &&
419 (MasterSocketBase
->lib_Flags
& LIBF_DELEXP
)) {
420 return __ELL_Expunge(MasterSocketBase
);
423 return NULL
; /* always return null */
426 AROS_LH0(ULONG
*, Close
, struct SocketBase
*, libPtr
, 2, UL
)
429 #if defined(__AROS__)
430 D(bug("[AROSTCP](amiga_api.c) ELL_Close()\n"));
432 return __UL_Close(libPtr
);
439 extern void select_init(void);
440 extern f_void ExecLibraryList_funcTable
[];
441 extern ULONG Miami_InitFuncTable
[];
443 #if defined(__AROS__)
444 D(bug("[AROSTCP](amiga_api.c) api_init()\n"));
447 if (api_state
!= API_SCRATCH
)
450 AROSTCP_FLAG_CANEXPUNGE
= FALSE
;
452 MasterSocketBase
= MakeLibrary(ExecLibraryList_funcTable
,
453 #if !defined(__AROS__)
454 (UWORD
*)&Library_initTable
,
459 sizeof(struct Library
),
461 #if defined(__AROS__)
462 ((struct Library
*)MasterSocketBase
)->lib_Node
.ln_Type
= NT_LIBRARY
;
463 ((struct Library
*)MasterSocketBase
)->lib_Node
.ln_Name
= (APTR
)SOCLIBNAME
;
464 ((struct Library
*)MasterSocketBase
)->lib_Flags
= (LIBF_SUMUSED
|LIBF_CHANGED
);
465 ((struct Library
*)MasterSocketBase
)->lib_Version
= VERSION
;
466 ((struct Library
*)MasterSocketBase
)->lib_Revision
= REVISION
;
467 ((struct Library
*)MasterSocketBase
)->lib_IdString
= (APTR
)RELEASESTRING VSTRING
;
469 D(bug("[AROSTCP](amiga_api.c) api_init: Created master library base: 0x%p\n", MasterSocketBase
));
471 D(Printf("Created master library base: 0x%p\n", MasterSocketBase
);)
472 if (MasterSocketBase
== NULL
)
475 MasterMiamiBase
= MakeLibrary(Miami_InitFuncTable
,
476 #if !defined(__AROS__)
477 (UWORD
*)&Miami_initTable
,
482 sizeof(struct Library
),
484 #if defined(__AROS__)
485 ((struct Library
*)MasterMiamiBase
)->lib_Node
.ln_Type
= NT_LIBRARY
;
486 ((struct Library
*)MasterMiamiBase
)->lib_Node
.ln_Name
= (APTR
)MIAMILIBNAME
;
487 ((struct Library
*)MasterMiamiBase
)->lib_Flags
= (LIBF_SUMUSED
|LIBF_CHANGED
);
488 ((struct Library
*)MasterMiamiBase
)->lib_Version
= MIAMI_VERSION
;
489 ((struct Library
*)MasterMiamiBase
)->lib_Revision
= MIAMI_REVISION
;
490 ((struct Library
*)MasterMiamiBase
)->lib_IdString
= (APTR
)RELEASESTRING MIAMI_VSTRING
;
492 D(bug("[AROSTCP](amiga_api.c) api_init: Created MIAMI library base: 0x%p\n", MasterMiamiBase
));
494 D(Printf("Created master miami.library base: 0x%p\n", MasterMiamiBase
);)
495 if (MasterMiamiBase
== NULL
)
498 InitSemaphore(&syscall_semaphore
);
499 select_init(); /* initializes data Select() needs */
500 NewList(&socketBaseList
);
501 NewList(&garbageSocketBaseList
);
502 NewList(&releasedSocketList
);
504 api_state
= API_INITIALIZED
;
512 struct Node
* libNode
;
513 STRPTR libName
= SOCLIBNAME
;
515 #if defined(__AROS__)
516 D(bug("[AROSTCP](amiga_api.c) api_show()\n"));
519 if (api_state
== API_SHOWN
)
521 if (api_state
== API_SCRATCH
)
525 for (libNode
= SysBase
->LibList
.lh_Head
; libNode
->ln_Succ
;
526 libNode
= libNode
->ln_Succ
) {
527 if (!strncmp(libNode
->ln_Name
, libName
, sizeof (SOCLIBNAME
) - 3)) {
530 if (libNode
->ln_Name
[sizeof (SOCLIBNAME
) - 3] == '\0')
533 i
= (BYTE
)(libNode
->ln_Name
[sizeof (SOCLIBNAME
) - 2] - '0' + 1);
547 libName
[sizeof (SOCLIBNAME
) - 3] = '.';
548 libName
[sizeof (SOCLIBNAME
) - 2] = '0' + nthLibrary
;
549 libName
[sizeof (SOCLIBNAME
) - 1] = '\0';
550 MasterSocketBase
->lib_Node
.ln_Name
= libName
;
553 AddLibrary(MasterSocketBase
);
554 AddLibrary(MasterMiamiBase
);
555 api_state
= API_SHOWN
;
562 #if defined(__AROS__)
563 D(bug("[AROSTCP](amiga_api.c) api_hide()\n"));
566 if (api_state
!= API_SHOWN
)
569 /* unlink Master SocketBase from System Library list */
570 Remove((struct Node
*)MasterSocketBase
);
571 Remove((struct Node
*)MasterMiamiBase
);
573 api_state
= API_HIDDEN
;
576 VOID
api_setfunctions() /* DOES NOTHING NOW */
578 /* struct Node *node2move; */
580 #if defined(__AROS__)
581 D(bug("[AROSTCP](amiga_api.c) api_setfunctions()\n"));
584 if (api_state
== API_SCRATCH
)
586 if (api_state
== API_SHOWN
) {
587 /* unlink Master SocketBase from System Library list */
589 Remove((struct Node
*)MasterMiamiBase
);
590 Remove((struct Node
*)MasterSocketBase
);
594 /* here SetFunction()s to patch libray calls (forbid()/permit()) */
595 /* while(node2move = RemHead(&socketBaseList))
596 AddTail(&garbageSocketBaseList, node2move); */
597 api_state
= API_FUNCTIONPATCHED
;
601 * Send CTRL_C to all tasks having socketbase open.
603 VOID
api_sendbreaktotasks()
605 extern struct List socketBaseList
; /* :/ */
606 struct Node
* libNode
;
608 #if defined(__AROS__)
609 D(bug("[AROSTCP](amiga_api.c) api_sendbreaktotask()\n"));
613 for (libNode
= socketBaseList
.lh_Head
; libNode
->ln_Succ
;
614 libNode
= libNode
->ln_Succ
)
615 if (((struct SocketBase
*)libNode
)->thisTask
!= Nettrace_Task
)
616 Signal(((struct SocketBase
*)libNode
)->thisTask
, SIGBREAKF_CTRL_C
);
624 #if defined(__AROS__)
625 D(bug("[AROSTCP](amiga_api.c) api_deinit()\n"));
628 if (FindTask(NULL
) != AROSTCP_Task
)
630 #if defined(__AROS__)
631 D(bug("[AROSTCP](amiga_api.c) api_deinit: The calling task of api_deinit() was not bsdsocket.library's"));
634 "The calling task of api_deinit() was not bsdsocket.library's");
637 if (api_state
== API_SHOWN
|| api_state
== API_HIDDEN
)
639 if (api_state
== API_SCRATCH
)
643 if (MasterMiamiBase
) {
644 __ELL_Expunge(MasterMiamiBase
);
645 MasterMiamiBase
= NULL
;
647 if (MasterSocketBase
) {
648 AROSTCP_FLAG_CANEXPUNGE
= TRUE
;
649 __ELL_Expunge(MasterSocketBase
);
650 MasterSocketBase
= NULL
;
652 Signal(AROSTCP_Task
, SIGBREAKF_CTRL_F
);
657 * if SB_Expunged == FALSE, waiting until last UL_Close() expunges
660 while(SB_Expunged
== FALSE
)
661 Wait(SIGBREAKF_CTRL_F
);
663 api_state
= API_SCRATCH
;
666 VOID
writeErrnoValue(struct SocketBase
* libPtr
, int error
)
668 #if defined(__AROS__)
669 D(bug("[AROSTCP](amiga_api.c) writeErrnoValue()\n"));
672 * errnoSize is now restricted to 1, 2 or 4
674 BYTE erri
= libPtr
->errnoSize
;
677 *(ULONG
*)libPtr
->errnoPtr
= (ULONG
)error
;
681 *(UWORD
*)libPtr
->errnoPtr
= (UWORD
)error
;
685 *(UBYTE
*)libPtr
->errnoPtr
= (UBYTE
)error
;
689 int readErrnoValue(struct SocketBase
* libPtr
)
691 #if defined(__AROS__)
692 D(bug("[AROSTCP](amiga_api.c) readErrnoValue()\n"));
695 * errnoSize is now restricted to 1, 2 or 4
697 BYTE erri
= libPtr
->errnoSize
;
700 return *(ULONG
*)libPtr
->errnoPtr
;
703 return *(UWORD
*)libPtr
->errnoPtr
;
706 return *(UBYTE
*)libPtr
->errnoPtr
;