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