#include <afsconfig.h>
#include "afs/param.h"
-RCSID
- ("$Header$");
#include "rx/rx_kcommon.h"
#ifdef AFS_DARWIN80_ENV
#define soclose sock_close
#endif
-
+
+#ifdef RXK_UPCALL_ENV
+void
+rx_upcall(socket_t so, void *arg, __unused int waitflag)
+{
+ mbuf_t m;
+ int error = 0;
+ int i, flags = 0;
+ struct msghdr msg;
+ struct sockaddr_storage ss;
+ struct sockaddr *sa = NULL;
+ struct sockaddr_in from;
+ struct rx_packet *p;
+ afs_int32 rlen;
+ afs_int32 tlen;
+ afs_int32 savelen; /* was using rlen but had aliasing problems */
+ size_t nbytes, resid, noffset;
+
+ p = rxi_AllocPacket(RX_PACKET_CLASS_RECEIVE);
+ rx_computelen(p, tlen);
+ rx_SetDataSize(p, tlen); /* this is the size of the user data area */
+ tlen += RX_HEADER_SIZE; /* now this is the size of the entire packet */
+ rlen = rx_maxJumboRecvSize; /* this is what I am advertising. Only check
+ * it once in order to avoid races. */
+ tlen = rlen - tlen;
+ if (tlen > 0) {
+ tlen = rxi_AllocDataBuf(p, tlen, RX_PACKET_CLASS_RECV_CBUF);
+ if (tlen > 0) {
+ tlen = rlen - tlen;
+ } else
+ tlen = rlen;
+ } else
+ tlen = rlen;
+ /* add some padding to the last iovec, it's just to make sure that the
+ * read doesn't return more data than we expect, and is done to get around
+ * our problems caused by the lack of a length field in the rx header. */
+ savelen = p->wirevec[p->niovecs - 1].iov_len;
+ p->wirevec[p->niovecs - 1].iov_len = savelen + RX_EXTRABUFFERSIZE;
+
+ resid = nbytes = tlen + sizeof(afs_int32);
+
+ memset(&msg, 0, sizeof(struct msghdr));
+ msg.msg_name = &ss;
+ msg.msg_namelen = sizeof(struct sockaddr_storage);
+ sa =(struct sockaddr *) &ss;
+
+ do {
+ m = NULL;
+ error = sock_receivembuf(so, &msg, &m, MSG_DONTWAIT, &nbytes);
+ if (!error) {
+ size_t sz, offset = 0;
+ noffset = 0;
+ resid = nbytes;
+ for (i=0;i<p->niovecs && resid;i++) {
+ sz=MIN(resid, p->wirevec[i].iov_len);
+ error = mbuf_copydata(m, offset, sz, p->wirevec[i].iov_base);
+ if (error)
+ break;
+ resid-=sz;
+ offset+=sz;
+ noffset += sz;
+ }
+ }
+ } while (0);
+
+ mbuf_freem(m);
+
+ /* restore the vec to its correct state */
+ p->wirevec[p->niovecs - 1].iov_len = savelen;
+
+ if (error == EWOULDBLOCK && noffset > 0)
+ error = 0;
+
+ if (!error) {
+ int host, port;
+
+ nbytes -= resid;
+
+ if (sa->sa_family == AF_INET)
+ from = *(struct sockaddr_in *)sa;
+
+ p->length = nbytes - RX_HEADER_SIZE;;
+ if ((nbytes > tlen) || (p->length & 0x8000)) { /* Bogus packet */
+ if (nbytes <= 0) {
+ if (rx_stats_active) {
+ MUTEX_ENTER(&rx_stats_mutex);
+ rx_stats.bogusPacketOnRead++;
+ rx_stats.bogusHost = from.sin_addr.s_addr;
+ MUTEX_EXIT(&rx_stats_mutex);
+ }
+ dpf(("B: bogus packet from [%x,%d] nb=%d",
+ from.sin_addr.s_addr, from.sin_port, nbytes));
+ }
+ return;
+ } else {
+ /* Extract packet header. */
+ rxi_DecodePacketHeader(p);
+
+ host = from.sin_addr.s_addr;
+ port = from.sin_port;
+ if (p->header.type > 0 && p->header.type < RX_N_PACKET_TYPES) {
+ if (rx_stats_active) {
+ MUTEX_ENTER(&rx_stats_mutex);
+ rx_stats.packetsRead[p->header.type - 1]++;
+ MUTEX_EXIT(&rx_stats_mutex);
+ }
+ }
+
+#ifdef RX_TRIMDATABUFS
+ /* Free any empty packet buffers at the end of this packet */
+ rxi_TrimDataBufs(p, 1);
+#endif
+ /* receive pcket */
+ p = rxi_ReceivePacket(p, so, host, port, 0, 0);
+ }
+ }
+ /* free packet? */
+ if (p)
+ rxi_FreePacket(p);
+
+ return;
+}
+
+/* in listener env, the listener shutdown does this. we have no listener */
+void
+osi_StopNetIfPoller(void)
+{
+ soclose(rx_socket);
+ if (afs_termState == AFSOP_STOP_NETIF) {
+ afs_termState = AFSOP_STOP_COMPLETE;
+ osi_rxWakeup(&afs_termState);
+ }
+}
+#elif defined(RXK_LISTENER_ENV)
int
osi_NetReceive(osi_socket so, struct sockaddr_in *addr, struct iovec *dvec,
int nvecs, int *alength)
for (i = 0; i < nvecs; i++)
iov[i] = dvec[i];
+
+ if ((afs_termState == AFSOP_STOP_RXK_LISTENER) ||
+ (afs_termState == AFSOP_STOP_COMPLETE))
+ return -1;
+
if (haveGlock)
AFS_GUNLOCK();
#if defined(KERNEL_FUNNEL)
thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
#endif
#ifdef AFS_DARWIN80_ENV
-#if 1
resid = *alength;
memset(&msg, 0, sizeof(struct msghdr));
msg.msg_name = &ss;
}
mbuf_freem(m);
#else
- resid = *alength;
- printf("Want to read %d bytes...", resid);
- for (i=0; i < nvecs && resid; i++) {
- if (resid < iov[i].iov_len)
- iov[0].iov_len = resid;
- resid -= iov[i].iov_len;
- }
- printf("Using %d/%d iovs\n", i, nvecs);
- nvecs = i;
- rlen = 0;
- memset(&msg, 0, sizeof(struct msghdr));
- msg.msg_name = &ss;
- msg.msg_namelen = sizeof(struct sockaddr_storage);
- msg.msg_iov = &iov[0];
- msg.msg_iovlen = nvecs;
- sa =(struct sockaddr_in *) &ss;
- code = sock_receive(asocket, &msg, 0, &rlen);
- resid = *alength;
- if (resid != rlen)
- printf("recieved %d bytes\n", rlen);
- if (resid > rlen)
- resid -= rlen;
- else
- resid = 0;
-#endif
-#else
u.uio_iov = &iov[0];
u.uio_iovcnt = nvecs;
*addr = *(struct sockaddr_in *)sa;
} else
printf("Unknown socket family %d in NetReceive\n", sa->sa_family);
+#ifndef AFS_DARWIN80_ENV
FREE(sa, M_SONAME);
+#endif
}
return code;
}
psignal(p, SIGUSR1);
#endif
}
+#else
+#error need upcall or listener
+#endif
int
osi_NetSend(osi_socket so, struct sockaddr_in *addr, struct iovec *dvec,
struct socket *asocket = (struct socket *)so;
struct uio u;
#endif
- register afs_int32 code;
+ afs_int32 code;
int i;
struct iovec iov[RX_MAXIOVECS];
int haveGlock = ISAFS_GLOCK();
addr->sin_len = sizeof(struct sockaddr_in);
+ if ((afs_termState == AFSOP_STOP_RXK_LISTENER) ||
+ (afs_termState == AFSOP_STOP_COMPLETE))
+ return -1;
+
if (haveGlock)
AFS_GUNLOCK();
+
#if defined(KERNEL_FUNNEL)
thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
#endif