PRInt32 _MD_accept(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout) { PRInt32 osfd = fd->secret->md.osfd; OSStatus err; EndpointRef endpoint = (EndpointRef) osfd; PRThread *me = _PR_MD_CURRENT_THREAD(); TBind bindReq; PRNetAddr bindAddr; PRInt32 newosfd = -1; EndpointRef newEndpoint; TCall call; PRNetAddr callAddr; if (endpoint == NULL) { err = kEBADFErr; goto ErrorExit; } memset(&call, 0 , sizeof(call)); call.addr.maxlen = PR_NETADDR_SIZE(&callAddr); call.addr.len = PR_NETADDR_SIZE(&callAddr); call.addr.buf = (UInt8*) &callAddr; PrepareThreadForAsyncIO(me, endpoint, osfd); err = OTListen (endpoint, &call); if (err != kOTNoError && (err != kOTNoDataErr || fd->secret->nonblocking)) { me->io_pending = PR_FALSE; goto ErrorExit; } while (err == kOTNoDataErr) { WaitOnThisThread(me, timeout); err = me->md.osErrCode; if (err != kOTNoError) goto ErrorExit; PrepareThreadForAsyncIO(me, endpoint, osfd); err = OTListen (endpoint, &call); if (err == kOTNoError) break; PR_ASSERT(err == kOTNoDataErr); } newosfd = _MD_socket(AF_INET, SOCK_STREAM, 0); if (newosfd == -1) return -1; newEndpoint = (EndpointRef)newosfd; // Bind to a local port; let the system assign it. bindAddr.inet.port = bindAddr.inet.ip = 0; bindReq.addr.maxlen = PR_NETADDR_SIZE (&bindAddr); bindReq.addr.len = 0; bindReq.addr.buf = (UInt8*) &bindAddr; bindReq.qlen = 0; PrepareThreadForAsyncIO(me, newEndpoint, newosfd); err = OTBind(newEndpoint, &bindReq, NULL); if (err != kOTNoError) goto ErrorExit; WaitOnThisThread(me, timeout); err = me->md.osErrCode; if (err != kOTNoError) goto ErrorExit; PrepareThreadForAsyncIO(me, endpoint, newosfd); err = OTAccept (endpoint, newEndpoint, &call); if (err != kOTNoError) goto ErrorExit; WaitOnThisThread(me, timeout); err = me->md.osErrCode; if (err != kOTNoError) goto ErrorExit; PR_ASSERT(me->md.cookie != NULL); if (addr != NULL) *addr = callAddr; if (addrlen != NULL) *addrlen = call.addr.len; return newosfd; ErrorExit: if (newosfd != -1) _MD_closesocket(newosfd); macsock_map_error(err); return -1; }
/* Accept an incoming connection on the given server socket. The newly created socket is returned, or NULL if there was an error. */ TCPsocket SDLNet_TCP_Accept(TCPsocket server) { /* Only server sockets can accept */ if ( ! server->sflag ) { SDLNet_SetError("Only server sockets can accept()"); return(NULL); } server->ready = 0; /* Accept a new TCP connection on a server socket */ { InetAddress peer; TCall peerinfo; TCPsocket sock = NULL; Boolean mustListen = false; OTResult err; memset(&peerinfo, 0, (sizeof peerinfo )); peerinfo.addr.buf = (Uint8 *) &peer; peerinfo.addr.maxlen = sizeof(peer); while( mustListen || !sock ) { // OTListen // We do NOT block ---- right thing ? (TODO) err = OTListen( server->channel, &peerinfo ); if( err ) goto error_return; else { mustListen = false; sock = AsyncTCPNewSocket(); if( ! sock ) goto error_return; } } if( sock ) { // OTAsyncOpenEndpoint server->error = OTAsyncOpenEndpoint( OTCloneConfiguration( server->config ), NULL, &(sock->info), (OTNotifyProcPtr)AsyncTCPNotifier, sock ); AsyncTCPPopEvent( sock ); while( !sock->error && !( sock->completion & CompleteMask( T_OPENCOMPLETE))) { AsyncTCPPopEvent( sock ); } if( ! sock->channel ) { mustListen = false; goto error_return; } // OTAccept server->completion &= ~(CompleteMask(T_ACCEPTCOMPLETE)); server->error = OTAccept( server->channel, sock->channel, &peerinfo ); AsyncTCPPopEvent( server ); while( !(server->completion & CompleteMask(T_ACCEPTCOMPLETE))) { AsyncTCPPopEvent( server ); } switch( server->error ) { case kOTLookErr: switch( OTLook(server->channel )) { case T_LISTEN: mustListen = true; break; case T_DISCONNECT: goto error_return; } break; case 0: sock->nextListener = server->nextListener; server->nextListener = sock; sock->remoteAddress.host = peer.fHost; sock->remoteAddress.port = peer.fPort; return sock; // accept successful break; default: free( sock ); } } sock->remoteAddress.host = peer.fHost; sock->remoteAddress.port = peer.fPort; sock->sflag = 0; sock->ready = 0; /* The socket is ready */ return(sock); // Error; close the socket and return error_return: SDLNet_TCP_Close(sock); return(NULL); } }