Пример #1
0
int TCPLow_PutPacket(TCPINSTANCE* tcp, TCPPEER* pPeer,void* bufptr,ULONG len)
{
	TUnitData	udata;
	OSStatus	err;
	OTResult	theResult;
	InetAddress	destAddr;
	unsigned char *pt;
	
	OTInitInetAddress(&destAddr,pPeer->port,pPeer->addr);
	
	udata.addr.maxlen = sizeof(InetAddress);
	udata.addr.len = sizeof(InetAddress);
	udata.addr.buf = (unsigned char *) &destAddr;
	
	udata.opt.maxlen = 0;
	udata.opt.len = 0;
	udata.opt.buf = nil;
	
	udata.udata.maxlen = len;
	udata.udata.len = len;
	udata.udata.buf = (unsigned char *)bufptr;
	
	do {
		err = OTSndUData(tcp->udpEndpoint, &udata);
		if (err == kOTLookErr) {
			theResult = OTLook(tcp->udpEndpoint);
			if (theResult == T_UDERR) {
				HandleErrorUDERR();
				err = 666;
			}
		}
	} while (err == 666);

	return err;
}
Пример #2
0
// no modified.. waiting for a MAC!
int	my_recv(TCPsocket sock, void *data, int maxlen)
{
	int len = 0;
	OSStatus res;
	/* Server sockets are for accepting connections only */
	if ( sock->sflag ) {
		SDLNet_SetError("Server sockets cannot receive");
		return(-1);
	}
	do
	{
		res = OTRcv(sock->channel, data, maxlen-len, 0);
		if (res > 0) {
			len = res;
		}
		AsyncTCPPopEvent(sock);
		if( res == kOTLookErr )
		{
			res = OTLook(sock->channel );
			continue;
		}
	} while ( (len == 0) && (res == kOTNoDataErr) );

	sock->ready = 0;
	if ( len == 0 ) { /* Open Transport error */
		return(-1);
	}
	return(len);
}
Пример #3
0
void
OTIPEnumerator::HandleLookErr(void)
{
	DEBUG_ENTRY_EXIT("IPEnumerator::HandleLookErr");

OTResult	result;
OSStatus	status;
TUDErr		udErr;
InetAddress	addr;
	
	udErr.addr.buf = (NMUInt8 *) &addr;
	udErr.addr.len = udErr.addr.maxlen = sizeof(InetAddress);
	udErr.opt.maxlen = 0;
	
	
	result = OTLook(mEP);
	DEBUG_PRINT("OTLook returned %ld", result);

	switch (result)
	{
		case T_DATA:
			ReceiveDatagram();
			break;
			
		case T_UDERR:
			status = OTRcvUDErr(mEP, &udErr);
			DEBUG_PRINT("OTRcvUDErr returned %ld", status);
			break;

		default:
			DEBUG_PRINT("Unhandled look error!");
			break;
	}
}
Пример #4
0
int tcpabi_udp_send( unsigned handle, void *buf, unsigned len, unsigned ttltos, unsigned id, unsigned char flags ) {
    TUnitData	udata;
    OSStatus	err;
    OTResult	theResult;

    udata.addr.maxlen = sizeof(gDests[handle].dest_addr);
    udata.addr.len = sizeof(gDests[handle].dest_addr);
    udata.addr.buf = (unsigned char *) &gDests[handle].dest_addr;

    udata.opt.maxlen = 0;
    udata.opt.len = 0;
    udata.opt.buf = nil;

    udata.udata.maxlen = len;
    udata.udata.len = len;
    udata.udata.buf = (unsigned char *)buf;

    do {
        err = OTSndUData(gUDPEndpoint, &udata);
        if (err == kOTLookErr) {
            theResult = OTLook(gUDPEndpoint);
            if (theResult == T_UDERR) {
                HandleErrorUDERR();
                err = 666;
            }
        }
    } while (err == 666);

    return err;
}
Пример #5
0
int SDLNet_CheckSockets(SDLNet_SocketSet set, Uint32 timeout)
{
Uint32	stop;
int 	numReady;

	/* Loop, polling the network devices */
	
	stop = SDL_GetTicks() + timeout;
	
	do 
	{
	OTResult status;
	size_t	numBytes;
	int 	i;
		
		numReady = 0;
	
		for (i = set->numsockets-1;i >= 0;--i) 
		{
			status = OTLook( set->sockets[i]->channel );
			if( status > 0 )
			{
				switch( status )
				{
					case T_UDERR:
						OTRcvUDErr( set->sockets[i]->channel , nil);
						break;
					case T_DISCONNECT:
						OTRcvDisconnect( set->sockets[i]->channel, nil );
						break;
					case T_ORDREL:
						OTRcvOrderlyDisconnect(set->sockets[i]->channel );
						break;
					case T_CONNECT:
						OTRcvConnect( set->sockets[i]->channel, nil );
						break;
					
				
					default:
						set->sockets[i]->ready = 1;
						++numReady;
				}
			}
			else if( OTCountDataBytes(set->sockets[i]->channel, &numBytes ) != kOTNoDataErr )
			{
				set->sockets[i]->ready = 1;
				++numReady;
			}
			else
				set->sockets[i]->ready = 0;
		}
		
	} while (!numReady && (SDL_GetTicks() < stop));

	return(numReady);
}
Пример #6
0
/* Returns true if a socket is has data available for reading right now */
static int SocketReady(SOCKET sock)
{
	int retval = 0;
#ifdef MACOS_OPENTRANSPORT
	OTResult status;
#else
	struct timeval tv;
	fd_set mask;
#endif

#ifdef MACOS_OPENTRANSPORT
	//status = OTGetEndpointState(sock);
	status = OTLook(sock);
	if( status > 0 )
		retval = 1;
		
/*	switch( status )
	{
//		case T_IDLE:
		case T_DATAXFER:
//		case T_INREL:
			retval = 1;
			break;
		default:
			OTCountDataBytes( sock, &numBytes );
			if( numBytes )
				retval = 1;
	}*/
#else
	/* Check the file descriptors for available data */
	do {
		errno = 0;

		/* Set up the mask of file descriptors */
		FD_ZERO(&mask);
		FD_SET(sock, &mask);

		/* Set up the timeout */
		tv.tv_sec = 0;
		tv.tv_usec = 0;

		/* Look! */
		retval = select(sock+1, &mask, NULL, NULL, &tv);
	} while ( errno == EINTR );
#endif /* MACOS_OPENTRANSPORT */

	return(retval == 1);
}
Пример #7
0
static PRBool GetState(EndpointRef endpoint, PRBool *readReady, PRBool *writeReady, PRBool *exceptReady)
{
	OSStatus err;
	OTResult resultOT;
	TDiscon discon;
	PRBool result = PR_FALSE;
	
	*readReady = *writeReady = *exceptReady = PR_FALSE;

	resultOT = OTLook(endpoint);
	switch (resultOT) {
		case T_DATA:
		case T_LISTEN:
			*readReady = PR_TRUE;
			break;
		case T_CONNECT:
			err = OTRcvConnect(endpoint, NULL);
			PR_ASSERT(err == kOTNoError);
			break;		
		case T_DISCONNECT:
			memset(&discon, 0 , sizeof(discon));
			err = OTRcvDisconnect(endpoint, &discon);
			PR_ASSERT(err == kOTNoError);
			macsock_map_error(discon.reason);
			*exceptReady = PR_TRUE;
			break;		
		case T_ORDREL:
			*readReady = PR_TRUE;
			err = OTRcvOrderlyDisconnect(endpoint);
			PR_ASSERT(err == kOTNoError);
			break;
	}
	resultOT = OTGetEndpointState(endpoint);
	switch (resultOT)	{
		case T_DATAXFER:
		case T_INREL:
			*writeReady = PR_TRUE;
			break;
		default:
			*writeReady = PR_FALSE;
	}
	
	if ((*readReady == PR_TRUE) || (*writeReady==PR_TRUE) || (*exceptReady==PR_TRUE))
		result = PR_TRUE;

	return result;
}
Пример #8
0
int tcpabi_udp_broadcast(void *buf, unsigned len) {
    OSStatus			err = noErr;
    TUnitData			udata;
    OTResult			theResult;
    short				i;
    InetAddress			currentAddress;

    //	this method sends the specified packet to our list of
    //	IP addreses. We return noErr if they were all sent
    //	without any trouble (we should ignore errors which
    //	indicate that the other end is not there since we
    //	really don't care if all of these packets are delivered)

    //	we don't broadcast to the first address because it's our own

    for (i = 1; i < gAddressList.addressCount; i++) {

        OTInitInetAddress(&currentAddress, SOCKET_MW2, gAddressList.addressList[i]);

        udata.addr.maxlen = sizeof(InetAddress);
        udata.addr.len = sizeof(InetAddress);
        udata.addr.buf = (unsigned char *) &currentAddress;

        udata.opt.maxlen = 0;
        udata.opt.len = 0;
        udata.opt.buf = nil;

        udata.udata.maxlen = len;
        udata.udata.len = len;
        udata.udata.buf = (unsigned char *)buf;

        do {
            err = OTSndUData(gUDPEndpoint, &udata);
            if (err == kOTLookErr) {
                theResult = OTLook(gUDPEndpoint);
                if (theResult == T_UDERR) {
                    HandleErrorUDERR();
                    err = 666;
                }
            }
        } while (err == 666);

    }

    return err;
}
Пример #9
0
void PostUDERR(char *source, EndpointRef ep) {
	OSStatus	err;
	TUDErr errBlock;
	struct InetAddress addr;
#define OPTIONS_LENGTH 2048
	unsigned char RoomForStupidOptions[OPTIONS_LENGTH];
	
	errBlock.addr.buf = (void *) &addr;
	errBlock.addr.maxlen = sizeof(addr);
#ifdef IGNORE_OPTIONS
	errBlock.opt.len = 0;
	errBlock.opt.maxlen = 0;
	errBlock.opt.buf = 0;
#else
	errBlock.opt.len = 0;
	errBlock.opt.maxlen = OPTIONS_LENGTH;
	errBlock.opt.buf = RoomForStupidOptions;
#endif
		
	err = OTRcvUDErr(ep, &errBlock);
	post("OTUDP: %s  \"protocol-dependent\" error code %ld", source, errBlock.error);
	{
		char hostNameString[255];
		OTInetHostToString(addr.fHost, hostNameString);
		post(" Addr. assoc w/ error is %s, port %d.", hostNameString, addr.fPort);
	}

	if (errBlock.error == 49) {
		post("Error 49 seems to mean that you're sending to a machine that's listening to");
		post("UDP but not on the port you're sending to.");
	}


	if (err == kOTNoError ) {
		// No further error; don't worry about it
	} else if (err == kOTLookErr) {
		OTResult r = OTLook(ep);
		post("Got kOTLookErr; OTLook returned %d", r);
	} else if (err == kOTFlowErr) {
		post("Flow control error.");
	} else if (err == kOTBufferOverflowErr) {
	    post("Lame Open Transport says it doesn't have enough memory0 to tell me what my problem is.");
	} else {	
		post("OTRcvUDErr returned %ld", err);
	}
}
Пример #10
0
int atalk_ddp_broadcast(void *buf, unsigned len) {
	OSStatus			err = noErr;
	TUnitData			udata;
	OTResult			theResult;
	short				i;
	extern short		gLookupCount;
	extern DDPAddress	gLookupResults[];
	
	//	this method sends the specified packet to our list of
	//	DDP addreses. We return noErr if they were all sent
	//	without any trouble (we should ignore errors which
	//	indicate that the other end is not there since we
	//	really don't care if all of these packets are delivered)
	
	for (i = 0; i < gLookupCount; i++) {

		udata.addr.len = sizeof(DDPAddress);
		udata.addr.buf = (unsigned char *) &gLookupResults[i];
		
		udata.opt.len = 0;
		udata.opt.buf = nil;
		
		udata.udata.len = len;
		udata.udata.buf = (unsigned char *)buf;
		
		do {
			err = OTSndUData(gDDPEndpoint, &udata);
			if (err == kOTLookErr) {
				theResult = OTLook(gDDPEndpoint);
				if (theResult == T_UDERR) {
					HandleErrorUDERR();
					err = 666;
				}
			}
		} while (err == 666);
		
	}
	
	return err;
}
Пример #11
0
/* Receive up to 'maxlen' bytes of data over the non-server socket 'sock',
   and store them in the buffer pointed to by 'data'.
   This function returns the actual amount of data received.  If the return
   value is less than or equal to zero, then either the remote connection was
   closed, or an unknown socket error occurred.
*/
int SDLNet_TCP_Recv(TCPsocket sock, void *data, int maxlen)
{
	int len = 0;
	OSStatus res;
	/* Server sockets are for accepting connections only */
	if ( sock->sflag ) {
		SDLNet_SetError("Server sockets cannot receive");
		return(-1);
	}

	do
	{
		res = OTRcv(sock->channel, data, maxlen-len, 0);
		if (res > 0) {
			len = res;
		}

#ifdef DEBUG_NET
		if ( res != kOTNoDataErr )
			printf("SDLNet_TCP_Recv received ; %d\n", res );
#endif
		
		AsyncTCPPopEvent(sock);
		if( res == kOTLookErr )
		{
			res = OTLook(sock->channel );
			continue;
		}
	} while ( (len == 0) && (res == kOTNoDataErr) );

	sock->ready = 0;
	if ( len == 0 ) { /* Open Transport error */
#ifdef DEBUG_NET
		printf("Open Transport error: %d\n", res);
#endif
		return(-1);
	}
	return(len);
}
Пример #12
0
NMErr
EndpointHander::Finish(void)
{
	DEBUG_ENTRY_EXIT("EndpointHander::Finish");

NMErr	status;
		
	OTRemoveNotifier(mNewEP->mStreamEndpoint->mEP);
	OTInstallNotifier(mNewEP->mStreamEndpoint->mEP, mNewEP->mNotifier.fUPP, mNewEP->mStreamEndpoint);

	if (mNewEP->mMode == kNMNormalMode)
	{
		OTRemoveNotifier(mNewEP->mDatagramEndpoint->mEP);
		OTInstallNotifier(mNewEP->mDatagramEndpoint->mEP, mNewEP->mNotifier.fUPP, mNewEP->mDatagramEndpoint);
	}
	
	status = OTAccept(mListenerEP->mStreamEndpoint->mEP, mNewEP->mStreamEndpoint->mEP, mCall);
	DEBUG_NETWORK_API(mListenerEP->mStreamEndpoint->mEP, "OTAccept", status);					

	if (status == kOTLookErr)
	{
		OTResult lookResult = OTLook(mListenerEP->mStreamEndpoint->mEP);

		if (lookResult == T_DISCONNECT)		// the active peer disconnected
			OTRcvDisconnect(mListenerEP->mStreamEndpoint->mEP, NULL);
			
		//	fake the accept complete
		mListenerEP->HandleAcceptComplete();
		
		//	kill the new endpoint
		EndpointDisposer *killer = new EndpointDisposer(mNewEP, true);
	}
	
	if (! ScheduleDelete())
		delete this;		// this is pretty damn likely to crach [gg]
	
	return kNMNoError;
}
Пример #13
0
int tcpabi_udp_send_to_address(InetAddress* theAddress, void *buf, unsigned len) {
    TUnitData	udata;
    OSStatus	err;
    OTResult	theResult;

    //	send our list of addresses to the destination address

    udata.addr.maxlen = sizeof(InetAddress);
    udata.addr.len = sizeof(InetAddress);
    udata.addr.buf = (unsigned char *) theAddress;

    udata.opt.maxlen = 0;
    udata.opt.len = 0;
    udata.opt.buf = nil;

    udata.udata.maxlen = len;
    udata.udata.len = len;
    udata.udata.buf = (unsigned char *)buf;

    do {
        err = OTSndUData(gUDPEndpoint, &udata);
        if (err == kOTLookErr) {
            theResult = OTLook(gUDPEndpoint);
            if (theResult == T_UDERR) {
                HandleErrorUDERR();
                err = 666;
            }
        }
    } while (err == 666);

    //	add the destination address to our list of addresses

    AddAddressToList(theAddress->fHost);

    return err;
}
Пример #14
0
void ottcp_handleIncomingData(OTTCP *x) {
	/* 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.  */
	
	OTFlags flags;
	OTResult r;
	short oldLockout;

	EnterCallback();

//	post("** Entering ottcp_handleIncomingData");

	// Are we in a state where we want to read data that comes in?
	
	if (x->o_state == SETTING_UP) {
		post("е OTTCP: How could ottcp_handleIncomingData() be called in state SETTING_UP?");
	} else if (x->o_state == NO_REQUEST) {
		// The rest of this Max program hasn't asked us for any data yet, so
		// we won't read it out of OpenTransport.  That way, when OT's buffers
		// fill up, TCP flow control will happen correctly.
		x->o_datawaiting = 1;
	} else if (x->o_state == OUTPUTTING) {
		// We're still busy trying to output the last chunk of data, so again
		// we just leave the new data in OT's buffers so flow control will work.
		x->o_datawaiting = 1;
	} else if (x->o_state == GET_NBYTES) {
		// Try to read N bytes
		long numLeftToRead = x->o_numBytesWeWant - x->o_bytesRead;
		if (numLeftToRead <= 0) {
			post("е OTTCP: internal error: read too much.");
		} else {
			oldLockout = AcquireLock(x);
			r = OTRcv(x->o_tcp_ep, x->o_currentReadBuf+x->o_bytesRead, numLeftToRead, &flags);
			ReleaseLock(x,oldLockout);
			if (r == numLeftToRead) {
				// We read everything we wanted, so output the darn buffer
				x->o_bytesRead += r;
				ChangeState(x, OUTPUTTING);
				x->o_whatToOutput = GET_NBYTES;
				clock_delay(x->o_clock, 0);
				// Maybe there's more data to be read
				x->o_datawaiting = 1;	
			} else if (r > 0) {
				// We read some, but not all, of our N bytes.
				x->o_bytesRead += r;
				x->o_datawaiting = 0;
			} else if (r == kOTNoDataErr) {
				// We didn't read squat, but that's supposed to be OK.
				x->o_datawaiting = 0;
			} else if (r == kOTLookErr) {
				OTResult lookr = OTLook(x->o_tcp_ep);
				post("OTTCP: OTRcv returned kOTLookErr; OTLook returned %ld", lookr);
			} else {
				post("е OTTCP: warning: OTRcv returned %ld", r);
			}
		}
	} else if (x->o_state == GET_DELIM) {
		long capacity = x->o_ReadBufSize - x->o_bytesRead;
		long numToRead;
		
		if (capacity > MAX_TO_READ_LOOKING_FOR_DELIMITER) {
			numToRead = MAX_TO_READ_LOOKING_FOR_DELIMITER;
		} else {
			numToRead = capacity;
		}
	readagain:
		oldLockout = AcquireLock(x);
		r = OTRcv(x->o_tcp_ep, x->o_currentReadBuf+x->o_bytesRead, numToRead, &flags);
		ReleaseLock(x,oldLockout);

		if (r == numToRead) {
			// We read everything we asked for
			char *afterDelimiter;
			
			x->o_datawaiting = 1;	// Maybe there's more data to be read
			x->o_bytesRead += r;
			if (FoundDelimiter(x, &afterDelimiter)) {
				ChangeState(x, OUTPUTTING);
				x->o_whatToOutput = GET_DELIM;
				CopyAfterDelimiterToOtherBuffer(x, afterDelimiter);
				clock_delay(x->o_clock, 0);
			} else if (x->o_bytesRead == x->o_ReadBufSize) {
				post("е OTTCP: error: filled %ld byte read buffer but never found delimiter string \"%s\"",
					 x->o_ReadBufSize, x->o_delimiterBytes);
				post("Discarding buffer and calling off the search.  You probably want to reconnect.");
				ChangeState(x, NO_REQUEST);
				x->o_bytesRead = 0;
			} else {
				// We didn't find the delimiter in the MAX_TO_READ_LOOKING_FOR_DELIMITER bytes
				// we read, but we've got more room in our buffer and there may be more
				// data in the OT buffer, so let's do another read.
				goto readagain;
			}
		} else if (r > 0) {
			// We read everything that was available
			char *afterDelimiter;
			x->o_datawaiting = 0;
			x->o_bytesRead += r;
			
			if (FoundDelimiter(x, &afterDelimiter)) {
				ChangeState(x, OUTPUTTING);
				x->o_whatToOutput = GET_DELIM;
				CopyAfterDelimiterToOtherBuffer(x, afterDelimiter);
				clock_delay(x->o_clock, 0);
			} else {
				// We didn't see the delimiter, TCP's buffer is empty, and our buffer
				// still has room, so there's nothing else to do until the next T_DATA event.
			}
		} else if (r == kOTNoDataErr) {
			// We didn't read squat, but that's supposed to be OK.
			x->o_datawaiting = 0;
		} else if (r == kOTLookErr) {
			OTResult lookr = OTLook(x->o_tcp_ep);
			post("OTTCP: OTRcv returned kOTLookErr; OTLook returned %ld", lookr);
		} else {
			post("е OTTCP: warning: OTRcv returned %ld", r);
		}
	} else {
		post("е OTTCP: error: unrecognized state %ld", x->o_state);
	}

bag:
	ExitCallback();
}
Пример #15
0
void do_write(OTTCP *x, long length, void *bytes) {
	OTResult r;
	
	if (x->o_WBReadPos == x->o_WBWritePos) {
		// Nothing in the circular buffer, so try to write the new stuff

		if (length == 0) return;
		r = OTSnd(x->o_tcp_ep, bytes, length, (OTFlags) 0);
		
		if (r == length) {
			// Great; everything was accepted
		} else if (r > 0) {
			// Partial flow control: some was accepted; the rest was not
			AddToWriteBuffer(x, length-r, ((void *) (((char *) bytes) + r)));
		} else if (r == kOTFlowErr) {
			// Full flow control situation: nothing was accepted
			AddToWriteBuffer(x, length, bytes);
		} else if (r == kOTLookErr) {
			// Maybe we got a disconnect or something
			OTResult lookr = OTLook(x->o_tcp_ep);
			post("е OTTCP: OTSnd returned kOTLookErr; OTLook returned %ld", lookr);
		} else {
			post("е OTTCP: OTSnd returned %ld", r);
		}
	} else {
		// We already have some flow-controlled bytes in the write buffer; they have to
		// go out before the new ones.  We'll try to write the old ones again, just in case 
		// they go out, and the new ones go out, without copying the new ones into the buffer
		
		if (x->o_WBReadPos > x->o_WBWritePos) {
			// Data in the buffer wraps around, so first we try to OTSnd the contiguous
			// part up to the end of the buffer
			
			r = OTSnd(x->o_tcp_ep, x->o_WriteBuf + x->o_WBReadPos, 
				      x->o_WriteBufSize - x->o_WBReadPos, (OTFlags) 0);
			
			if (r == length) {
				// Great; the latter part of the write buffer was accepted
				// Adjust the read position of the write buffer and make a recursive
				// call to try to write some more
				x->o_WBReadPos = 0;
				do_write(x, length, bytes);
			} else if (r > 0) {
				// Partial flow control: some was accepted; the rest was not
				x->o_WBReadPos += r;
				AddToWriteBuffer(x, length, bytes);
			} else if (r == kOTFlowErr) {
				// Full flow control situation: nothing was accepted
				AddToWriteBuffer(x, length, bytes);
			} else if (r == kOTLookErr) {
				// Maybe we got a disconnect or something
				OTResult lookr = OTLook(x->o_tcp_ep);
				post("е OTTCP: OTSnd returned kOTLookErr; OTLook returned %ld", lookr);
			} else {
				post("е OTTCP: OTSnd returned %ld", r);
			}
		} else {
			// Data in the write buffer is all in one contiguous chunk, so try writing it
			r = OTSnd(x->o_tcp_ep, x->o_WriteBuf+x->o_WBReadPos, 
				      x->o_WBWritePos - x->o_WBReadPos, (OTFlags) 0);
			
			if (r == length) {
				// Great; the entire write buffer was accepted.  Mark it empty
				// and make a recursive call to try to write the new stuff
				x->o_WBReadPos = x->o_WBWritePos = 0;
				do_write(x, length, bytes);
			} else if (r > 0) {
				// Partial flow control: some was accepted; the rest was not
				x->o_WBReadPos += r;
				AddToWriteBuffer(x, length, bytes);
			} else if (r == kOTFlowErr) {
				// Full flow control situation: nothing was accepted
				AddToWriteBuffer(x, length, bytes);
			} else if (r == kOTLookErr) {
				// Maybe we got a disconnect or something
				OTResult lookr = OTLook(x->o_tcp_ep);
				post("е OTTCP: OTSnd returned kOTLookErr; OTLook returned %ld", lookr);
			} else {
				post("е OTTCP: OTSnd returned %ld", r);
			}
		}
	}
}
Пример #16
0
/* 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);
	}
}