static OSErr CreateSocket(int type, EndpointRef *endpoint) { OSStatus err; PRThread *me = _PR_MD_CURRENT_THREAD(); switch (type){ case SOCK_STREAM: err = OTAsyncOpenEndpoint(OTCreateConfiguration(kTCPName), 0, NULL, NotifierRoutine, me); break; case SOCK_DGRAM: err = OTAsyncOpenEndpoint(OTCreateConfiguration(kUDPName), 0, NULL, NotifierRoutine, me); break; } if (err != kOTNoError) goto ErrorExit; WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); err = me->md.osErrCode; if (err != kOTNoError) goto ErrorExit; *endpoint = me->md.cookie; PR_ASSERT(*endpoint != NULL); return kOTNoError; ErrorExit: return err; }
NMErr EndpointHander::GetStreamEP(void) { DEBUG_ENTRY_EXIT("EndpointHander::GetStreamEP"); CachedEP *streamEP = NULL; OTLink *acceptorLink = NULL; NMErr status = kNMNoError; //Try_ { // Get a cached stream ep acceptorLink = OTLIFODequeue(&OTEndpoint::sStreamEPCache.Q); //if there was an available one in the cache if (acceptorLink) { OTAtomicAdd32(-1, &OTEndpoint::sStreamEPCache.readyCount); OTAtomicAdd32(-1, &OTEndpoint::sStreamEPCache.totalCount); //jacked up and good to go mState |= kGotStreamEP; //get the cache reloading itself OTEndpoint::ServiceEPCaches(); } //otherwise, make one now else { return OTAsyncOpenEndpoint(OTCreateConfiguration(mListenerEP->GetStreamProtocolName()), 0, NULL, mNotifier.fUPP, this); } // Get the pointer to the cached ep object streamEP = OTGetLinkObject(acceptorLink, CachedEP, link); op_assert(streamEP != NULL); // Remove the notifier that was being used for cacheing and install the "normal" one OTRemoveNotifier(streamEP->ep); OTInstallNotifier(streamEP->ep, mNotifier.fUPP, this); mNewEP->mStreamEndpoint->mEP = streamEP->ep; delete streamEP; } //Catch_(code) error: if (status) { NMErr code = status; return code; } mState |= kStreamDone; return kNMNoError; }
/* Open a UDP network socket If 'port' is non-zero, the UDP socket is bound to a fixed local port. */ extern UDPsocket SDLNet_UDP_Open(Uint16 port) { UDPsocket sock; #ifdef MACOS_OPENTRANSPORT EndpointRef dummy = NULL; #endif /* Allocate a UDP socket structure */ sock = (UDPsocket)malloc(sizeof(*sock)); if ( sock == NULL ) { SDLNet_SetError("Out of memory"); goto error_return; } memset(sock, 0, sizeof(*sock)); /* Open the socket */ #ifdef MACOS_OPENTRANSPORT { sock->error = OTAsyncOpenEndpoint( OTCreateConfiguration(kUDPName),0, &(sock->info), (OTNotifyProcPtr)AsyncUDPNotifier, sock ); AsyncUDPPopEvent( sock ); while( !sock->error && !( sock->completion & CompleteMask(T_OPENCOMPLETE))) { AsyncUDPPopEvent( sock ); } if( sock->error ) { SDLNet_SetError("Could not open UDP socket"); goto error_return; } // Should we ?? // (01/05/03 minami<*****@*****.**> OTSetBlocking( sock->channel ); } #else sock->channel = socket(AF_INET, SOCK_DGRAM, 0); #endif /* MACOS_OPENTRANSPORT */ if ( sock->channel == INVALID_SOCKET ) { SDLNet_SetError("Couldn't create socket"); goto error_return; } #ifdef MACOS_OPENTRANSPORT { InetAddress required, assigned; TBind req_addr, assigned_addr; OSStatus status; InetInterfaceInfo info; memset(&assigned_addr, 0, sizeof(assigned_addr)); assigned_addr.addr.maxlen = sizeof(assigned); assigned_addr.addr.len = sizeof(assigned); assigned_addr.addr.buf = (UInt8 *) &assigned; if ( port ) { status = OTInetGetInterfaceInfo( &info, kDefaultInetInterface ); if( status != kOTNoError ) goto error_return; OTInitInetAddress(&required, port, info.fAddress ); req_addr.addr.maxlen = sizeof( required ); req_addr.addr.len = sizeof( required ); req_addr.addr.buf = (UInt8 *) &required; sock->error = OTBind(sock->channel, &req_addr, &assigned_addr); } else { sock->error = OTBind(sock->channel, nil, &assigned_addr ); } AsyncUDPPopEvent(sock); while( !sock->error && !(sock->completion & CompleteMask(T_BINDCOMPLETE))) { AsyncUDPPopEvent(sock); } if (sock->error != noErr) { SDLNet_SetError("Couldn't bind to local port, OTBind() = %d",(int) status); goto error_return; } sock->address.host = assigned.fHost; sock->address.port = assigned.fPort; #ifdef DEBUG_NET printf("UDP open host = %d, port = %d\n", assigned.fHost, assigned.fPort ); #endif } #else /* Bind locally, if appropriate */ if ( port ) { struct sockaddr_in sock_addr; memset(&sock_addr, 0, sizeof(sock_addr)); sock_addr.sin_family = AF_INET; sock_addr.sin_addr.s_addr = INADDR_ANY; sock_addr.sin_port = SDL_SwapBE16(port); /* Bind the socket for listening */ if ( bind(sock->channel, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) == SOCKET_ERROR ) { SDLNet_SetError("Couldn't bind to local port"); goto error_return; } /* Fill in the channel host address */ sock->address.host = sock_addr.sin_addr.s_addr; sock->address.port = sock_addr.sin_port; } /* Allow LAN broadcasts with the socket */ { int yes = 1; setsockopt(sock->channel, SOL_SOCKET, SO_BROADCAST, (char*)&yes, sizeof(yes)); } #endif /* MACOS_OPENTRANSPORT */ /* The socket is ready */ return(sock); error_return: #ifdef MACOS_OPENTRANSPORT if( dummy ) OTCloseProvider( dummy ); #endif SDLNet_UDP_Close(sock); return(NULL); }
void *ottcp_new(Symbol *s, short argc, Atom *argv) { OTTCP *x; OSStatus err; // These variables will be filled with the args we parse char *inetHostName = 0; InetPort port = 0; long readbufsize = DEFAULT_BUFFER_SIZE; long writebufsize = DEFAULT_BUFFER_SIZE; EnterCallback(); if (ParseArgs(argc, argv, &inetHostName, &port, &readbufsize, &readbufsize) == 0) { ouchstring("ottcp usage: \"ottcp [<hostname> <port>] [readbufsize <nbytes>] [writebufsize <nbytes>]\""); ExitCallback(); return 0; } post("Parsed args: inetHostName %s, port %ld, readbufsize %ld, writebufsize %ld", inetHostName, port, readbufsize, writebufsize); x = newobject(ottcp_class); x->o_a5 = (long) LMGetCurrentA5(); x->o_inetHostName = inetHostName; x->o_inetPort = port; x->o_inetHost = 0; if (x->o_inetHostName != 0) { // They gave the server's IP address and port # as arguments if (LookUpInetHost(x->o_inetHostName, &(x->o_inetHost)) == 0) { post("е OTTCP: can't understand host \"%s\"; not connecting", x->o_inetHostName); } } x->o_state = SETTING_UP; x->o_datawaiting = 0; x->o_errorreporting = 1; x->o_outlet = outlet_new(x,0L); x->o_clock = clock_new(x, (method) do_output); x->o_connectedclock = clock_new(x, (method) do_output_connected); x->o_connectionSymbol = 0; OTClearLock(&(x->o_readlock)); /* Allocate buffers */ x->o_ReadBufSize = readbufsize; x->o_WriteBufSize = writebufsize; x->o_ReadBufA = NewPtr(readbufsize); x->o_ReadBufB = NewPtr(readbufsize); x->o_WriteBuf = NewPtr(writebufsize); if (x->o_ReadBufA == 0 || x->o_ReadBufB == 0 || x->o_WriteBuf == 0) { ouchstring("ottcp: not enough memory for two %ld byte read buffers and a %ld byte write buffer.", readbufsize, writebufsize); } x->o_currentReadBuf = x->o_ReadBufA; x->o_nextReadBuf = x->o_ReadBufB; x->o_bytesRead = 0; x->o_bytesReadForNextTime = 0; x->o_WBReadPos = 0; x->o_WBWritePos = 0; /* Make the endpoint */ x->o_tcp_ep = 0; // Indicates endpoint hasn't been created yet. err = OTAsyncOpenEndpoint(OTCreateConfiguration(kTCPName), 0, &(x->epinfo), OTTCPNotifier, x); if (err != noErr) { ouchstring("otudp: Error %d from OTAsyncOpenEndpoint. This is bad.", err); return 0; } // This didn't actually make the endpoint; my notifier should get the T_OPENCOMPLETE // event after the endpoint is opened. ExitCallback(); return (x); }
/* 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); } }
/* Open a TCP network socket If 'remote' is NULL, this creates a local server socket on the given port, otherwise a TCP connection to the remote host and port is attempted. The newly created socket is returned, or NULL if there was an error. ( re-written by masahiro minami<*****@*****.**> Now endpoint is created in Async mode. 01/02/20 ) */ TCPsocket SDLNet_TCP_Open(IPaddress *ip) { EndpointRef dummy = NULL; TCPsocket sock = AsyncTCPNewSocket(); if( ! sock) return NULL; // Determin whether bind locally, or connect to remote if ( (ip->host != INADDR_NONE) && (ip->host != INADDR_ANY) ) { // ######## Connect to remote OTResult stat; InetAddress inAddr; TBind bindReq; // Open endpoint sock->error = OTAsyncOpenEndpoint( OTCreateConfiguration(kTCPName), NULL, &(sock->info), (OTNotifyProcPtr)(AsyncTCPNotifier), sock ); AsyncTCPPopEvent( sock ); while( !sock->error && !( sock->completion & CompleteMask(T_OPENCOMPLETE))) { //SetThreadState( kCurrentThreadID, kReadyThreadState, kNoThreadID ); //YieldToAnyThread(); //WaitNextEvent(everyEvent, &macEvent, 1, NULL); AsyncTCPPopEvent( sock ); } if( !sock->channel ) { SDLNet_SetError("OTAsyncOpenEndpoint failed --- client socket could not be opened"); goto error_return; } // Set blocking mode // I'm not sure if this is a good solution.... // Check out Apple's sample code, OT Virtual Server // ( 010314 masahiro minami<*****@*****.**>) sock->error = OTSetBlocking( sock->channel ); if( sock->error != kOTNoError ) { SDLNet_SetError("OTSetBlocking() returned an error"); goto error_return; } // Bind the socket OTInitInetAddress(&inAddr, 0, 0 ); bindReq.addr.len = sizeof( InetAddress ); bindReq.addr.buf = (unsigned char*)&inAddr; bindReq.qlen = 0; sock->error = OTBind( sock->channel, &bindReq, NULL ); AsyncTCPPopEvent(sock); while( !sock->error && !( sock->completion & CompleteMask(T_BINDCOMPLETE))) { //YieldToAnyThread(); //WaitNextEvent(everyEvent, &macEvent, 1, NULL); AsyncTCPPopEvent(sock); } switch( stat = OTGetEndpointState( sock->channel )) { InetAddress inAddr; TCall sndCall; OTResult res; case T_OUTCON: SDLNet_SetError("SDLNet_Open() failed -- T_OUTCON"); goto error_return; break; case T_IDLE: sock->readShutdown = false; sock->writeShutdown = false; sock->event &=~T_CONNECT; OTMemzero(&sndCall, sizeof(TCall)); OTInitInetAddress(&inAddr, ip->port, ip->host ); sndCall.addr.len = sizeof(InetAddress); sndCall.addr.buf = (unsigned char*)&inAddr; sock->connected = 0; res = OTConnect( sock->channel, &sndCall, NULL ); AsyncTCPPopEvent(sock); while( sock->error == kOTNoDataErr || !sock->connected ) AsyncTCPPopEvent(sock); break; default: // What's to be done ? (TODO) SDLNet_SetError("SDLNet_TCP_Open() failed -- EndpointState not good"); goto error_return; } if( !(sock->event & (T_CONNECT|T_DISCONNECT))) goto error_return; AsyncTCPPopEvent( sock ); while( !(sock->event & (T_CONNECT|T_DISCONNECT))) { AsyncTCPPopEvent( sock ); } // OTConnect successfull if( sock->event & T_CONNECT) { sock->remoteAddress.host = inAddr.fHost; sock->remoteAddress.port = inAddr.fPort; sock->sflag = false; } else { // OTConnect failed sock->event &= ~T_DISCONNECT; goto error_return; } } else { // ######## Bind locally TBind bindReq; InetAddress inAddr; // First, get InetInterfaceInfo. // I don't search for all of them. // Does that matter ? sock->error = OTAsyncOpenEndpoint( OTCreateConfiguration("tilisten, tcp"), NULL, &(sock->info), (OTNotifyProcPtr)(AsyncTCPNotifier), sock); AsyncTCPPopEvent( sock ); while( !sock->error && !( sock->completion & CompleteMask( T_OPENCOMPLETE))) { AsyncTCPPopEvent( sock ); } if( ! sock->channel ) { SDLNet_SetError("OTAsyncOpenEndpoint failed --- server socket could not be opened"); goto error_return; } // Create a master OTConfiguration sock->config = OTCreateConfiguration(kTCPName); if( ! sock->config ) { SDLNet_SetError("Could not create master OTConfiguration"); goto error_return; } // Bind the socket OTInitInetAddress(&inAddr, ip->port, 0 ); inAddr.fAddressType = AF_INET; bindReq.addr.len = sizeof( InetAddress ); bindReq.addr.buf = (unsigned char*)&inAddr; bindReq.qlen = 35; // This number is NOT well considered. (TODO) sock->localAddress.host = inAddr.fHost; sock->localAddress.port = inAddr.fPort; sock->sflag = true; sock->error = OTBind( sock->channel, &bindReq, NULL ); AsyncTCPPopEvent(sock); while( !sock->error && !( sock->completion & CompleteMask(T_BINDCOMPLETE))) { AsyncTCPPopEvent(sock); } if( sock->error != kOTNoError ) { SDLNet_SetError("Could not bind server socket"); goto error_return; } if( dummy ) OTCloseProvider( dummy ); } sock->ready = 0; return sock; error_return: if( dummy ) OTCloseProvider( dummy ); SDLNet_TCP_Close( sock ); return NULL; }
pascal void EndpointHander::Notifier( void *contextPtr, OTEventCode code, OTResult result, void *cookie) { NMErr status; DEBUG_ENTRY_EXIT("EndpointHander::Notifier"); EndpointHander *epHander = (EndpointHander *) contextPtr; UNUSED_PARAMETER(result); switch (code) { case T_OPENCOMPLETE: // one of our endpoints finished opening //if we were waiting on the stream ep, move on to the datagram ep if necessary if (!(epHander->mState & kGotStreamEP)) { epHander->mNewEP->mStreamEndpoint->mEP = (EndpointRef)cookie; epHander->mState |= kGotStreamEP; if (!(epHander->mState & kGotDatagramEP)) { OTAsyncOpenEndpoint(OTCreateConfiguration(epHander->mListenerEP->GetDatagramProtocolName()), 0, NULL, epHander->mNotifier.fUPP, contextPtr); } } //it must be our datagram ep that's done else { epHander->mNewEP->mDatagramEndpoint->mEP = (EndpointRef)cookie; epHander->mState |= kGotDatagramEP; } //once both eps are done, we go ahead and bind if ((epHander->mState & kGotStreamEP) && (epHander->mState & kGotDatagramEP)) { // Bind the endpoint. Execution continues in the notifier for T_BINDCOMPLETE epHander->mBindReq.addr.len = 0; epHander->mBindReq.addr.buf = NULL; epHander->mBindRet.addr = epHander->mNewEP->mDatagramEndpoint->mLocalAddress; //ECF011114 caused problems under MacOSX... status = OTBind(epHander->mNewEP->mDatagramEndpoint->mEP, NULL, &epHander->mBindRet); //status = OTBind(epHander->mNewEP->mDatagramEndpoint->mEP, &epHander->mBindReq, &epHander->mBindRet); DEBUG_NETWORK_API(epHander->mNewEP->mDatagramEndpoint->mEP, "OTBind", status); } break; case T_BINDCOMPLETE: // The datagram endpoint has finished epHander->mState |= kDatagramDone; // by this time, we should have both endpoints ready to go op_assert(epHander->mState & (kStreamDone | kDatagramDone) == (kStreamDone | kDatagramDone)); // we got the local address from the bind epHander->mState |= kDatagramLocalAddr; // Now that everything is ready, accept the connection epHander->Finish(); break; default: break; } }
NMErr EndpointHander::GetDatagramEP(void) { DEBUG_ENTRY_EXIT("EndpointHander::GetDatagramEP"); CachedEP *datagramEP = NULL; OTLink *acceptorLink = NULL; NMErr status = kNMNoError; // if we're not in uber mode, there should be no datagram ep // just jump to the notifier if (mNewEP->mMode != kNMNormalMode) { Notifier(this, T_BINDCOMPLETE, kNMNoError, NULL); return kNMNoError; } //Try_ { // Get a datagram endpoint from the cache acceptorLink = OTLIFODequeue(&OTEndpoint::sDatagramEPCache.Q); if (acceptorLink) { OTAtomicAdd32(-1, &OTEndpoint::sDatagramEPCache.readyCount); OTAtomicAdd32(-1, &OTEndpoint::sDatagramEPCache.totalCount); //jacked up and good to go mState |= kGotDatagramEP; //get the cache reloading itself OTEndpoint::ServiceEPCaches(); } //if we couldn't get one off the cache, we'll make one after we have a stream endpoint // (one at a time for simplicity) else { if (mState & kGotStreamEP) { return OTAsyncOpenEndpoint(OTCreateConfiguration(mListenerEP->GetDatagramProtocolName()), 0, NULL, mNotifier.fUPP, this); } return kNMNoError; //we just wait for the stream endpoint to get done } // Get the pointer to the cached ep object datagramEP = OTGetLinkObject(acceptorLink, CachedEP, link); op_assert(datagramEP != NULL); // Remove the notifier that was being used for cacheing and install the "normal" one OTRemoveNotifier(datagramEP->ep); OTInstallNotifier(datagramEP->ep, mNotifier.fUPP, this); mNewEP->mDatagramEndpoint->mEP = datagramEP->ep; delete datagramEP; //if we got both endpoints, go ahead and bind here if (mState & kGotStreamEP) { // Bind the endpoint. Execution continues in the notifier for T_BINDCOMPLETE mBindReq.addr.len = 0; mBindReq.addr.buf = NULL; mBindRet.addr = mNewEP->mDatagramEndpoint->mLocalAddress; status = OTBind(mNewEP->mDatagramEndpoint->mEP,NULL, &mBindRet); //status = OTBind(mNewEP->mDatagramEndpoint->mEP,&mBindReq, &mBindRet); DEBUG_NETWORK_API(mNewEP->mDatagramEndpoint->mEP, "OTBind", status); //ThrowIfOSErr_(status); if (status) goto error; } } //Catch_(code) error: if (status) { NMErr code = status; return code; } return kNMNoError; }