📄 ot_tcp.cp
字号:
/* ***** BEGIN LICENSE BLOCK *****
* Version: RCSL 1.0/RPSL 1.0
*
* Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file, are
* subject to the current version of the RealNetworks Public Source License
* Version 1.0 (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the RealNetworks Community Source License Version 1.0
* (the "RCSL") available at http://www.helixcommunity.org/content/rcsl,
* in which case the RCSL will apply. You may also obtain the license terms
* directly from RealNetworks. You may not use this file except in
* compliance with the RPSL or, if you have a valid RCSL with RealNetworks
* applicable to this file, the RCSL. Please see the applicable RPSL or
* RCSL for the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the portions
* it created.
*
* This file, and the files included with this file, is distributed and made
* available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
#include "hxcom.h"
#include "OT_TCP.h"
#include "MWDebug.h"
#include "hxerrors.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "hxmm.h"
//#define _LOG_DATA 1
//#define USE_DEFERRED_IMPL 1
#if defined(_DEBUG) && defined (_LOG_DATA)
#define DEBUGSTR(x) DebugStr(x)
#else
#define DEBUGSTR(x)
#endif
//#include "dcon.h"
OT_TCP::OT_TCP (void)
: mDNSOpen (FALSE)
, mSocketOpen (FALSE)
, mState (TCP_STATE_CLOSED)
, mDNSRef (0)
, mRemoteHostName (0)
, mNewConnection(NULL)
, mDataReady(FALSE)
{ /* begin OT_TCP */
//dprintf("this:%X OT_TCP::OT_TCP\n", this);
} /* end OT_TCP */
OT_TCP::~OT_TCP (void)
{ /* begin ~OT_TCP */
//dprintf("this:%X OT_TCP::~OT_TCP\n", this);
Cleanup(TRUE);
if(mRemoteHostName)
{
delete mRemoteHostName;
mRemoteHostName = NULL;
}
} /* end ~OT_TCP */
void
OT_TCP::done(void)
{
//dprintf("this:%X OT_TCP::done\n", this);
Cleanup(TRUE);
}
/*----------------------------------------------------------------------------
Cleanup
Cleanup a TCP stream.
Exit: function result = error code.
Any active connection is also aborted, if necessary, before releasing
the stream.
----------------------------------------------------------------------------*/
OSErr OT_TCP::Cleanup (Boolean orderly /* = FALSE */ )
{
//dprintf("this:%X OT_TCP::Cleanup orderly:%s\n", this, (orderly? "TRUE" : "FALSE"));
OSErr theErr = HXR_OK;
Boolean abort;
mState = TCP_STATE_CLOSED;
close_resolver();
if(mRef)
{
abort = (!mOtherSideHasClosed || !mWeHaveClosed) && mConnectionOpen;
if (abort)
{
mComplete = FALSE;
if (orderly && mStartedReceivingData)
{
mComplete = FALSE;
theErr = ::OTSndOrderlyDisconnect(mRef);
EventRecord macEvent;
long ticks = TickCount();
do
{
#ifndef THREADS_SUPPORTED
// xxxbobclark when threading networking is
// on, this code may be executing on a non-main-
// app thread. I don't even know what WNE would
// do in that scenario, but that it'd be bad.
WaitNextEvent(nullEvent, &macEvent, 6,NULL);
#endif
}
while (!mComplete && ((TickCount() - ticks) < 120));
}
else
theErr = ::OTSndDisconnect(mRef, nil);
}
::OTRemoveNotifier(mRef); // DS 12.4.95
theErr = ::OTCloseProvider(mRef);
}
if ( mNewConnection )
{
mNewConnection->done();
HX_RELEASE(mNewConnection);
}
mRef = 0;
return theErr;
}
HX_RESULT
OT_TCP::connect (
const char *host,
UINT16 port,
UINT16 blocking,
ULONG32 ulPlatform )
{
//dprintf("this:%X OT_TCP::connect - host:%s port:%u\n", this, host, port);
HX_RESULT theErr = HXR_OK;
// check if socket is in a valid state
if(mState != TCP_STATE_CLOSED)
return HXR_SOCKET_CREATE; // should be PN_SOCKET_STATE_ERROR
if(mRemoteHostName)
{
delete mRemoteHostName;
mRemoteHostName = NULL;
}
// allocate a buffer to hold the host name
mRemoteHostName = new char[::strlen(host) + 1];
if(mRemoteHostName == NULL)
theErr = HXR_OUTOFMEMORY;
if(!theErr)
{
mConnectionOpen = FALSE;
mRemotePort = port;
mDataFlowOn = FALSE;
mDataArrived = FALSE;
mAsyncError = HXR_OK;
// save a copy of the host name
::strcpy(mRemoteHostName,host);
// check if host name is already in IP format or has been cached
if((::OTInetStringToHost(mRemoteHostName, &mRemoteHost) == HXR_OK) ||
(conn::is_cached(mRemoteHostName,&mRemoteHost)))
{
// open the socket, bind and connect to remote host
mState = TCP_STATE_OPEN_SOCKET;
theErr = open_socket();
}
else // DNR is required on host name
{
// do DNR,open the socket, bind and connect to remote host
theErr = open_resolver();
}
}
if(!theErr && blocking)
{
// wait for mConnectionOpen == TRUE or cancel
}
return theErr;
}
HX_RESULT
OT_TCP::init (
UINT32 local_addr,
UINT16 port,
UINT16 blocking)
{
//dprintf("this:%X OT_TCP::init\n", this);
return (HXR_INVALID_OPERATION);
}
/*----------------------------------------------------------------------------
write
Send data on a stream.
Entry: data = pointer to data to send.
len = length of data to send.
Exit: function result = error code.
----------------------------------------------------------------------------*/
HX_RESULT
OT_TCP::write (
void *data,
UINT16 *len)
{
//dprintf("this:%X OT_TCP::write\n", this);
HX_RESULT theErr = HXR_OK;
mLastError=HXR_OK;
if(mAsyncError)
{
theErr = mAsyncError;
mAsyncError = HXR_OK;
return theErr;
}
OTResult result;
unsigned short length, count;
count = 0;
if (mOtherSideHasClosed) //cz
theErr = HXR_SERVER_DISCONNECTED;
else if (!mOtherSideHasClosed && !mConnectionOpen)
theErr = HXR_WOULD_BLOCK;
else
{
#if 1
if(mDataFlowOn)
{
// DebugStr("\pDataFlowOn");
*len = 0;
return(HXR_WOULD_BLOCK);
}
#endif
length = *len;
while (length > 0 && !theErr)
{
result = ::OTSnd(mRef, data, length, 0);
if (result >= 0)
{
count += result;
length -= result;
}
else
{
#if 0
Str255 s;
NumToString(result,s);
DebugStr(s);
#endif
switch(result)
{
case kOTFlowErr:
mWriteReady = FALSE;
mDataFlowOn = TRUE;
theErr = HXR_WOULD_BLOCK;
break;
case kENOMEMErr:
case kEBUSYErr:
case kOTOutStateErr:
case kEWOULDBLOCKErr:
case kOTStateChangeErr:
case kOTLookErr:
mLastError = HXR_WOULD_BLOCK;
theErr = HXR_WOULD_BLOCK;
break;
default:
#if 0
Str255 s;
DebugStr("\pOT_TCP::read");
NumToString(result,s);
DebugStr(s);
#endif
mLastError = HXR_SERVER_DISCONNECTED;
theErr = HXR_SERVER_DISCONNECTED;
break;
}
break; // break out of the while loop
}
}
}
*len = count; // return actual number of bytes written
return theErr;
}
/*----------------------------------------------------------------------------
read
read data on a stream.
Entry: data = pointer to data buffer.
*len = length of data buffer.
Exit: function result = error code.
*len = number of bytes received.
----------------------------------------------------------------------------*/
HX_RESULT
OT_TCP::read (void *data, UINT16 *len)
{
//dprintf("this:%X OT_TCP::read\n", this);
//dprintf("mConnectionOpen: %s\n", (mConnectionOpen ? "TRUE" : "FALSE") );
//dprintf("mOtherSideHadClosed: %s\n", (mOtherSideHasClosed ? "TRUE" : "FALSE"));
//dprintf("mDataArrived: %s\n", (mDataArrived ? "TRUE" : "FALSE"));
HX_RESULT theErr = HXR_OK;
OTResult result;
mLastError=HXR_OK;
if(mAsyncError)
{
theErr = mAsyncError;
mAsyncError = HXR_OK;
return theErr;
}
if (mOtherSideHasClosed)
theErr = HXR_SERVER_DISCONNECTED;
else if (!mOtherSideHasClosed && !mConnectionOpen)
theErr = HXR_WOULD_BLOCK;
else
{
if(!mDataArrived)
{
*len = 0;
mLastError = HXR_WOULD_BLOCK;
return HXR_WOULD_BLOCK;
}
result = ::OTRcv(mRef, data, *len, nil);
if (result >= 0)
{
//dprintf("data read\n");
*len = result;
theErr = HXR_OK;
}
else
{
//dprintf("read error\n");
switch(result)
{
/* take out this case after HXTCPSocket::TCPSchedulerCallbackProc
gets implemented - we're not getting data fast enough now XXXZach */
case kOTNoDataErr:
*len = 0;
theErr = HXR_OK;
break;
case kEBUSYErr:
case kOTOutStateErr:
case kEWOULDBLOCKErr:
case kOTStateChangeErr:
case kOTLookErr:
*len = 0;
mLastError = HXR_WOULD_BLOCK;
theErr = HXR_WOULD_BLOCK;
break;
default:
#if 0
Str255 s;
DebugStr("\pOT_TCP::read");
NumToString(result,s);
DebugStr(s);
#endif
*len = 0;
mLastError = HXR_SERVER_DISCONNECTED;
theErr = HXR_SERVER_DISCONNECTED; //cz
break;
}
}
}
return theErr;
}
HX_RESULT
OT_TCP::readfrom (REF(IHXBuffer*) pBuffer,
REF(UINT32) ulAddress,
REF(UINT16) ulPort)
{
//dprintf("this:%X OT_TCP::readfrom\n", this);
pBuffer = NULL;
ulAddress = 0;
ulPort = 0;
return HXR_NOTIMPL;
}
HX_RESULT OT_TCP::listen(ULONG32 ulLocalAddr,
UINT16 port,
UINT16 backlog,
UINT16 blocking,
ULONG32 ulPlatform)
{
//dprintf("this:%X OT_TCP::listen address:%X port:%u\n", this, ulLocalAddr, port);
// check if socket is in a valid state
if(mState != TCP_STATE_CLOSED)
return HXR_UNEXPECTED; // should be PN_SOCKET_STATE_ERROR
OSErr theErr = HXR_OK;
InetAddress reqAd,retAd;
TBind req,ret;
// Open TCP endpoint
mState = TCP_STATE_OPEN_LISTEN;
mComplete = false;
// Note: We are using the UDPTCPNotifyProc... Therefore we do
// not get a Proccess command call at interupt time. Normal
// operation somehow gets away with it...
#ifdef _CARBON
theErr = ::OTAsyncOpenEndpointInContext(OTCreateConfiguration(kTCPName), 0,NULL,
(OTNotifyUPP)UDPTCPNotifyProc, this, NULL);
#else
theErr = ::OTAsyncOpenEndpoint(OTCreateConfiguration(kTCPName),
0,NULL, UDPTCPNotifyProc, this);
#endif
if ( theErr )
{
mLastError = theErr;
theErr = HXR_SOCKET_CREATE;
}
// wait for open completion
if(!theErr)
{
theErr = OTWait();
if(theErr == kOTNoDataErr) theErr = HXR_OK;
if(theErr || mCode != T_OPENCOMPLETE)
{
theErr = theErr ? theErr : HXR_SOCKET_CREATE;
mLastError = theErr;
theErr = HXR_SOCKET_CREATE;
}
}
if ( !theErr )
{
// get Inet address of port
OTInitInetAddress(&reqAd, port, (InetHost) ulLocalAddr);
// bind tcp to current address and requested port
req.addr.maxlen = sizeof(struct InetAddress);
req.addr.len = sizeof(struct InetAddress);
req.addr.buf = (unsigned char *) &reqAd;
req.qlen = 1;
ret.addr.maxlen = sizeof(struct InetAddress);
ret.addr.len = sizeof(struct InetAddress);
ret.addr.buf = (unsigned char *) &retAd;
// clear completion flag
mComplete = false;
mState = TCP_STATE_BIND_LISTEN;
// bind provider to return structure
theErr = OTBind(mRef, &req, &ret);
}
if(theErr)
{
mLastError = theErr;
theErr = HXR_BIND;
}
// wait for bind completion
if(!theErr)
{
theErr = OTWait();
if(theErr == kOTNoDataErr) theErr = HXR_OK;
if(theErr || mCode != T_BINDCOMPLETE)
{
theErr = theErr ? theErr : HXR_BIND;
mLastError = theErr;
theErr = HXR_BIND;
}
}
// get local port
if(!theErr)
{
mConnectionOpen = FALSE;
mRemotePort = port;
mDataFlowOn = FALSE;
mDataArrived = FALSE;
mAsyncError = HXR_OK;
mState = TCP_STATE_LISTEN;
}
if ( !theErr )
{
// check to see if we are not being called again...
// calling done() on mNewConnection should be fine, because
// it should be released after a connection has been accepted.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -