NMErr OTIPEnumerator::ReceiveDatagram(void) { DEBUG_ENTRY_EXIT("IPEnumerator::ReceiveDatagram"); NMErr status = kNMNoError; OTResult result; OTFlags flags = 0; do { result = OTRcvUData(mEP, &mIncomingData, &flags); if (result == kOTLookErr) HandleLookErr(); else if (result == kNMNoError) HandleReply(mIncomingData.udata.buf, mIncomingData.udata.len, (InetAddress *) mIncomingData.addr.buf); } while (result != kNMNoError && result == kOTLookErr); if (result == kOTNoDataErr) bDataWaiting = false; return status; }
/* Receive a vector of pending packets from the UDP socket. The returned packets contain the source address and the channel they arrived on. If they did not arrive on a bound channel, the the channel will be set to -1. This function returns the number of packets read from the network, or -1 on error. This function does not block, so can return 0 packets pending. */ extern int SDLNet_UDP_RecvV(UDPsocket sock, UDPpacket **packets) { int numrecv, i, j; struct UDP_channel *binding; #ifdef MACOS_OPENTRANSPORT TUnitData OTpacket; OTFlags flags; InetAddress address; #else int sock_len; struct sockaddr_in sock_addr; #endif numrecv = 0; while ( packets[numrecv] && SocketReady(sock->channel) ) { UDPpacket *packet; packet = packets[numrecv]; #ifdef MACOS_OPENTRANSPORT memset(&OTpacket, 0, sizeof(OTpacket)); OTpacket.addr.buf = (Uint8 *)&address; OTpacket.addr.maxlen = (sizeof address); OTpacket.udata.buf = packet->data; OTpacket.udata.maxlen = packet->maxlen; packet->status = OTRcvUData(sock->channel, &OTpacket, &flags); #ifdef DEBUG_NET printf("Packet status: %d\n", packet->status); #endif AsyncUDPPopEvent(sock); if (packet->status == noErr) { packet->len = OTpacket.udata.len; packet->address.host = address.fHost; packet->address.port = address.fPort; #ifdef DEBUG_NET printf("Packet address: 0x%8.8x:%d, length = %d\n", packet->address.host, packet->address.port, packet->len); #endif } #else sock_len = sizeof(sock_addr); packet->status = recvfrom(sock->channel, packet->data, packet->maxlen, 0, (struct sockaddr *)&sock_addr, #ifdef USE_GUSI_SOCKETS (unsigned int *)&sock_len); #else &sock_len); #endif if ( packet->status >= 0 ) { packet->len = packet->status; packet->address.host = sock_addr.sin_addr.s_addr; packet->address.port = sock_addr.sin_port; } #endif if (packet->status >= 0) { packet->channel = -1; for (i=(SDLNET_MAX_UDPCHANNELS-1); i>=0; --i ) { binding = &sock->binding[i]; for ( j=binding->numbound-1; j>=0; --j ) { if ( (packet->address.host == binding->address[j].host) && (packet->address.port == binding->address[j].port) ) { packet->channel = i; goto foundit; /* break twice */ } } } foundit: ++numrecv; } else { packet->len = 0; } } sock->ready = 0; return(numrecv); }
// Errors: // EBADF -- bad socket id // EFAULT -- bad buffer static PRInt32 SendReceiveDgram(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout, SndRcvOpCode opCode) { OSStatus err; PRInt32 osfd = fd->secret->md.osfd; EndpointRef endpoint = (EndpointRef) osfd; PRThread *me = _PR_MD_CURRENT_THREAD(); PRInt32 bytesLeft = amount; TUnitData dgram; PR_ASSERT(flags == 0); if (endpoint == NULL) { err = kEBADFErr; goto ErrorExit; } if (buf == NULL || addr == NULL) { err = kEFAULTErr; goto ErrorExit; } memset(&dgram, 0 , sizeof(dgram)); dgram.addr.maxlen = *addrlen; dgram.addr.len = *addrlen; dgram.addr.buf = (UInt8*) addr; dgram.udata.maxlen = amount; dgram.udata.len = amount; dgram.udata.buf = (UInt8*) buf; while (bytesLeft > 0) { PrepareThreadForAsyncIO(me, endpoint, osfd); if (opCode == kDGRAM_SEND) err = OTSndUData(endpoint, &dgram); else if (opCode == kDGRAM_RECEIVE) err = OTRcvUData(endpoint, &dgram, NULL); else { err = kEINVALErr; goto ErrorExit; } if (err == kOTNoError) { buf = (void *) ( (UInt32) buf + (UInt32)dgram.udata.len ); bytesLeft -= dgram.udata.len; dgram.udata.buf = (UInt8*) buf; me->io_pending = PR_FALSE; } else { PR_ASSERT(err == kOTNoDataErr || err == kOTOutStateErr); WaitOnThisThread(me, timeout); err = me->md.osErrCode; if (err != kOTNoError) goto ErrorExit; PR_ASSERT(me->md.cookie != NULL); } } if (opCode == kDGRAM_RECEIVE) *addrlen = dgram.addr.len; return amount; ErrorExit: macsock_map_error(err); return -1; }
/* Here's where we actually do the read. This is called by our notifier, so it will run at "deferred task time", i.e., interrupt level. */ void otudp_read(OTUDP *x) { TUnitData unitdata; OTFlags flags; OSStatus err; OTBuffer *theOTBuffer; long shouldCheckAgain; PacketBuffer myPB; UInt8 *bufferToUse; int i; int numPacketsThisTime; short oldLockout; // post("** Entering otudp_read"); // Set up the data structures OT wants to put the incoming data into unitdata.addr.maxlen = sizeof(struct InetAddress); unitdata.opt.maxlen = 0; unitdata.opt.buf = 0; unitdata.udata.maxlen = x->bufsize; // Mutual exclusion: Make sure that neither Max not Open Transport will interrupt // this until we've read all there is to read. That makes it safe to access the global // buffer lists in my object. oldLockout = AcquireLock(x); numPacketsThisTime = 0; shouldCheckAgain = 1; // By default, after we do one read we should do another while (shouldCheckAgain) { // Try to allocate an available PacketBuffer myPB = PacketBufferListPop(&(x->freeBuffers)); if (myPB == 0) { // Out of buffers, but we're still going to do the read just so we can // drop the packet (gracefully) without Open Transport blowing up. if (x->o_errorreporting) { if (!(x->o_num_dropped_packets)) { error("otudp: Out of packet buffers; have to drop packet(s)"); } ++(x->o_num_dropped_packets); x->o_ever_dropped_a_packet = 1; } unitdata.udata.buf = DevNullBuffer; unitdata.addr.buf = DevNullBuffer; } else { unitdata.udata.buf = (UInt8 *) myPB->buf; unitdata.addr.buf = (UInt8*) &(myPB->returnAddress); } // post("** About to call OTRcvUData"); err = OTRcvUData(x->o_udp_ep, &unitdata, &flags); if (err == kOTNoError ) { if (flags == 0) { if (myPB != 0) { myPB->n = unitdata.udata.len; PBFIFOEnqueue(myPB, &(x->pendingBuffers)); ++numPacketsThisTime; clock_delay(x->o_clock, 0); } } else if (flags == T_MORE) { // Only the beginning of the (large) UDP packet fit in our buffer if (x->o_errorreporting) { error("OTUDP: packet too big; dropping."); } ++numPacketsThisTime; while (flags == T_MORE) { err = OTRcvUData(x->o_udp_ep, &unitdata, &flags); } if (myPB) PacketBufferListPush(myPB, &(x->freeBuffers)); } else { if (x->o_errorreporting) { error("OTUDP: OTRcvUData returned flags of %ld; dropped packet", (long) flags); } if (myPB) PacketBufferListPush(myPB, &(x->freeBuffers)); } } else if ( err == kOTNoDataErr ) { /* We're supposed to keep trying to read incoming data until we get this "error", so it's not really an error; it just says we've read enough for now. */ shouldCheckAgain = 0; if (myPB) { PacketBufferListPush(myPB, &(x->freeBuffers)); } else { // We're out of buffers, but we didn't actually need one, so we need to un-count // this as a dropped packet --(x->o_num_dropped_packets); } } else { error("OTUDP: OTRcvUData returned error %ld; dropped packet", (long) err); if (myPB) PacketBufferListPush(myPB, &(x->freeBuffers)); } } end: ReleaseLock(x, oldLockout); /* if (numPacketsThisTime > 1) { post("* Read %ld packets in one call to otudp_read", numPacketsThisTime); } */ }