darwin: stop processing upcalls once rx shutdown starts
[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 extern rx_atomic_t rxinit_status;
26
27 void
28 rx_upcall(socket_t so, void *arg, __unused int waitflag)
29 {
30     mbuf_t m;
31     int error = 0;
32     int i, flags = 0;
33     struct msghdr msg;
34     struct sockaddr_storage ss;
35     struct sockaddr *sa = NULL;
36     struct sockaddr_in from;
37     struct rx_packet *p;
38     afs_int32 rlen;
39     afs_int32 tlen;
40     afs_int32 savelen;          /* was using rlen but had aliasing problems */
41     size_t nbytes, resid, noffset;
42
43     /* we stopped rx but the socket isn't closed yet */
44     if (rx_atomic_test_bit(&rxinit_status, 0))
45         return;
46
47     /* See if a check for additional packets was issued */
48     rx_CheckPackets();
49
50     p = rxi_AllocPacket(RX_PACKET_CLASS_RECEIVE);
51     rx_computelen(p, tlen);
52     rx_SetDataSize(p, tlen);    /* this is the size of the user data area */
53     tlen += RX_HEADER_SIZE;     /* now this is the size of the entire packet */
54     rlen = rx_maxJumboRecvSize; /* this is what I am advertising.  Only check
55                                  * it once in order to avoid races.  */
56     tlen = rlen - tlen;
57     if (tlen > 0) {
58         tlen = rxi_AllocDataBuf(p, tlen, RX_PACKET_CLASS_RECV_CBUF);
59         if (tlen > 0) {
60             tlen = rlen - tlen;
61         } else
62             tlen = rlen;
63     } else
64         tlen = rlen;
65     /* add some padding to the last iovec, it's just to make sure that the
66      * read doesn't return more data than we expect, and is done to get around
67      * our problems caused by the lack of a length field in the rx header. */
68     savelen = p->wirevec[p->niovecs - 1].iov_len;
69     p->wirevec[p->niovecs - 1].iov_len = savelen + RX_EXTRABUFFERSIZE;
70
71     resid = nbytes = tlen + sizeof(afs_int32);
72
73     memset(&msg, 0, sizeof(struct msghdr));
74     msg.msg_name = &ss;
75     msg.msg_namelen = sizeof(struct sockaddr_storage);
76     sa =(struct sockaddr *) &ss;
77
78     do {
79         m = NULL;
80         error = sock_receivembuf(so, &msg, &m, MSG_DONTWAIT, &nbytes);
81         if (!error) {
82             size_t sz, offset = 0;
83             noffset = 0;
84             resid = nbytes;
85             for (i=0;i<p->niovecs && resid;i++) {
86                 sz=MIN(resid, p->wirevec[i].iov_len);
87                 error = mbuf_copydata(m, offset, sz, p->wirevec[i].iov_base);
88                 if (error)
89                     break;
90                 resid-=sz;
91                 offset+=sz;
92                 noffset += sz;
93             }
94         }
95     } while (0);
96
97     mbuf_freem(m);
98
99     /* restore the vec to its correct state */
100     p->wirevec[p->niovecs - 1].iov_len = savelen;
101
102     if (error == EWOULDBLOCK && noffset > 0)
103         error = 0;
104
105     if (!error) {
106         int host, port;
107
108         nbytes -= resid;
109
110         if (sa->sa_family == AF_INET)
111             from = *(struct sockaddr_in *)sa;
112
113         p->length = nbytes - RX_HEADER_SIZE;;
114         if ((nbytes > tlen) || (p->length & 0x8000)) {  /* Bogus packet */
115             if (nbytes <= 0) {
116                 if (rx_stats_active) {
117                     MUTEX_ENTER(&rx_stats_mutex);
118                     rx_atomic_inc(&rx_stats.bogusPacketOnRead);
119                     rx_stats.bogusHost = from.sin_addr.s_addr;
120                     MUTEX_EXIT(&rx_stats_mutex);
121                 }
122                 dpf(("B: bogus packet from [%x,%d] nb=%d",
123                      from.sin_addr.s_addr, from.sin_port, nbytes));
124             }
125             return;
126         } else {
127             /* Extract packet header. */
128             rxi_DecodePacketHeader(p);
129
130             host = from.sin_addr.s_addr;
131             port = from.sin_port;
132             if (p->header.type > 0 && p->header.type < RX_N_PACKET_TYPES) {
133                 if (rx_stats_active) {
134                     rx_atomic_inc(&rx_stats.packetsRead[p->header.type - 1]);
135                 }
136             }
137
138 #ifdef RX_TRIMDATABUFS
139             /* Free any empty packet buffers at the end of this packet */
140             rxi_TrimDataBufs(p, 1);
141 #endif
142             /* receive pcket */
143             p = rxi_ReceivePacket(p, so, host, port, 0, 0);
144         }
145     }
146     /* free packet? */
147     if (p)
148         rxi_FreePacket(p);
149
150     return;
151 }
152
153 /* in listener env, the listener shutdown does this. we have no listener */
154 void
155 osi_StopNetIfPoller(void)
156 {
157     shutdown_rx();
158     soclose(rx_socket);
159     if (afs_termState == AFSOP_STOP_NETIF) {
160         afs_termState = AFSOP_STOP_COMPLETE;
161         osi_rxWakeup(&afs_termState);
162     }
163 }
164 #elif defined(RXK_LISTENER_ENV)
165 int
166 osi_NetReceive(osi_socket so, struct sockaddr_in *addr, struct iovec *dvec,
167                int nvecs, int *alength)
168 {
169 #ifdef AFS_DARWIN80_ENV
170     socket_t asocket = (socket_t)so;
171     struct msghdr msg;
172     struct sockaddr_storage ss;
173     int rlen;
174     mbuf_t m;
175 #else
176     struct socket *asocket = (struct socket *)so;
177     struct uio u;
178 #endif
179     int i;
180     struct iovec iov[RX_MAXIOVECS];
181     struct sockaddr *sa = NULL;
182     int code;
183     size_t resid;
184
185     int haveGlock = ISAFS_GLOCK();
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 #ifdef AFS_DARWIN80_ENV
286     socket_t asocket = (socket_t)so;
287     struct msghdr msg;
288     size_t slen;
289 #else
290     struct socket *asocket = (struct socket *)so;
291     struct uio u;
292 #endif
293     afs_int32 code;
294     int i;
295     struct iovec iov[RX_MAXIOVECS];
296     int haveGlock = ISAFS_GLOCK();
297
298     AFS_STATCNT(osi_NetSend);
299     if (nvecs > RX_MAXIOVECS)
300         osi_Panic("osi_NetSend: %d: Too many iovecs.\n", nvecs);
301
302     for (i = 0; i < nvecs; i++)
303         iov[i] = dvec[i];
304
305     addr->sin_len = sizeof(struct sockaddr_in);
306
307     if ((afs_termState == AFSOP_STOP_RXK_LISTENER) ||
308         (afs_termState == AFSOP_STOP_COMPLETE))
309         return -1;
310
311     if (haveGlock)
312         AFS_GUNLOCK();
313
314 #if defined(KERNEL_FUNNEL)
315     thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
316 #endif
317 #ifdef AFS_DARWIN80_ENV
318     memset(&msg, 0, sizeof(struct msghdr));
319     msg.msg_name = addr;
320     msg.msg_namelen = ((struct sockaddr *)addr)->sa_len;
321     msg.msg_iov = &iov[0];
322     msg.msg_iovlen = nvecs;
323     code = sock_send(asocket, &msg, 0, &slen);
324 #else
325     u.uio_iov = &iov[0];
326     u.uio_iovcnt = nvecs;
327     u.uio_offset = 0;
328     u.uio_resid = alength;
329     u.uio_segflg = UIO_SYSSPACE;
330     u.uio_rw = UIO_WRITE;
331     u.uio_procp = NULL;
332     code = sosend(asocket, (struct sockaddr *)addr, &u, NULL, NULL, 0);
333 #endif
334
335 #if defined(KERNEL_FUNNEL)
336     thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
337 #endif
338     if (haveGlock)
339         AFS_GLOCK();
340     return code;
341 }