#include #include #include #include #include #include "EasyNet.h" struct EasyNetConn { EndpointRef ep; UInt32 timeoutTicks; }; static UInt32 Deadline(EasyNetConn *conn) { return TickCount() + conn->timeoutTicks; } static Boolean Idle(UInt32 deadline) { EventRecord event; if(TickCount() > deadline) return false; WaitNextEvent(0, &event, 1, NULL); return true; } OSStatus EasyNet_Init(void) { return InitOpenTransport(); } void EasyNet_Shutdown(void) { CloseOpenTransport(); } OSStatus EasyNet_Connect(const char *host, UInt16 port, long timeoutSecs, EasyNetConn **outConn) { OSStatus err; InetSvcRef inetServices; InetHostInfo hostInfo; EasyNetConn *conn; InetAddress addr; TCall sndCall; OTResult event; UInt32 deadline; *outConn = NULL; /* look up host */ inetServices = OTOpenInternetServices(kDefaultInternetServicesPath, 0, &err); if(err != noErr) return err; err = OTInetStringToAddress(inetServices, (char *) host, &hostInfo); OTCloseProvider(inetServices); if(err != noErr) return err; conn = (EasyNetConn *) malloc(sizeof(EasyNetConn)); if(conn == NULL) return memFullErr; conn->ep = kOTInvalidEndpointRef; conn->timeoutTicks = timeoutSecs * 60; /* create endpoint */ conn->ep = OTOpenEndpoint(OTCreateConfiguration(kTCPName), 0, NULL, &err); if(err != noErr) goto fail; OTSetSynchronous(conn->ep); OTSetNonBlocking(conn->ep); err = OTBind(conn->ep, NULL, NULL); if(err != noErr) goto fail; /* connect */ OTInitInetAddress(&addr, port, hostInfo.addrs[0]); OTMemzero(&sndCall, sizeof(TCall)); sndCall.addr.buf = (UInt8 *) &addr; sndCall.addr.len = sizeof(InetAddress); err = OTConnect(conn->ep, &sndCall, NULL); if(err == kOTLookErr) err = kOTNoDataErr; /* wait for conn */ deadline = Deadline(conn); while(err == kOTNoDataErr) { event = OTLook(conn->ep); if(event == T_CONNECT) { err = OTRcvConnect(conn->ep, NULL); } else if(event == T_DISCONNECT) { OTRcvDisconnect(conn->ep, NULL); err = kEasyNetConnectFailedErr; } else if(!Idle(deadline)) { err = kEasyNetTimeoutErr; } } if(err != noErr) goto fail; *outConn = conn; return noErr; fail: if(conn->ep != kOTInvalidEndpointRef) OTCloseProvider(conn->ep); free(conn); return err; } OSStatus EasyNet_Send(EasyNetConn *conn, const void *data, long length) { const char *p = (const char *) data; OTResult result; UInt32 deadline; deadline = Deadline(conn); while(length > 0) { result = OTSnd(conn->ep, (void *) p, length, 0); if(result >0) { p+= result; length -= result; deadline = Deadline(conn); } else if(result == kOTFlowErr) { if(!Idle(deadline)) return kEasyNetTimeoutErr; } else if(result == kOTLookErr) { return kEasyNetDisconnectedErr; } else { return result; } } return noErr; } OSStatus EasyNet_SendString(EasyNetConn *conn, const char *s) { return EasyNet_Send(conn, s, strlen(s)); } long EasyNet_Receive(EasyNetConn *conn, void *buf, long size) { OTResult result; OTResult event; OTFlags flags; UInt32 deadline; deadline = TickCount() + conn->timeoutTicks; for(;;) { result = OTRcv(conn->ep, buf, size, &flags); if(result > 0) return result; if(result == kOTLookErr) { event = OTLook(conn->ep); if(event == T_ORDREL) { OTRcvOrderlyDisconnect(conn->ep); return 0; } if(event == T_DISCONNECT) { OTRcvDisconnect(conn->ep, NULL); return kEasyNetDisconnectedErr; } } else if(result != kOTNoDataErr) { return result; } if(!Idle(deadline)) return kEasyNetTimeoutErr; } } void EasyNet_Close(EasyNetConn *conn) { if(conn == NULL) return; OTSndOrderlyDisconnect(conn->ep); OTCloseProvider(conn->ep); free(conn); }