tools/adflib: build only host variant which is used by Sam440 target
[AROS.git] / workbench / network / stacks / AROSTCP / bsdsocket / api / amiga_sendrecv.c
blob76c852d023cdc0f9d4e1e535e83e8bb373cde4a9
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 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,
20 * MA 02111-1307, USA.
24 #include <conf.h>
26 #include <sys/param.h>
27 #include <sys/systm.h>
28 #include <sys/malloc.h>
29 #include <sys/mbuf.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>
48 #include <sys/uio.h>
50 static LONG sendit(struct SocketBase * p,
51 LONG s,
52 struct msghdr * mp,
53 LONG flags,
54 LONG * retsize);
56 static LONG recvit(struct SocketBase * p,
57 LONG s,
58 struct msghdr * mp,
59 LONG flags,
60 LONG * namelenp,
61 LONG * retsize);
64 LONG __send(LONG s, caddr_t buf, LONG len, LONG flags, struct SocketBase *libPtr)
66 struct msghdr msg;
67 struct iovec aiov;
68 LONG error, retval;
70 CHECK_TASK();
72 msg.msg_name = 0;
73 msg.msg_namelen = 0;
74 msg.msg_iov = &aiov;
75 msg.msg_iovlen = 1;
76 msg.msg_control = 0;
77 aiov.iov_base = buf;
78 aiov.iov_len = len;
80 ObtainSyscallSemaphore(libPtr);
81 error = sendit(libPtr, s, &msg, flags, &retval);
82 ReleaseSyscallSemaphore(libPtr);
84 API_STD_RETURN(error, retval);
87 AROS_LH4(LONG, send,
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)
94 AROS_LIBFUNC_INIT
95 DSYSCALLS(log(LOG_DEBUG,"send(%ld, buf, %ld, 0x%08lx) called", s, len, flags);)
96 return __send(s, buf, len, flags, libPtr);
97 AROS_LIBFUNC_EXIT
100 LONG __sendto(LONG s, caddr_t buf, LONG len, LONG flags, caddr_t to, LONG tolen, struct SocketBase *libPtr)
102 struct msghdr msg;
103 struct iovec aiov;
104 LONG error, retval;
105 #ifdef ENABLE_TTCP_SHUTUP
106 struct socket *so;
107 #endif
108 CHECK_TASK();
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);
116 if (!error) {
117 if (so->so_options & SO_TTCP_SHUTUP)
118 error = ENOTCONN;
119 else {
120 #endif
121 msg.msg_name = to;
122 msg.msg_namelen = tolen;
123 msg.msg_iov = &aiov;
124 msg.msg_iovlen = 1;
125 msg.msg_control = 0;
126 aiov.iov_base = buf;
127 aiov.iov_len = len;
129 ObtainSyscallSemaphore(libPtr);
130 error = sendit(libPtr, s, &msg, flags, &retval);
131 ReleaseSyscallSemaphore(libPtr);
132 #ifdef ENABLE_TTCP_SHUTUP
135 #endif
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)
148 AROS_LIBFUNC_INIT
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);
152 AROS_LIBFUNC_EXIT
155 /*LONG SAVEDS sendmsg(
156 REG(d0, LONG s),
157 REG(a0, struct msghdr *msg_p),
158 REG(d1, LONG flags),
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)
166 AROS_LIBFUNC_INIT
167 LONG error, retval;
169 CHECK_TASK();
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);
176 AROS_LIBFUNC_EXIT
179 static LONG sendit(struct SocketBase * p,
180 LONG s,
181 struct msghdr * mp,
182 LONG flags,
183 LONG * retsize)
185 struct socket *so;
186 struct uio auio;
187 register int i;
188 register struct iovec *iov;
189 struct mbuf *to, *control;
190 LONG len, error;
192 if (error = getSock(p, s, &so))
193 return (error);
195 auio.uio_iov = mp->msg_iov;
196 auio.uio_iovcnt = mp->msg_iovlen;
197 auio.uio_procp = p;
198 auio.uio_resid = 0;
199 iov = mp->msg_iov;
201 for(i = 0; i < mp->msg_iovlen; i++, iov++) {
202 if (iov->iov_len < 0)
203 return (EINVAL);
204 if ((auio.uio_resid += iov->iov_len) < 0)
205 return (EINVAL);
208 if (mp->msg_name) {
209 if (error = sockArgs(&to, mp->msg_name, mp->msg_namelen, MT_SONAME))
210 return (error);
212 else
213 to = 0;
215 if (mp->msg_control) {
216 if (mp->msg_controllen < sizeof (struct cmsghdr)) {
217 error = EINVAL;
218 goto bad;
220 if (error = sockArgs(&control, mp->msg_control,
221 mp->msg_controllen, MT_CONTROL))
222 goto bad;
224 else
225 control = 0;
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))
231 error = 0;
233 if (error == 0)
234 *retsize = len - auio.uio_resid;
236 /* sosend() frees control if allocated */
237 bad:
238 if (to)
239 m_freem(to);
241 return (error);
244 LONG __recv(LONG s, caddr_t buf, LONG len, LONG flags, struct SocketBase *libPtr)
246 struct msghdr msg;
247 struct iovec aiov;
248 LONG error, retval;
250 CHECK_TASK();
252 msg.msg_name = 0;
253 msg.msg_namelen = 0;
254 msg.msg_iov = &aiov;
255 msg.msg_iovlen = 1;
256 msg.msg_control = 0;
257 aiov.iov_base = buf;
258 aiov.iov_len = len;
260 ObtainSyscallSemaphore(libPtr);
261 error = recvit(libPtr, s, &msg, flags, NULL, &retval);
262 ReleaseSyscallSemaphore(libPtr);
264 API_STD_RETURN(error, retval);
267 AROS_LH4(LONG, recv,
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)
274 AROS_LIBFUNC_INIT
275 DSYSCALLS(log(LOG_DEBUG,"recv(%ld, buf, %ld, 0x%08lx) called", s, len, flags);)
276 return __recv(s, buf, len, flags, libPtr);
277 AROS_LIBFUNC_EXIT
280 /*LONG SAVEDS recvfrom(
281 REG(d0, LONG s),
282 REG(a0, caddr_t buf),
283 REG(d1, LONG len),
284 REG(d2, LONG flags),
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)
297 AROS_LIBFUNC_INIT
298 struct msghdr msg;
299 struct iovec aiov;
300 LONG error, retval;
302 CHECK_TASK();
303 DSYSCALLS(log(LOG_DEBUG,"recvfrom(%ld, buf, %ld, 0x%08lx) called", s, len, flags);)
304 if (fromlenaddr)
305 msg.msg_namelen = *fromlenaddr;
306 else
307 msg.msg_namelen = 0;
309 msg.msg_name = from;
310 msg.msg_iov = &aiov;
311 msg.msg_iovlen = 1;
312 msg.msg_control = 0;
313 aiov.iov_base = buf;
314 aiov.iov_len = len;
316 ObtainSyscallSemaphore(libPtr);
317 error = recvit(libPtr, s, &msg, flags, fromlenaddr, &retval);
318 ReleaseSyscallSemaphore(libPtr);
320 API_STD_RETURN(error, retval);
321 AROS_LIBFUNC_EXIT
324 /*LONG SAVEDS recvmsg(
325 REG(d0, LONG s),
326 REG(a0, struct msghdr *msg_p),
327 REG(d1, LONG flags),
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)
335 AROS_LIBFUNC_INIT
336 LONG error, retval;
338 CHECK_TASK();
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);
345 AROS_LIBFUNC_EXIT
348 static LONG recvit(struct SocketBase * p,
349 LONG s,
350 struct msghdr * mp,
351 LONG flags,
352 LONG * namelenp,
353 LONG * retsize)
355 struct socket * so;
356 struct uio auio;
357 struct iovec *iov;
358 register int i;
359 ULONG len;
360 LONG error;
361 struct mbuf *from = 0, *control = 0;
363 if (error = getSock(p, s, &so))
364 return (error);
366 auio.uio_iov = mp->msg_iov;
367 auio.uio_iovcnt = mp->msg_iovlen;
368 auio.uio_procp = p;
369 auio.uio_resid = 0;
371 iov = mp->msg_iov;
372 for(i = 0; i < mp->msg_iovlen; i++, iov++) {
373 if (iov->iov_len < 0)
374 return (EINVAL);
375 if ((auio.uio_resid += iov->iov_len) < 0)
376 return (EINVAL);
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))
383 error = 0;
385 if (error)
386 goto out;
388 *retsize = len - auio.uio_resid;
390 if (mp->msg_name) {
391 len = mp->msg_namelen;
392 if (len <= 0 || from == 0)
393 len = 0;
394 else {
395 if (len > from->m_len)
396 len = from->m_len;
397 aligned_bcopy(mtod(from, caddr_t), (caddr_t)mp->msg_name, (unsigned)len);
399 mp->msg_namelen = len;
400 if (namelenp)
401 *namelenp = len;
403 if (mp->msg_control) {
404 len = mp->msg_controllen;
405 if (len <= 0 || control == 0)
406 len = 0;
407 else {
408 if (len >= control->m_len)
409 len = control->m_len;
410 /* else
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;
418 out:
419 if (from)
420 m_freem(from);
421 if (control)
422 m_freem(control);
424 return (error);