2 * Copyright (C) 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>
3 * Helsinki University of Technology, Finland.
5 * Copyright (C) 2005 Neil Cafferkey
6 * Copyright (C) 2005 Pavel Fedin
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
26 #include <sys/param.h>
27 #include <sys/systm.h>
28 #include <sys/malloc.h>
30 #include <sys/protosw.h>
31 #include <sys/socket.h>
32 #include <sys/socketvar.h>
33 #include <sys/synch.h>
34 #include <sys/errno.h>
36 #include <aros/libcall.h>
37 #include <exec/types.h>
38 #include <exec/libraries.h>
39 #include <exec/semaphores.h>
41 #include <api/amiga_api.h>
42 #include <api/amiga_libcallentry.h>
43 #include <api/sockargs.h>
45 #include <kern/uipc_socket_protos.h>
46 #include <kern/uipc_socket2_protos.h>
50 static LONG
sendit(struct SocketBase
* p
,
56 static LONG
recvit(struct SocketBase
* p
,
64 LONG
__send(LONG s
, caddr_t buf
, LONG len
, LONG flags
, struct SocketBase
*libPtr
)
80 ObtainSyscallSemaphore(libPtr
);
81 error
= sendit(libPtr
, s
, &msg
, flags
, &retval
);
82 ReleaseSyscallSemaphore(libPtr
);
84 API_STD_RETURN(error
, retval
);
88 AROS_LHA(LONG
, s
, D0
),
89 AROS_LHA(caddr_t
, buf
, A0
),
90 AROS_LHA(LONG
, len
, D1
),
91 AROS_LHA(LONG
, flags
, D2
),
92 struct SocketBase
*, libPtr
, 11, UL
)
95 DSYSCALLS(log(LOG_DEBUG
,"send(%ld, buf, %ld, 0x%08lx) called", s
, len
, flags
);)
96 return __send(s
, buf
, len
, flags
, libPtr
);
100 LONG
__sendto(LONG s
, caddr_t buf
, LONG len
, LONG flags
, caddr_t to
, LONG tolen
, struct SocketBase
*libPtr
)
105 #ifdef ENABLE_TTCP_SHUTUP
109 #ifdef ENABLE_TTCP_SHUTUP
110 /* This is a workaround for IBrowse which tries to use T/TCP if it discovers miami.library
111 => V3. Before using T/TCP it sets TCP_NOPUSH option for the socket. We have to implement
112 this option because if IBrowse receives ENOPROTOOPT after this call it refusess to work
113 instead of falling back to normal TCP. Normal TCP is used in this mode only when sendto()
114 returns ENOTCONN. Here we enforce this error if TCP_NOPUSH is set. */
115 error
= getSock(libPtr
, s
, &so
);
117 if (so
->so_options
& SO_TTCP_SHUTUP
)
122 msg
.msg_namelen
= tolen
;
129 ObtainSyscallSemaphore(libPtr
);
130 error
= sendit(libPtr
, s
, &msg
, flags
, &retval
);
131 ReleaseSyscallSemaphore(libPtr
);
132 #ifdef ENABLE_TTCP_SHUTUP
136 API_STD_RETURN(error
, retval
);
139 AROS_LH6(LONG
, sendto
,
140 AROS_LHA(LONG
, s
, D0
),
141 AROS_LHA(caddr_t
, buf
, A0
),
142 AROS_LHA(LONG
, len
, D1
),
143 AROS_LHA(LONG
, flags
, D2
),
144 AROS_LHA(caddr_t
, to
, A1
),
145 AROS_LHA(LONG
, tolen
, D3
),
146 struct SocketBase
*, libPtr
, 10, UL
)
149 DSYSCALLS(log(LOG_DEBUG
,"sendto(%ld, buf, %ld, 0x%08lx, sockaddr_in, %ld", s
, len
, flags
, tolen
);)
150 DSYSCALLS(dump_sockaddr_in((struct sockaddr_in
*)to
, libPtr
);)
151 return __sendto(s
, buf
, len
, flags
, to
, tolen
, libPtr
);
155 /*LONG SAVEDS sendmsg(
157 REG(a0, struct msghdr *msg_p),
159 REG(a6, struct SocketBase *libPtr))*/
160 AROS_LH3(LONG
, sendmsg
,
161 AROS_LHA(LONG
, s
, D0
),
162 AROS_LHA(struct msghdr
*, msg_p
, A0
),
163 AROS_LHA(LONG
, flags
, D1
),
164 struct SocketBase
*, libPtr
, 45, UL
)
170 DSYSCALLS(log(LOG_DEBUG
,"sendmsg(%ld, msghdr, 0x%08lx) called", s
, flags
);)
171 ObtainSyscallSemaphore(libPtr
);
172 error
= sendit(libPtr
, s
, msg_p
, flags
, &retval
);
173 ReleaseSyscallSemaphore(libPtr
);
175 API_STD_RETURN(error
, retval
);
179 static LONG
sendit(struct SocketBase
* p
,
188 register struct iovec
*iov
;
189 struct mbuf
*to
, *control
;
192 if (error
= getSock(p
, s
, &so
))
195 auio
.uio_iov
= mp
->msg_iov
;
196 auio
.uio_iovcnt
= mp
->msg_iovlen
;
201 for(i
= 0; i
< mp
->msg_iovlen
; i
++, iov
++) {
202 if (iov
->iov_len
< 0)
204 if ((auio
.uio_resid
+= iov
->iov_len
) < 0)
209 if (error
= sockArgs(&to
, mp
->msg_name
, mp
->msg_namelen
, MT_SONAME
))
215 if (mp
->msg_control
) {
216 if (mp
->msg_controllen
< sizeof (struct cmsghdr
)) {
220 if (error
= sockArgs(&control
, mp
->msg_control
,
221 mp
->msg_controllen
, MT_CONTROL
))
227 len
= auio
.uio_resid
;
228 if (error
= sosend(so
, to
, &auio
, (struct mbuf
*)0, control
, flags
)) {
229 if (auio
.uio_resid
!= len
&& (error
== ERESTART
|| error
== EINTR
||
230 error
== EWOULDBLOCK
))
234 *retsize
= len
- auio
.uio_resid
;
236 /* sosend() frees control if allocated */
244 LONG
__recv(LONG s
, caddr_t buf
, LONG len
, LONG flags
, struct SocketBase
*libPtr
)
260 ObtainSyscallSemaphore(libPtr
);
261 error
= recvit(libPtr
, s
, &msg
, flags
, NULL
, &retval
);
262 ReleaseSyscallSemaphore(libPtr
);
264 API_STD_RETURN(error
, retval
);
268 AROS_LHA(LONG
, s
, D0
),
269 AROS_LHA(caddr_t
, buf
, A0
),
270 AROS_LHA(LONG
, len
, D1
),
271 AROS_LHA(LONG
, flags
, D2
),
272 struct SocketBase
*, libPtr
, 13, UL
)
275 DSYSCALLS(log(LOG_DEBUG
,"recv(%ld, buf, %ld, 0x%08lx) called", s
, len
, flags
);)
276 return __recv(s
, buf
, len
, flags
, libPtr
);
280 /*LONG SAVEDS recvfrom(
282 REG(a0, caddr_t buf),
285 REG(a1, caddr_t from),
286 REG(a2, LONG * fromlenaddr),
287 REG(a6, struct SocketBase *libPtr))*/
288 AROS_LH6(LONG
, recvfrom
,
289 AROS_LHA(LONG
, s
, D0
),
290 AROS_LHA(caddr_t
, buf
, A0
),
291 AROS_LHA(LONG
, len
, D1
),
292 AROS_LHA(LONG
, flags
, D2
),
293 AROS_LHA(caddr_t
, from
, A1
),
294 AROS_LHA(LONG
*, fromlenaddr
, A2
),
295 struct SocketBase
*, libPtr
, 12, UL
)
303 DSYSCALLS(log(LOG_DEBUG
,"recvfrom(%ld, buf, %ld, 0x%08lx) called", s
, len
, flags
);)
305 msg
.msg_namelen
= *fromlenaddr
;
316 ObtainSyscallSemaphore(libPtr
);
317 error
= recvit(libPtr
, s
, &msg
, flags
, fromlenaddr
, &retval
);
318 ReleaseSyscallSemaphore(libPtr
);
320 API_STD_RETURN(error
, retval
);
324 /*LONG SAVEDS recvmsg(
326 REG(a0, struct msghdr *msg_p),
328 REG(a6, struct SocketBase *libPtr))*/
329 AROS_LH3(LONG
, recvmsg
,
330 AROS_LHA(LONG
, s
, D0
),
331 AROS_LHA(struct msghdr
*, msg_p
, A0
),
332 AROS_LHA(LONG
, flags
, D1
),
333 struct SocketBase
*, libPtr
, 46, UL
)
339 DSYSCALLS(log(LOG_DEBUG
,"recvmsg(%ld, msghdr, 0x%08lx) called", s
, flags
);)
340 ObtainSyscallSemaphore(libPtr
);
341 error
= recvit(libPtr
, s
, msg_p
, flags
, NULL
, &retval
);
342 ReleaseSyscallSemaphore(libPtr
);
344 API_STD_RETURN(error
, retval
);
348 static LONG
recvit(struct SocketBase
* p
,
361 struct mbuf
*from
= 0, *control
= 0;
363 if (error
= getSock(p
, s
, &so
))
366 auio
.uio_iov
= mp
->msg_iov
;
367 auio
.uio_iovcnt
= mp
->msg_iovlen
;
372 for(i
= 0; i
< mp
->msg_iovlen
; i
++, iov
++) {
373 if (iov
->iov_len
< 0)
375 if ((auio
.uio_resid
+= iov
->iov_len
) < 0)
378 len
= auio
.uio_resid
;
379 if (error
= soreceive(so
, &from
, &auio
,
380 (struct mbuf
**)0, &control
, (int *)&flags
))
381 if (auio
.uio_resid
!= len
&& (error
== ERESTART
|| error
== EINTR
||
382 error
== EWOULDBLOCK
))
388 *retsize
= len
- auio
.uio_resid
;
391 len
= mp
->msg_namelen
;
392 if (len
<= 0 || from
== 0)
395 if (len
> from
->m_len
)
397 aligned_bcopy(mtod(from
, caddr_t
), (caddr_t
)mp
->msg_name
, (unsigned)len
);
399 mp
->msg_namelen
= len
;
403 if (mp
->msg_control
) {
404 len
= mp
->msg_controllen
;
405 if (len
<= 0 || control
== 0)
408 if (len
>= control
->m_len
)
409 len
= control
->m_len
;
411 flags |= MSG_CTRUNC; no syscall ever does something w/ mp->flags */
413 aligned_bcopy(mtod(control
, caddr_t
),
414 (caddr_t
)mp
->msg_control
, (unsigned)len
);
416 mp
->msg_controllen
= len
;