static pascal OSStatus DoIncomingBind(OTMPEndpointRef ep, InetPort portNum, OTQLen qlen) { OSStatus err; TBind req; TBind ret; InetAddress reqAddr; InetAddress retAddr; OTInitInetAddress(&reqAddr, portNum, kOTAnyInetAddress); OTMemzero(&req, sizeof(req)); req.addr.len = sizeof(reqAddr); req.addr.buf = (UInt8 *) &reqAddr; req.qlen = qlen; OTMemzero(&ret, sizeof(ret)); ret.addr.maxlen = sizeof(retAddr); ret.addr.buf = (UInt8 *) &retAddr; err = OTMPXBind(ep, &req, &ret); if (err == noErr) { char addrAsStr[32]; OTInetHostToString(retAddr.fHost, addrAsStr); MPLogPrintf("\n"); MPLogPrintf("Bound to = %s:%d with qlen of %d\n", addrAsStr, retAddr.fPort, ret.qlen); } return err; }
static OSStatus ListenTest(OTMPEndpointRef ep) { OSStatus err; OSStatus junk; TCall call; InetAddress remoteAddr; OTMPEndpointRef worker; worker = NULL; err = SetFourByteOption(ep, INET_IP, IP_REUSEADDR, 0); if (err == noErr) { err = DoIncomingBind(ep, 1024, 10); } if (err == noErr) { OTMemzero(&remoteAddr, sizeof(remoteAddr)); OTMemzero(&call, sizeof(call)); call.addr.buf = (UInt8 *) &remoteAddr; call.addr.maxlen = sizeof(remoteAddr); err = OTMPXListen(ep, &call); if (err == noErr) { char addrAsStr[100]; OTInetHostToString(remoteAddr.fHost, addrAsStr); printf("\n"); printf("Call from %s:%d\n", addrAsStr, remoteAddr.fPort); worker = OTMPXOpenEndpointQInContext("tcp", 0, NULL, &err, NULL); } if (err == noErr) { err = OTMPXAccept(ep, worker, &call); } } if (err == noErr) { err = OTMPXSndDisconnect(worker, NULL); } if (err == noErr) { err = OTMPXUnbind(ep); } if (worker != NULL) { junk = OTMPXCloseProvider(worker); assert(junk == noErr); } return err; }
static pascal OSStatus DoOutgoingBind(OTMPEndpointRef ep) { OSStatus err; TBind ret; InetAddress boundAddr; OTMemzero(&ret, sizeof(ret)); ret.addr.maxlen = sizeof(boundAddr); ret.addr.buf = (UInt8 *) &boundAddr; err = OTMPXBind(ep, NULL, &ret); if (err == noErr) { char addrAsStr[32]; OTInetHostToString(boundAddr.fHost, addrAsStr); printf("\n"); printf("boundAddr = %s:%d\n", addrAsStr, boundAddr.fPort); } return err; }
pascal void OTTCPNotifier(void* vobj, OTEventCode code, OTResult result, void* cookie) { OTTCP *x = (OTTCP *) vobj; long oldA5; OSStatus s; EnterCallback(); oldA5 = SetA5(x->o_a5); post("*** OTTCPNotifier(code %x, result %ld)", (long) code, (long) result); if (code == T_OPENCOMPLETE) { if (result != noErr) { post("OTTCPNotifier got a T_OPENCOMPLETE code with error %ld", result); } // Even if we got an error, we'll use the endpoint. x->o_tcp_ep = (EndpointRef) cookie; if (x->o_inetHostName != 0) { BindTheEndpoint(x); // Now we expect a T_BINDCOMPLETE message. } } else if (code == T_BINDCOMPLETE) { TCall sndCall; InetAddress inAddr; // See what ephemeral port number OT gave us x->o_receiveInetPort = x->o_addrWeActuallyGot.fPort; // Now the endpoint has been bound; next trick is connecting OTInitInetAddress(&inAddr, x->o_inetPort, x->o_inetHost); OTMemzero(&sndCall, sizeof(TCall)); sndCall.addr.buf = (void *) &inAddr; sndCall.addr.len = sizeof(InetAddress); post("** About to OTConnect"); s = OTConnect(x->o_tcp_ep, &sndCall, NULL); if (s == kOTNoDataErr) { // No problem; that means connection is in progress post("** OTConnect returned kOTNoDataErr - good"); } else { post("е OTTCP: error: OTConnect returned %ld; not connecting.", s); } // Now we expect T_CONNECT } else if (code == T_CONNECT) { if (result == kOTBadAddressErr) { post("е OTTCP: error: bad address. Disconnecting"); x->o_inetHost = 0; change_connection(x); } else { post("** Got T_CONNECT"); post("** Result passed to notifier: %ld", (long) result); post("** Endpoint state before OTRcvConnect: %ld", (long) OTGetEndpointState(x->o_tcp_ep)); // We could pass in buffers to find out the actual address we connected to, etc. s = OTRcvConnect(x->o_tcp_ep, nil); if (s != kOTNoError) { post("е OTTCP: error: RcvConnect returned %ld", s); } post("** Endpoint state after OTRcvConnect: %ld", (long) OTGetEndpointState(x->o_tcp_ep)); ChangeState(x, NO_REQUEST); x->o_connectionSymbol = ps_connected; clock_delay(x->o_connectedclock, 0); } } else if (code == T_UNBINDCOMPLETE) { // If we have a new inetHost, try to bind it if (x->o_inetHost != 0) { BindTheEndpoint(x); // Now we expect T_BINDCOMPLETE } else { // No inetHost, so we're disonnected x->o_connectionSymbol = ps_disconnected; clock_delay(x->o_connectedclock, 0); } } else if (code == T_DISCONNECTCOMPLETE) { // We always want to rebind when we reconnect, so after disconnecting we unbind s = OTUnbind(x->o_tcp_ep); if (s != kOTNoError) { post("OTTCP: warning: OTUnbind returned %ld", s); } } else if (code == T_DATA) { ottcp_handleIncomingData(x); } else if (code == T_UDERR) { if (x->o_errorreporting) { PostUDERR("OTTCPNotifier was called for a T_UDERR code", x->o_tcp_ep); } else { /* We still have to receive the error to clear the condition */ OTRcvUDErr(x->o_tcp_ep, 0); } } else if (code == T_GODATA) { // Flow control restriction has lifted; now it's OK to send more data. do_write(x, 0, 0); } else if (code == T_DISCONNECT) { // The other dude wants to disconnect post("OTTCP: peer wants to disconnect"); s = OTRcvDisconnect(x->o_tcp_ep, NULL); if (s == kOTNoError) { x->o_inetHost = 0; change_connection(x); } else if (s == kOTNoDisconnectErr) { // false alarm } else { post("е OTTCP: error: OTRcvDisconnect returned %ld", s); } } else if (code == T_ORDREL) { post("*** Got T_ORDREL"); s = OTRcvOrderlyDisconnect(x->o_tcp_ep); if (s == kOTNoReleaseErr) { post("...false alarm!"); } else if (s == kOTNoError) { x->o_inetHost = 0; change_connection(x); } else { post("е OTTCP: error: OTRcvOrderlyDisconnect returned %ld", s); } } else { if (x->o_errorreporting) { post("OTTCP: Unrecognized OTEventCode %ld in event handler. Oh well.", (long) code); } } done: SetA5(oldA5); ExitCallback(); }
static OSStatus SFCSnd(void *parameter) { #pragma unused(parameter) OSStatus err; OSStatus junk; OTMPEndpointRef ep; TCall call; InetAddress inet; OTByteCount bytesThisTime; OTByteCount bytesRemaining; ep = NULL; err = OTMPXPrepareThisTask(); if (err == noErr) { ep = OTMPXOpenEndpointQInContext("tcp", 0, NULL, &err, NULL); } if (err == noErr) { gLookerEP = ep; err = OTMPXBind(ep, NULL, NULL); } if (err == noErr) { OTInitInetAddress(&inet, 1025, 0x7f000001); // 127.0.0.1:1025 OTMemzero(&call, sizeof(call)); call.addr.buf = (UInt8 *) &inet; call.addr.len = sizeof(inet); err = OTMPXConnect(ep, &call, NULL); } if (err == noErr) { if (false) { bytesRemaining = 0x01000000; // 16 MB } else { bytesRemaining = 0x00100000; // 1 MB } do { if (bytesRemaining > sizeof(gJunkBuffer)) { bytesThisTime = sizeof(gJunkBuffer); } else { bytesThisTime = bytesRemaining; } err = OTMPXSnd(ep, gJunkBuffer, bytesThisTime, 0); if (err > noErr) { bytesRemaining -= err; err = noErr; } } while ( (err == noErr) && (bytesRemaining != 0) ); } if (err == noErr) { err = OTMPXSndDisconnect(ep, NULL); } gLookerEP = NULL; gQuitLooker = true; if (ep != NULL) { junk = OTMPXCloseProvider(ep); assert(junk == noErr); } OTMPXUnprepareThisTask(); return err; }
static OSStatus SFCRcv(void *parameter) { #pragma unused(parameter) OSStatus err; OSStatus junk; OTMPEndpointRef ep; TCall call; OTFlags junkFlags; UInt32 sleepCounter; ep = NULL; err = OTMPXPrepareThisTask(); if (err == noErr) { ep = OTMPXOpenEndpointQInContext("tcp", 0, NULL, &err, NULL); } if (err == noErr) { err = SetFourByteOption(ep, INET_IP, IP_REUSEADDR, 1); } if (err == noErr) { err = DoIncomingBind(ep, 1025, 1); } gRcvStarted = true; if (err == noErr) { OTMemzero(&call, sizeof(call)); err = OTMPXListen(ep, &call); } if (err == noErr) { err = OTMPXAccept(ep, ep, &call); } if (err == noErr) { sleepCounter = 0; do { if (sleepCounter == 0) { RcvSleep(); } err = OTMPXRcv(ep, gJunkBuffer, sizeof(gJunkBuffer), &junkFlags); if (err > noErr) { err = noErr; } sleepCounter += 1; if (sleepCounter > 64) { sleepCounter = 0; } } while (err == noErr); if (err == kOTLookErr) { OTResult look; look = OTMPXLook(ep); switch (look) { case T_ORDREL: err = OTMPXRcvOrderlyDisconnect(ep); if (err == noErr) { err = OTMPXSndOrderlyDisconnect(ep); } break; case T_DISCONNECT: err = OTMPXRcvDisconnect(ep, NULL); break; default: MPLogPrintf("look = %08lx\n", look); break; } } } if (ep != NULL) { junk = OTMPXCloseProvider(ep); assert(junk == noErr); } OTMPXUnprepareThisTask(); return err; }
static OSStatus UnitDataTest(void) { OSStatus err; OTMPEndpointRef ep; TUnitData udata; const char *message = "Hello Cruel World!\x0d\x0a"; ep = OTMPXOpenEndpointQInContext("udp", 0, NULL, &err, NULL); if (err == noErr) { err = OTMPXBind(ep, NULL, NULL); } if (err == noErr) { InetAddress dest; OTMemzero(&udata, sizeof(udata)); OTInitInetAddress(&dest, 7, 0x01020304); udata.addr.len = sizeof(dest); udata.addr.buf = (UInt8 *) &dest; udata.udata.len = OTStrLength(message); udata.udata.buf = (UInt8 *) message; err = OTMPXSndUData(ep, &udata); } if (err == noErr) { char buffer[256]; InetAddress src; OTFlags junkFlags; OTMemzero(&udata, sizeof(udata)); OTMemzero(&src, sizeof(src)); udata.addr.maxlen = sizeof(src); udata.addr.buf = (UInt8 *) &src; udata.udata.maxlen = sizeof(buffer); udata.udata.buf = (UInt8 *) buffer; err = OTMPXRcvUData(ep, &udata, &junkFlags); if (err == noErr) { if ( udata.udata.len != OTStrLength(message) || ! OTMemcmp(buffer, message, udata.udata.len) ) { err = -1; } } else if (err == kOTLookErr) { OTResult look; // If echo server isn't running, previous send will generate // an ICMP port unreachable, which the above RcvUData will return // as a look error and which we consume here. look = OTMPXLook(ep); if (look == T_UDERR) { TUDErr uderr; OTMemzero(&uderr, sizeof(uderr)); OTMemzero(&src, sizeof(src)); uderr.addr.maxlen = sizeof(src); uderr.addr.buf = (UInt8 *) &src; uderr.opt.maxlen = sizeof(buffer); uderr.opt.buf = (UInt8 *) buffer; err = OTMPXRcvUDErr(ep, &uderr); if (err == noErr) { printf("uderr src = %08xl\n", src.fHost); printf("uderr error = %ld\n", uderr.error); } } } } if (err == noErr) { err = OTMPXUnbind(ep); } if (ep != NULL) { OTMPXCloseProvider(ep); } return err; }
static OSStatus MiscEndpointTest(OTMPEndpointRef ep) { OSStatus err; OSStatus junk; TEndpointInfo info; char addrAsStr[100]; err = OTMPXGetEndpointInfo(ep, &info); if (err == noErr) { printf("addr = %ld\n", info.addr); printf("options = %ld\n", info.options); printf("tsdu = %ld\n", info.tsdu); printf("etsdu = %ld\n", info.etsdu); printf("connect = %ld\n", info.connect); printf("discon = %ld\n", info.discon); printf("servtype = %ld\n", info.servtype); printf("flags = %ld\n", info.flags); } if (err == noErr) { err = OTMPXGetEndpointState(ep); if (err >= noErr) { printf("state1 = %ld\n", err); err = noErr; } } if (err == noErr) { err = OTMPXBind(ep, NULL, NULL); } if (err == noErr) { err = OTMPXGetEndpointState(ep); if (err >= noErr) { printf("state2 = %ld\n", err); err = noErr; } if (err == noErr) { TBind local; InetAddress localAddr; OTMemzero(&localAddr, sizeof(localAddr)); OTMemzero(&local, sizeof(local)); local.addr.maxlen = sizeof(localAddr); local.addr.buf = (UInt8 *) &localAddr; err = OTMPXGetProtAddress(ep, &local, NULL); if (err == noErr) { OTInetHostToString(localAddr.fHost, addrAsStr); printf("localAddr = %s:%d\n", addrAsStr, localAddr.fPort); } } if (err == noErr) { TBind dns; TBind inet; DNSAddress dnsAddr; InetAddress inetAddr; OTMemzero(&dns, sizeof(dns)); OTMemzero(&inet, sizeof(inet)); OTMemzero(&inetAddr, sizeof(inetAddr)); dns.addr.len = OTInitDNSAddress(&dnsAddr, "1.2.3.4:80"); dns.addr.buf = (UInt8 *) &dnsAddr; inet.addr.maxlen = sizeof(inetAddr); inet.addr.buf = (UInt8 *) &inetAddr; err = OTMPXResolveAddress(ep, &dns, &inet, 1000); if (err == noErr) { OTInetHostToString(inetAddr.fHost, addrAsStr); printf("inetAddr = %s:%d\n", addrAsStr, inetAddr.fPort); } } junk = OTMPXUnbind(ep); assert(junk == noErr); } if (err == noErr) { OTByteCount byteCount; byteCount = 666; err = OTMPXCountDataBytes(ep, &byteCount); assert(err == kOTNoDataErr); assert(byteCount == 0); if (err == kOTNoDataErr) { printf("byteCount = %ld\n", byteCount); err = noErr; } else { err = -1; } } return err; }
static OSStatus EchoDisconnectTest(OTMPEndpointRef ep) { OSStatus err; err = DoOutgoingBind(ep); if (err == noErr) { InetAddress sndAddr; InetAddress rcvAddr; TCall sndCall; TCall rcvCall; OTInitInetAddress(&sndAddr, 7, 0x7f000001); // localhost addr OTMemzero(&rcvAddr, sizeof(rcvAddr)); OTMemzero(&sndCall, sizeof(sndCall)); sndCall.addr.buf = (UInt8 *) &sndAddr; sndCall.addr.len = sizeof(sndAddr); OTMemzero(&rcvCall, sizeof(rcvCall)); rcvCall.addr.buf = (UInt8 *) &rcvAddr; rcvCall.addr.maxlen = sizeof(rcvAddr); err = OTMPXConnect(ep, &sndCall, &rcvCall); if (err == noErr) { OTFlags flags; char rcvBuf[100]; printf("\n"); printf("Now quit Mac TCP Watcher.\n"); OTMemzero(rcvBuf, sizeof(rcvBuf)); flags = 0; err = OTMPXRcv(ep, rcvBuf, sizeof(rcvBuf), &flags); if (err == kOTLookErr) { OTResult look; look = OTMPXLook(ep); if (look == T_DISCONNECT) { TDiscon discon; OTMemzero(&discon, sizeof(discon)); err = OTMPXRcvDisconnect(ep, &discon); if (err == noErr) { printf("\n"); printf("Received disconnected with reason %ld.\n", discon.reason); } } else { printf("\n"); printf("look = %ld\n", look); } } } } if (err == noErr) { err = OTMPXUnbind(ep); } return err; }
static OSStatus BasicEchoTest(OTMPEndpointRef ep) { OSStatus err; OSStatus err2; err = DoOutgoingBind(ep); if (err == noErr) { InetAddress sndAddr; InetAddress rcvAddr; TCall sndCall; TCall rcvCall; OTInitInetAddress(&sndAddr, 7, 0x7f000001); // localhost addr OTMemzero(&rcvAddr, sizeof(rcvAddr)); OTMemzero(&sndCall, sizeof(sndCall)); sndCall.addr.buf = (UInt8 *) &sndAddr; sndCall.addr.len = sizeof(sndAddr); OTMemzero(&rcvCall, sizeof(rcvCall)); rcvCall.addr.buf = (UInt8 *) &rcvAddr; rcvCall.addr.maxlen = sizeof(rcvAddr); err = OTMPXConnect(ep, &sndCall, &rcvCall); if (err == kOTLookErr) { OTResult look; look = OTMPXLook(ep); if (look == T_DISCONNECT) { TDiscon discon; OTMemzero(&discon, sizeof(discon)); err = OTMPXRcvDisconnect(ep, &discon); if (err == noErr) { printf("\n"); printf("Connect failed with reason %ld.\n", discon.reason); } } } else if (err == noErr) { err = OTMPXSnd(ep, "Hello Cruel World!\x0d\x0a", 20, 0); if (err == 20) { err = noErr; } if (err == noErr) { OTFlags flags; char rcvBuf[100]; OTMemzero(rcvBuf, sizeof(rcvBuf)); flags = 0; err = OTMPXRcv(ep, rcvBuf, sizeof(rcvBuf), &flags); if (err == 20) { err = noErr; } } err2 = OTMPXSndDisconnect(ep, NULL); if (err == noErr) { err = err2; } } } if (err == noErr) { err = OTMPXUnbind(ep); } return err; }
/* 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; }