def2994d6d9fc44978f35a12ec15ef6e4db6a075
[openafs.git] / src / rx / DARWIN / rx_knet.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include "afs/param.h"
12
13
14 #include "rx/rx_kcommon.h"
15 #include "rx/rx_atomic.h"
16 #include "rx/rx_internal.h"
17 #include "rx/rx_packet.h"
18 #include "rx/rx_stats.h"
19
20 #ifdef AFS_DARWIN80_ENV
21 #define soclose sock_close
22 #endif
23
24 #ifdef RXK_UPCALL_ENV
25 void
26 rx_upcall(socket_t so, void *arg, __unused int waitflag)
27 {
28     mbuf_t m;
29     int error = 0;
30     int i, flags = 0;
31     struct msghdr msg;
32     struct sockaddr_storage ss;
33     struct sockaddr *sa = NULL;
34     struct sockaddr_in from;
35     struct rx_packet *p;
36     afs_int32 rlen;
37     afs_int32 tlen;
38     afs_int32 savelen;          /* was using rlen but had aliasing problems */
39     size_t nbytes, resid, noffset;
40
41     /* See if a check for additional packets was issued */
42     rx_CheckPackets();
43
44     p = rxi_AllocPacket(RX_PACKET_CLASS_RECEIVE);
45     rx_computelen(p, tlen);
46     rx_SetDataSize(p, tlen);    /* this is the size of the user data area */
47     tlen += RX_HEADER_SIZE;     /* now this is the size of the entire packet */
48     rlen = rx_maxJumboRecvSize; /* this is what I am advertising.  Only check
49                                  * it once in order to avoid races.  */
50     tlen = rlen - tlen;
51     if (tlen > 0) {
52         tlen = rxi_AllocDataBuf(p, tlen, RX_PACKET_CLASS_RECV_CBUF);
53         if (tlen > 0) {
54             tlen = rlen - tlen;
55         } else
56             tlen = rlen;
57     } else
58         tlen = rlen;
59     /* add some padding to the last iovec, it's just to make sure that the
60      * read doesn't return more data than we expect, and is done to get around
61      * our problems caused by the lack of a length field in the rx header. */
62     savelen = p->wirevec[p->niovecs - 1].iov_len;
63     p->wirevec[p->niovecs - 1].iov_len = savelen + RX_EXTRABUFFERSIZE;
64
65     resid = nbytes = tlen + sizeof(afs_int32);
66
67     memset(&msg, 0, sizeof(struct msghdr));
68     msg.msg_name = &ss;
69     msg.msg_namelen = sizeof(struct sockaddr_storage);
70     sa =(struct sockaddr *) &ss;
71
72     do {
73         m = NULL;
74         error = sock_receivembuf(so, &msg, &m, MSG_DONTWAIT, &nbytes);
75         if (!error) {
76             size_t sz, offset = 0;
77             noffset = 0;
78             resid = nbytes;
79             for (i=0;i<p->niovecs && resid;i++) {
80                 sz=MIN(resid, p->wirevec[i].iov_len);
81                 error = mbuf_copydata(m, offset, sz, p->wirevec[i].iov_base);
82                 if (error)
83                     break;
84                 resid-=sz;
85                 offset+=sz;
86                 noffset += sz;
87             }
88         }
89     } while (0);
90
91     mbuf_freem(m);
92
93     /* restore the vec to its correct state */
94     p->wirevec[p->niovecs - 1].iov_len = savelen;
95
96     if (error == EWOULDBLOCK && noffset > 0)
97         error = 0;
98
99     if (!error) {
100         int host, port;
101
102         nbytes -= resid;
103
104         if (sa->sa_family == AF_INET)
105             from = *(struct sockaddr_in *)sa;
106
107         p->length = nbytes - RX_HEADER_SIZE;;
108         if ((nbytes > tlen) || (p->length & 0x8000)) {  /* Bogus packet */
109             if (nbytes <= 0) {
110                 if (rx_stats_active) {
111                     MUTEX_ENTER(&rx_stats_mutex);
112                     rx_atomic_inc(&rx_stats.bogusPacketOnRead);
113                     rx_stats.bogusHost = from.sin_addr.s_addr;
114                     MUTEX_EXIT(&rx_stats_mutex);
115                 }
116                 dpf(("B: bogus packet from [%x,%d] nb=%d",
117                      from.sin_addr.s_addr, from.sin_port, nbytes));
118             }
119             return;
120         } else {
121             /* Extract packet header. */
122             rxi_DecodePacketHeader(p);
123
124             host = from.sin_addr.s_addr;
125             port = from.sin_port;
126             if (p->header.type > 0 && p->header.type < RX_N_PACKET_TYPES) {
127                 if (rx_stats_active) {
128                     rx_atomic_inc(&rx_stats.packetsRead[p->header.type - 1]);
129                 }
130             }
131
132 #ifdef RX_TRIMDATABUFS
133             /* Free any empty packet buffers at the end of this packet */
134             rxi_TrimDataBufs(p, 1);
135 #endif
136             /* receive pcket */
137             p = rxi_ReceivePacket(p, so, host, port, 0, 0);
138         }
139     }
140     /* free packet? */
141     if (p)
142         rxi_FreePacket(p);
143
144     return;
145 }
146
147 /* in listener env, the listener shutdown does this. we have no listener */
148 void
149 osi_StopNetIfPoller(void)
150 {
151     shutdown_rx();
152     soclose(rx_socket);
153     if (afs_termState == AFSOP_STOP_NETIF) {
154         afs_termState = AFSOP_STOP_COMPLETE;
155         osi_rxWakeup(&afs_termState);
156     }
157 }
158 #elif defined(RXK_LISTENER_ENV)
159 int
160 osi_NetReceive(osi_socket so, struct sockaddr_in *addr, struct iovec *dvec,
161                int nvecs, int *alength)
162 {
163 #ifdef AFS_DARWIN80_ENV
164     socket_t asocket = (socket_t)so;
165     struct msghdr msg;
166     struct sockaddr_storage ss;
167     int rlen;
168     mbuf_t m;
169 #else
170     struct socket *asocket = (struct socket *)so;
171     struct uio u;
172 #endif
173     int i;
174     struct iovec iov[RX_MAXIOVECS];
175     struct sockaddr *sa = NULL;
176     int code;
177     size_t resid;
178
179     int haveGlock = ISAFS_GLOCK();
180     /*AFS_STATCNT(osi_NetReceive); */
181
182     if (nvecs > RX_MAXIOVECS)
183         osi_Panic("osi_NetReceive: %d: Too many iovecs.\n", nvecs);
184
185     for (i = 0; i < nvecs; i++)
186         iov[i] = dvec[i];
187
188     if ((afs_termState == AFSOP_STOP_RXK_LISTENER) ||
189         (afs_termState == AFSOP_STOP_COMPLETE))
190         return -1;
191
192     if (haveGlock)
193         AFS_GUNLOCK();
194 #if defined(KERNEL_FUNNEL)
195     thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
196 #endif
197 #ifdef AFS_DARWIN80_ENV
198     resid = *alength;
199     memset(&msg, 0, sizeof(struct msghdr));
200     msg.msg_name = &ss;
201     msg.msg_namelen = sizeof(struct sockaddr_storage);
202     sa =(struct sockaddr *) &ss;
203     code = sock_receivembuf(asocket, &msg, &m, 0, alength);
204     if (!code) {
205         size_t offset=0,sz;
206         resid = *alength;
207         for (i=0;i<nvecs && resid;i++) {
208             sz=MIN(resid, iov[i].iov_len);
209             code = mbuf_copydata(m, offset, sz, iov[i].iov_base);
210             if (code)
211                 break;
212             resid-=sz;
213             offset+=sz;
214         }
215     }
216     mbuf_freem(m);
217 #else
218
219     u.uio_iov = &iov[0];
220     u.uio_iovcnt = nvecs;
221     u.uio_offset = 0;
222     u.uio_resid = *alength;
223     u.uio_segflg = UIO_SYSSPACE;
224     u.uio_rw = UIO_READ;
225     u.uio_procp = NULL;
226     code = soreceive(asocket, &sa, &u, NULL, NULL, NULL);
227     resid = u.uio_resid;
228 #endif
229
230 #if defined(KERNEL_FUNNEL)
231     thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
232 #endif
233     if (haveGlock)
234         AFS_GLOCK();
235
236     if (code)
237         return code;
238     *alength -= resid;
239     if (sa) {
240         if (sa->sa_family == AF_INET) {
241             if (addr)
242                 *addr = *(struct sockaddr_in *)sa;
243         } else
244             printf("Unknown socket family %d in NetReceive\n", sa->sa_family);
245 #ifndef AFS_DARWIN80_ENV
246         FREE(sa, M_SONAME);
247 #endif
248     }
249     return code;
250 }
251
252 extern int rxk_ListenerPid;
253 void
254 osi_StopListener(void)
255 {
256     struct proc *p;
257
258 #if defined(KERNEL_FUNNEL)
259     thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
260 #endif
261     soclose(rx_socket);
262 #if defined(KERNEL_FUNNEL)
263     thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
264 #endif
265 #ifndef AFS_DARWIN80_ENV
266     p = pfind(rxk_ListenerPid);
267     if (p)
268         psignal(p, SIGUSR1);
269 #endif
270 }
271 #else
272 #error need upcall or listener
273 #endif
274
275 int
276 osi_NetSend(osi_socket so, struct sockaddr_in *addr, struct iovec *dvec,
277             int nvecs, afs_int32 alength, int istack)
278 {
279 #ifdef AFS_DARWIN80_ENV
280     socket_t asocket = (socket_t)so;
281     struct msghdr msg;
282     size_t slen;
283 #else
284     struct socket *asocket = (struct socket *)so;
285     struct uio u;
286 #endif
287     afs_int32 code;
288     int i;
289     struct iovec iov[RX_MAXIOVECS];
290     int haveGlock = ISAFS_GLOCK();
291
292     AFS_STATCNT(osi_NetSend);
293     if (nvecs > RX_MAXIOVECS)
294         osi_Panic("osi_NetSend: %d: Too many iovecs.\n", nvecs);
295
296     for (i = 0; i < nvecs; i++)
297         iov[i] = dvec[i];
298
299     addr->sin_len = sizeof(struct sockaddr_in);
300
301     if ((afs_termState == AFSOP_STOP_RXK_LISTENER) ||
302         (afs_termState == AFSOP_STOP_COMPLETE))
303         return -1;
304
305     if (haveGlock)
306         AFS_GUNLOCK();
307
308 #if defined(KERNEL_FUNNEL)
309     thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
310 #endif
311 #ifdef AFS_DARWIN80_ENV
312     memset(&msg, 0, sizeof(struct msghdr));
313     msg.msg_name = addr;
314     msg.msg_namelen = ((struct sockaddr *)addr)->sa_len;
315     msg.msg_iov = &iov[0];
316     msg.msg_iovlen = nvecs;
317     code = sock_send(asocket, &msg, 0, &slen);
318 #else
319     u.uio_iov = &iov[0];
320     u.uio_iovcnt = nvecs;
321     u.uio_offset = 0;
322     u.uio_resid = alength;
323     u.uio_segflg = UIO_SYSSPACE;
324     u.uio_rw = UIO_WRITE;
325     u.uio_procp = NULL;
326     code = sosend(asocket, (struct sockaddr *)addr, &u, NULL, NULL, 0);
327 #endif
328
329 #if defined(KERNEL_FUNNEL)
330     thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
331 #endif
332     if (haveGlock)
333         AFS_GLOCK();
334     return code;
335 }