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_atomic_inc(&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) { rx_atomic_inc(&rx_stats.packetsRead[p->header.type - 1]); } } #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; }
static void rxi_ListenerProc(fd_set * rfds, int *tnop, struct rx_call **newcallp) { afs_uint32 host; u_short port; struct rx_packet *p = (struct rx_packet *)0; osi_socket socket; struct clock cv; afs_int32 nextPollTime; /* time to next poll FD before sleeping */ int lastPollWorked, doingPoll; /* true iff last poll was useful */ struct timeval tv, *tvp; int code; #ifdef AFS_NT40_ENV int i; #endif PROCESS pid; char name[MAXTHREADNAMELENGTH] = "srv_0"; clock_NewTime(); lastPollWorked = 0; nextPollTime = 0; code = LWP_CurrentProcess(&pid); if (code) { fprintf(stderr, "rxi_Listener: Can't get my pid.\n"); exit(1); } rx_listenerPid = pid; if (swapNameProgram) (*swapNameProgram) (pid, "listener", &name[0]); for (;;) { /* Grab a new packet only if necessary (otherwise re-use the old one) */ if (p) { rxi_RestoreDataBufs(p); } else { if (!(p = rxi_AllocPacket(RX_PACKET_CLASS_RECEIVE))) osi_Panic("rxi_ListenerProc: no packets!"); /* Shouldn't happen */ } /* Wait for the next event time or a packet to arrive. */ /* event_RaiseEvents schedules any events whose time has come and * then atomically computes the time to the next event, guaranteeing * that this is positive. If there is no next event, it returns 0 */ clock_NewTime(); if (!rxevent_RaiseEvents(&cv)) tvp = NULL; else { /* It's important to copy cv to tv, because the 4.3 documentation * for select threatens that *tv may be updated after a select, in * future editions of the system, to indicate how much of the time * period has elapsed. So we shouldn't rely on tv not being altered. */ tv.tv_sec = cv.sec; /* Time to next event */ tv.tv_usec = cv.usec; tvp = &tv; } rx_AtomicIncrement(rx_stats.selects, rx_stats_mutex); *rfds = rx_selectMask; if (lastPollWorked || nextPollTime < clock_Sec()) { /* we're catching up, or haven't tried to for a few seconds */ doingPoll = 1; nextPollTime = clock_Sec() + 4; /* try again in 4 seconds no matter what */ tv.tv_sec = tv.tv_usec = 0; /* make sure we poll */ tvp = &tv; code = select((int)(rx_maxSocketNumber + 1), rfds, 0, 0, tvp); } else { doingPoll = 0; code = IOMGR_Select((int)(rx_maxSocketNumber + 1), rfds, 0, 0, tvp); } lastPollWorked = 0; /* default is that it didn't find anything */ if (quitListening) { quitListening = 0; LWP_DestroyProcess(pid); } switch (code) { case 0: /* Timer interrupt: * If it was a timer interrupt then we can assume that * the time has advanced by roughly the value of the * previous timeout, and that there is now at least * one pending event. */ clock_NewTime(); break; case -1: /* select or IOMGR_Select returned failure */ debugSelectFailure++; /* update debugging counter */ clock_NewTime(); break; case -2: /* IOMGR_Cancel: * IOMGR_Cancel is invoked whenever a new event is * posted that is earlier than any existing events. * So we re-evaluate the time, and then go back to * reschedule events */ clock_NewTime(); break; default: /* Packets have arrived, presumably: * If it wasn't a timer interrupt, then no event should have * timed out yet (well some event may have, but only just...), so * we don't bother looking to see if any have timed out, but just * go directly to reading the data packets */ clock_NewTime(); if (doingPoll) lastPollWorked = 1; #ifdef AFS_NT40_ENV for (i = 0; p && i < rfds->fd_count; i++) { socket = rfds->fd_array[i]; if (rxi_ReadPacket(socket, p, &host, &port)) { *newcallp = NULL; p = rxi_ReceivePacket(p, socket, host, port, tnop, newcallp); if (newcallp && *newcallp) { if (p) { rxi_FreePacket(p); } if (swapNameProgram) { (*swapNameProgram) (rx_listenerPid, name, 0); rx_listenerPid = 0; } return; } } } #else for (socket = rx_minSocketNumber; p && socket <= rx_maxSocketNumber; socket++) { if (!FD_ISSET(socket, rfds)) continue; if (rxi_ReadPacket(socket, p, &host, &port)) { p = rxi_ReceivePacket(p, socket, host, port, tnop, newcallp); if (newcallp && *newcallp) { if (p) { rxi_FreePacket(p); } if (swapNameProgram) { (*swapNameProgram) (rx_listenerPid, name, 0); rx_listenerPid = 0; } return; } } } #endif break; } } /* NOTREACHED */ }