738554331b
PR: 241
1607 lines
37 KiB
C++
1607 lines
37 KiB
C++
/*
|
|
* A simple socket-like package.
|
|
* This could undoubtedly be improved, since it does polling and busy-waiting.
|
|
* At least it uses asynch I/O and implements timeouts!
|
|
*
|
|
* Other funkiness includes the use of my own (possibly brain-damaged) error-handling infrastructure.
|
|
*
|
|
* -Roy Wood (roy@centricsystems.ca)
|
|
*
|
|
*/
|
|
|
|
|
|
/* ====================================================================
|
|
* Copyright (c) 1998-1999 The OpenSSL Project. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in
|
|
* the documentation and/or other materials provided with the
|
|
* distribution.
|
|
*
|
|
* 3. All advertising materials mentioning features or use of this
|
|
* software must display the following acknowledgment:
|
|
* "This product includes software developed by the OpenSSL Project
|
|
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
|
|
*
|
|
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
|
|
* endorse or promote products derived from this software without
|
|
* prior written permission. For written permission, please contact
|
|
* openssl-core@openssl.org.
|
|
*
|
|
* 5. Products derived from this software may not be called "OpenSSL"
|
|
* nor may "OpenSSL" appear in their names without prior written
|
|
* permission of the OpenSSL Project.
|
|
*
|
|
* 6. Redistributions of any form whatsoever must retain the following
|
|
* acknowledgment:
|
|
* "This product includes software developed by the OpenSSL Project
|
|
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
|
|
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
|
|
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
* ====================================================================
|
|
*
|
|
* This product includes cryptographic software written by Eric Young
|
|
* (eay@cryptsoft.com). This product includes software written by Tim
|
|
* Hudson (tjh@cryptsoft.com).
|
|
*
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include "MacSocket.h"
|
|
|
|
#include <Threads.h>
|
|
|
|
#include <OpenTransport.h>
|
|
#include <OpenTpTInternet.h>
|
|
#include <OpenTptClient.h>
|
|
|
|
|
|
|
|
#include "CPStringUtils.hpp"
|
|
#include "ErrorHandling.hpp"
|
|
|
|
|
|
// #define MACSOCKET_DEBUG 1
|
|
|
|
#ifdef MACSOCKET_DEBUG
|
|
#include <stdio.h>
|
|
#endif
|
|
|
|
|
|
|
|
extern int errno;
|
|
|
|
|
|
#define kMaxNumSockets 4
|
|
|
|
|
|
struct SocketStruct
|
|
{
|
|
Boolean mIsInUse;
|
|
|
|
Boolean mEndpointIsBound;
|
|
|
|
Boolean mLocalEndIsConnected;
|
|
Boolean mRemoteEndIsConnected;
|
|
|
|
Boolean mReceivedTOpenComplete;
|
|
Boolean mReceivedTBindComplete;
|
|
Boolean mReceivedTConnect;
|
|
Boolean mReceivedTListen;
|
|
Boolean mReceivedTPassCon;
|
|
Boolean mReceivedTDisconnect;
|
|
Boolean mReceivedTOrdRel;
|
|
Boolean mReceivedTDisconnectComplete;
|
|
|
|
long mTimeoutTicks;
|
|
long mOperationStartTicks;
|
|
|
|
MacSocket_IdleWaitCallback mIdleWaitCallback;
|
|
void *mUserRefPtr;
|
|
|
|
OTEventCode mExpectedCode;
|
|
OTResult mAsyncOperationResult;
|
|
|
|
EndpointRef mEndPointRef;
|
|
TBind *mBindRequestedAddrInfo;
|
|
TBind *mAssignedAddrInfo;
|
|
TCall *mRemoteAddrInfo;
|
|
|
|
Boolean mReadyToReadData;
|
|
Boolean mReadyToWriteData;
|
|
|
|
Ptr mReadBuffer;
|
|
Ptr mWriteBuffer;
|
|
|
|
int mLastError;
|
|
char mErrMessage[256];
|
|
};
|
|
|
|
typedef struct SocketStruct SocketStruct;
|
|
|
|
|
|
static SocketStruct sSockets[kMaxNumSockets];
|
|
static Boolean sSocketsSetup = false;
|
|
|
|
|
|
|
|
|
|
static OSErr MyBusyWait(SocketStruct *ioSocket,Boolean returnImmediatelyOnError,OTResult *outOTResult,Boolean *inAsyncOperationCompleteFlag);
|
|
|
|
static pascal void OTNonYieldingNotifier(void *contextPtr,OTEventCode code,OTResult result,void *cookie);
|
|
|
|
static Boolean SocketIndexIsValid(const int inSocketNum);
|
|
|
|
static void InitSocket(SocketStruct *ioSocket);
|
|
|
|
static void PrepareForAsyncOperation(SocketStruct *ioSocket,const OTEventCode inExpectedCode);
|
|
|
|
static Boolean TimeoutElapsed(const SocketStruct *inSocket);
|
|
|
|
static OSStatus NegotiateIPReuseAddrOption(EndpointRef inEndpoint,const Boolean inEnableReuseIP);
|
|
|
|
|
|
|
|
void MacSocket_GetSocketErrorInfo(const int inSocketNum,int *outSocketErrCode,char *outSocketErrString,const int inSocketErrStringMaxLength)
|
|
{
|
|
if (outSocketErrCode != nil)
|
|
{
|
|
*outSocketErrCode = -1;
|
|
}
|
|
|
|
if (outSocketErrString != nil)
|
|
{
|
|
CopyCStrToCStr("",outSocketErrString,inSocketErrStringMaxLength);
|
|
}
|
|
|
|
|
|
if (SocketIndexIsValid(inSocketNum))
|
|
{
|
|
SocketStruct *theSocketStruct = &(sSockets[inSocketNum]);
|
|
|
|
|
|
if (outSocketErrCode != nil)
|
|
{
|
|
*outSocketErrCode = theSocketStruct->mLastError;
|
|
}
|
|
|
|
if (outSocketErrString != nil)
|
|
{
|
|
CopyCStrToCStr(theSocketStruct->mErrMessage,outSocketErrString,inSocketErrStringMaxLength);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void MacSocket_SetUserRefPtr(const int inSocketNum,void *inNewRefPtr)
|
|
{
|
|
if (SocketIndexIsValid(inSocketNum))
|
|
{
|
|
SocketStruct *theSocketStruct = &(sSockets[inSocketNum]);
|
|
|
|
theSocketStruct->mUserRefPtr = inNewRefPtr;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void MacSocket_GetLocalIPAndPort(const int inSocketNum,char *outIPAndPort,const int inIPAndPortLength)
|
|
{
|
|
if (outIPAndPort != nil && SocketIndexIsValid(inSocketNum))
|
|
{
|
|
char tempString[256];
|
|
SocketStruct *theSocketStruct = &(sSockets[inSocketNum]);
|
|
|
|
|
|
CopyCStrToCStr("",tempString,sizeof(tempString));
|
|
|
|
if (theSocketStruct->mAssignedAddrInfo != nil)
|
|
{
|
|
InetAddress *theInetAddress = (InetAddress *) theSocketStruct->mAssignedAddrInfo->addr.buf;
|
|
InetHost theInetHost = theInetAddress->fHost;
|
|
|
|
if (theInetHost == 0)
|
|
{
|
|
InetInterfaceInfo theInetInterfaceInfo;
|
|
|
|
if (::OTInetGetInterfaceInfo(&theInetInterfaceInfo,kDefaultInetInterface) == noErr)
|
|
{
|
|
theInetHost = theInetInterfaceInfo.fAddress;
|
|
}
|
|
}
|
|
|
|
::OTInetHostToString(theInetHost,tempString);
|
|
|
|
ConcatCStrToCStr(":",tempString,sizeof(tempString));
|
|
ConcatLongIntToCStr(theInetAddress->fPort,tempString,sizeof(tempString));
|
|
}
|
|
|
|
CopyCStrToCStr(tempString,outIPAndPort,inIPAndPortLength);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void MacSocket_GetRemoteIPAndPort(const int inSocketNum,char *outIPAndPort,const int inIPAndPortLength)
|
|
{
|
|
if (outIPAndPort != nil && SocketIndexIsValid(inSocketNum))
|
|
{
|
|
char tempString[256];
|
|
SocketStruct *theSocketStruct = &(sSockets[inSocketNum]);
|
|
|
|
|
|
CopyCStrToCStr("",tempString,sizeof(tempString));
|
|
|
|
if (theSocketStruct->mRemoteAddrInfo != nil)
|
|
{
|
|
InetAddress *theInetAddress = (InetAddress *) theSocketStruct->mRemoteAddrInfo->addr.buf;
|
|
InetHost theInetHost = theInetAddress->fHost;
|
|
|
|
if (theInetHost == 0)
|
|
{
|
|
InetInterfaceInfo theInetInterfaceInfo;
|
|
|
|
if (::OTInetGetInterfaceInfo(&theInetInterfaceInfo,kDefaultInetInterface) == noErr)
|
|
{
|
|
theInetHost = theInetInterfaceInfo.fAddress;
|
|
}
|
|
}
|
|
|
|
::OTInetHostToString(theInetHost,tempString);
|
|
|
|
ConcatCStrToCStr(":",tempString,sizeof(tempString));
|
|
ConcatLongIntToCStr(theInetAddress->fPort,tempString,sizeof(tempString));
|
|
}
|
|
|
|
CopyCStrToCStr(tempString,outIPAndPort,inIPAndPortLength);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
Boolean MacSocket_RemoteEndIsClosing(const int inSocketNum)
|
|
{
|
|
Boolean theResult = false;
|
|
|
|
if (SocketIndexIsValid(inSocketNum))
|
|
{
|
|
SocketStruct *theSocketStruct = &(sSockets[inSocketNum]);
|
|
|
|
theResult = theSocketStruct->mReceivedTOrdRel;
|
|
}
|
|
|
|
return(theResult);
|
|
}
|
|
|
|
|
|
|
|
Boolean MacSocket_ListenCompleted(const int inSocketNum)
|
|
{
|
|
Boolean theResult = false;
|
|
|
|
if (SocketIndexIsValid(inSocketNum))
|
|
{
|
|
SocketStruct *theSocketStruct = &(sSockets[inSocketNum]);
|
|
|
|
theResult = theSocketStruct->mReceivedTPassCon;
|
|
}
|
|
|
|
return(theResult);
|
|
}
|
|
|
|
|
|
|
|
Boolean MacSocket_RemoteEndIsOpen(const int inSocketNum)
|
|
{
|
|
if (SocketIndexIsValid(inSocketNum))
|
|
{
|
|
SocketStruct *theSocketStruct = &(sSockets[inSocketNum]);
|
|
|
|
return(theSocketStruct->mRemoteEndIsConnected);
|
|
}
|
|
|
|
else
|
|
{
|
|
return(false);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
Boolean MacSocket_LocalEndIsOpen(const int inSocketNum)
|
|
{
|
|
if (SocketIndexIsValid(inSocketNum))
|
|
{
|
|
SocketStruct *theSocketStruct = &(sSockets[inSocketNum]);
|
|
|
|
return(theSocketStruct->mLocalEndIsConnected);
|
|
}
|
|
|
|
else
|
|
{
|
|
return(false);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static Boolean TimeoutElapsed(const SocketStruct *inSocket)
|
|
{
|
|
Boolean timeIsUp = false;
|
|
|
|
if (inSocket != nil && inSocket->mTimeoutTicks > 0 && ::TickCount() > inSocket->mOperationStartTicks + inSocket->mTimeoutTicks)
|
|
{
|
|
timeIsUp = true;
|
|
}
|
|
|
|
|
|
return(timeIsUp);
|
|
}
|
|
|
|
|
|
|
|
static Boolean SocketIndexIsValid(const int inSocketNum)
|
|
{
|
|
if (inSocketNum >= 0 && inSocketNum < kMaxNumSockets && sSockets[inSocketNum].mEndPointRef != kOTInvalidEndpointRef)
|
|
{
|
|
return(true);
|
|
}
|
|
|
|
else
|
|
{
|
|
return(false);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void InitSocket(SocketStruct *ioSocket)
|
|
{
|
|
ioSocket->mIsInUse = false;
|
|
|
|
ioSocket->mEndpointIsBound = false;
|
|
|
|
ioSocket->mLocalEndIsConnected = false;
|
|
ioSocket->mRemoteEndIsConnected = false;
|
|
|
|
ioSocket->mReceivedTOpenComplete = false;
|
|
ioSocket->mReceivedTBindComplete = false;
|
|
ioSocket->mReceivedTConnect = false;
|
|
ioSocket->mReceivedTListen = false;
|
|
ioSocket->mReceivedTPassCon = false;
|
|
ioSocket->mReceivedTDisconnect = false;
|
|
ioSocket->mReceivedTOrdRel = false;
|
|
ioSocket->mReceivedTDisconnectComplete = false;
|
|
|
|
ioSocket->mTimeoutTicks = 30 * 60;
|
|
ioSocket->mOperationStartTicks = -1;
|
|
|
|
ioSocket->mIdleWaitCallback = nil;
|
|
ioSocket->mUserRefPtr = nil;
|
|
|
|
ioSocket->mExpectedCode = 0;
|
|
ioSocket->mAsyncOperationResult = noErr;
|
|
|
|
ioSocket->mEndPointRef = kOTInvalidEndpointRef;
|
|
|
|
ioSocket->mBindRequestedAddrInfo = nil;
|
|
ioSocket->mAssignedAddrInfo = nil;
|
|
ioSocket->mRemoteAddrInfo = nil;
|
|
|
|
ioSocket->mReadyToReadData = false;
|
|
ioSocket->mReadyToWriteData = true;
|
|
|
|
ioSocket->mReadBuffer = nil;
|
|
ioSocket->mWriteBuffer = nil;
|
|
|
|
ioSocket->mLastError = noErr;
|
|
CopyCStrToCStr("",ioSocket->mErrMessage,sizeof(ioSocket->mErrMessage));
|
|
}
|
|
|
|
|
|
|
|
static void PrepareForAsyncOperation(SocketStruct *ioSocket,const OTEventCode inExpectedCode)
|
|
{
|
|
ioSocket->mOperationStartTicks = ::TickCount();
|
|
|
|
ioSocket->mAsyncOperationResult = noErr;
|
|
|
|
ioSocket->mExpectedCode = inExpectedCode;
|
|
}
|
|
|
|
|
|
// The wait function....
|
|
|
|
static OSErr MyBusyWait(SocketStruct *ioSocket,Boolean returnImmediatelyOnError,OTResult *outOTResult,Boolean *inAsyncOperationCompleteFlag)
|
|
{
|
|
OSErr errCode = noErr;
|
|
OTResult theOTResult = noErr;
|
|
|
|
|
|
SetErrorMessageAndBailIfNil(ioSocket,"MyBusyWait: Bad parameter, ioSocket = nil");
|
|
SetErrorMessageAndBailIfNil(inAsyncOperationCompleteFlag,"MyBusyWait: Bad parameter, inAsyncOperationCompleteFlag = nil");
|
|
|
|
for (;;)
|
|
{
|
|
if (*inAsyncOperationCompleteFlag)
|
|
{
|
|
theOTResult = ioSocket->mAsyncOperationResult;
|
|
|
|
break;
|
|
}
|
|
|
|
if (ioSocket->mIdleWaitCallback != nil)
|
|
{
|
|
theOTResult = (*(ioSocket->mIdleWaitCallback))(ioSocket->mUserRefPtr);
|
|
|
|
if (theOTResult != noErr && returnImmediatelyOnError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (TimeoutElapsed(ioSocket))
|
|
{
|
|
theOTResult = kMacSocket_TimeoutErr;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
EXITPOINT:
|
|
|
|
if (outOTResult != nil)
|
|
{
|
|
*outOTResult = theOTResult;
|
|
}
|
|
|
|
return(errCode);
|
|
}
|
|
|
|
|
|
|
|
// I used to do thread switching, but stopped. It could easily be rolled back in though....
|
|
|
|
static pascal void OTNonYieldingNotifier(void *contextPtr,OTEventCode code,OTResult result,void *cookie)
|
|
{
|
|
SocketStruct *theSocketStruct = (SocketStruct *) contextPtr;
|
|
|
|
if (theSocketStruct != nil)
|
|
{
|
|
if (theSocketStruct->mExpectedCode != 0 && code == theSocketStruct->mExpectedCode)
|
|
{
|
|
theSocketStruct->mAsyncOperationResult = result;
|
|
|
|
theSocketStruct->mExpectedCode = 0;
|
|
}
|
|
|
|
|
|
switch (code)
|
|
{
|
|
case T_OPENCOMPLETE:
|
|
{
|
|
theSocketStruct->mReceivedTOpenComplete = true;
|
|
|
|
theSocketStruct->mEndPointRef = (EndpointRef) cookie;
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
case T_BINDCOMPLETE:
|
|
{
|
|
theSocketStruct->mReceivedTBindComplete = true;
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
case T_CONNECT:
|
|
{
|
|
theSocketStruct->mReceivedTConnect = true;
|
|
|
|
theSocketStruct->mLocalEndIsConnected = true;
|
|
|
|
theSocketStruct->mRemoteEndIsConnected = true;
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
case T_LISTEN:
|
|
{
|
|
theSocketStruct->mReceivedTListen = true;
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
case T_PASSCON:
|
|
{
|
|
theSocketStruct->mReceivedTPassCon = true;
|
|
|
|
theSocketStruct->mLocalEndIsConnected = true;
|
|
|
|
theSocketStruct->mRemoteEndIsConnected = true;
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
case T_DATA:
|
|
{
|
|
theSocketStruct->mReadyToReadData = true;
|
|
|
|
break;
|
|
}
|
|
|
|
case T_GODATA:
|
|
{
|
|
theSocketStruct->mReadyToWriteData = true;
|
|
|
|
break;
|
|
}
|
|
|
|
case T_DISCONNECT:
|
|
{
|
|
theSocketStruct->mReceivedTDisconnect = true;
|
|
|
|
theSocketStruct->mRemoteEndIsConnected = false;
|
|
|
|
theSocketStruct->mLocalEndIsConnected = false;
|
|
|
|
::OTRcvDisconnect(theSocketStruct->mEndPointRef,nil);
|
|
|
|
break;
|
|
}
|
|
|
|
case T_ORDREL:
|
|
{
|
|
theSocketStruct->mReceivedTOrdRel = true;
|
|
|
|
// We can still write data, so don't clear mRemoteEndIsConnected
|
|
|
|
::OTRcvOrderlyDisconnect(theSocketStruct->mEndPointRef);
|
|
|
|
break;
|
|
}
|
|
|
|
case T_DISCONNECTCOMPLETE:
|
|
{
|
|
theSocketStruct->mReceivedTDisconnectComplete = true;
|
|
|
|
theSocketStruct->mRemoteEndIsConnected = false;
|
|
|
|
theSocketStruct->mLocalEndIsConnected = false;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
T_LISTEN OTListen
|
|
T_CONNECT OTRcvConnect
|
|
T_DATA OTRcv, OTRcvUData
|
|
T_DISCONNECT OTRcvDisconnect
|
|
T_ORDREL OTRcvOrderlyDisconnect
|
|
T_GODATA OTSnd, OTSndUData, OTLook
|
|
T_PASSCON none
|
|
|
|
T_EXDATA OTRcv
|
|
T_GOEXDATA OTSnd, OTLook
|
|
T_UDERR OTRcvUDErr
|
|
*/
|
|
}
|
|
|
|
|
|
|
|
// Initialize the main socket data structure
|
|
|
|
OSErr MacSocket_Startup(void)
|
|
{
|
|
if (!sSocketsSetup)
|
|
{
|
|
for (int i = 0;i < kMaxNumSockets;i++)
|
|
{
|
|
InitSocket(&(sSockets[i]));
|
|
}
|
|
|
|
::InitOpenTransport();
|
|
|
|
sSocketsSetup = true;
|
|
}
|
|
|
|
|
|
return(noErr);
|
|
}
|
|
|
|
|
|
|
|
// Cleanup before exiting
|
|
|
|
OSErr MacSocket_Shutdown(void)
|
|
{
|
|
if (sSocketsSetup)
|
|
{
|
|
for (int i = 0;i < kMaxNumSockets;i++)
|
|
{
|
|
SocketStruct *theSocketStruct = &(sSockets[i]);
|
|
|
|
if (theSocketStruct->mIsInUse)
|
|
{
|
|
if (theSocketStruct->mEndPointRef != kOTInvalidEndpointRef)
|
|
{
|
|
OTResult theOTResult;
|
|
|
|
|
|
// Since we're killing the endpoint, I don't bother to send the disconnect (sorry!)
|
|
|
|
/*
|
|
if (theSocketStruct->mLocalEndIsConnected)
|
|
{
|
|
// This is an abortive action, so we do a hard disconnect instead of an OTSndOrderlyDisconnect
|
|
|
|
theOTResult = ::OTSndDisconnect(theSocketStruct->mEndPointRef, nil);
|
|
|
|
// Now we have to watch for T_DISCONNECTCOMPLETE event
|
|
|
|
theSocketStruct->mLocalEndIsConnected = false;
|
|
}
|
|
*/
|
|
|
|
theOTResult = ::OTCloseProvider(theSocketStruct->mEndPointRef);
|
|
|
|
|
|
theSocketStruct->mEndPointRef = kOTInvalidEndpointRef;
|
|
}
|
|
|
|
if (theSocketStruct->mBindRequestedAddrInfo != nil)
|
|
{
|
|
::OTFree((void *) theSocketStruct->mBindRequestedAddrInfo,T_BIND);
|
|
|
|
theSocketStruct->mBindRequestedAddrInfo = nil;
|
|
}
|
|
|
|
if (theSocketStruct->mAssignedAddrInfo != nil)
|
|
{
|
|
::OTFree((void *) theSocketStruct->mAssignedAddrInfo,T_BIND);
|
|
|
|
theSocketStruct->mAssignedAddrInfo = nil;
|
|
}
|
|
|
|
if (theSocketStruct->mRemoteAddrInfo != nil)
|
|
{
|
|
::OTFree((void *) theSocketStruct->mRemoteAddrInfo,T_CALL);
|
|
|
|
theSocketStruct->mRemoteAddrInfo = nil;
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
|
|
::CloseOpenTransport();
|
|
|
|
sSocketsSetup = false;
|
|
}
|
|
|
|
return(noErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Allocate a socket
|
|
|
|
OSErr MacSocket_socket(int *outSocketNum,const Boolean inDoThreadSwitching,const long inTimeoutTicks,MacSocket_IdleWaitCallback inIdleWaitCallback,void *inUserRefPtr)
|
|
{
|
|
// Gotta roll support back in for threads eventually.....
|
|
|
|
#pragma unused(inDoThreadSwitching)
|
|
|
|
|
|
OSErr errCode = noErr;
|
|
|
|
|
|
SetErrorMessageAndBailIfNil(outSocketNum,"MacSocket_socket: Bad parameter, outSocketNum == nil");
|
|
|
|
*outSocketNum = -1;
|
|
|
|
|
|
// Find an unused socket
|
|
|
|
for (int i = 0;i < kMaxNumSockets;i++)
|
|
{
|
|
if (sSockets[i].mIsInUse == false)
|
|
{
|
|
OTResult theOTResult;
|
|
SocketStruct *theSocketStruct = &(sSockets[i]);
|
|
|
|
|
|
InitSocket(theSocketStruct);
|
|
|
|
theSocketStruct->mIdleWaitCallback = inIdleWaitCallback;
|
|
theSocketStruct->mUserRefPtr = inUserRefPtr;
|
|
|
|
theSocketStruct->mTimeoutTicks = inTimeoutTicks;
|
|
|
|
|
|
// Set up OT endpoint
|
|
|
|
PrepareForAsyncOperation(theSocketStruct,T_OPENCOMPLETE);
|
|
|
|
theOTResult = ::OTAsyncOpenEndpoint(OTCreateConfiguration(kTCPName),0,nil,OTNonYieldingNotifier,(void *) theSocketStruct);
|
|
|
|
SetErrorMessageAndLongIntAndBailIfError(theOTResult,"MacSocket_socket: Can't create OT endpoint, OTAsyncOpenEndpoint() = ",theOTResult);
|
|
|
|
BailIfError(MyBusyWait(theSocketStruct,false,&theOTResult,&(theSocketStruct->mReceivedTOpenComplete)));
|
|
|
|
SetErrorMessageAndLongIntAndBailIfError(theOTResult,"MacSocket_socket: Can't create OT endpoint, OTAsyncOpenEndpoint() = ",theOTResult);
|
|
|
|
|
|
*outSocketNum = i;
|
|
|
|
errCode = noErr;
|
|
|
|
theSocketStruct->mIsInUse = true;
|
|
|
|
break;
|
|
}
|
|
|
|
else if (i == kMaxNumSockets - 1)
|
|
{
|
|
SetErrorMessageAndBail("MacSocket_socket: No sockets available");
|
|
}
|
|
}
|
|
|
|
|
|
EXITPOINT:
|
|
|
|
errno = errCode;
|
|
|
|
return(errCode);
|
|
}
|
|
|
|
|
|
|
|
|
|
OSErr MacSocket_listen(const int inSocketNum,const int inPortNum)
|
|
{
|
|
OSErr errCode = noErr;
|
|
SocketStruct *theSocketStruct = nil;
|
|
|
|
|
|
if (!SocketIndexIsValid(inSocketNum))
|
|
{
|
|
SetErrorMessageAndBail("MacSocket_listen: Invalid socket number specified");
|
|
}
|
|
|
|
|
|
theSocketStruct = &(sSockets[inSocketNum]);
|
|
|
|
|
|
OTResult theOTResult;
|
|
|
|
|
|
if (theSocketStruct->mBindRequestedAddrInfo == nil)
|
|
{
|
|
theSocketStruct->mBindRequestedAddrInfo = (TBind *) ::OTAlloc(theSocketStruct->mEndPointRef,T_BIND,T_ADDR,&theOTResult);
|
|
|
|
SetErrorMessageAndLongIntAndBailIfError(theOTResult,"MacSocket_listen: Can't allocate OT T_BIND structure, OTAlloc() = ",theOTResult);
|
|
SetErrorMessageAndBailIfNil(theSocketStruct->mBindRequestedAddrInfo,"MacSocket_listen: Can't allocate OT T_BIND structure, OTAlloc() returned nil");
|
|
}
|
|
|
|
if (theSocketStruct->mAssignedAddrInfo == nil)
|
|
{
|
|
theSocketStruct->mAssignedAddrInfo = (TBind *) ::OTAlloc(theSocketStruct->mEndPointRef,T_BIND,T_ADDR,&theOTResult);
|
|
|
|
SetErrorMessageAndLongIntAndBailIfError(theOTResult,"MacSocket_listen: Can't allocate OT T_BIND structure, OTAlloc() = ",theOTResult);
|
|
SetErrorMessageAndBailIfNil(theSocketStruct->mAssignedAddrInfo,"MacSocket_listen: Can't allocate OT T_BIND structure, OTAlloc() returned nil");
|
|
}
|
|
|
|
if (theSocketStruct->mRemoteAddrInfo == nil)
|
|
{
|
|
theSocketStruct->mRemoteAddrInfo = (TCall *) ::OTAlloc(theSocketStruct->mEndPointRef,T_CALL,T_ADDR,&theOTResult);
|
|
|
|
SetErrorMessageAndLongIntAndBailIfError(theOTResult,"MacSocket_listen: Can't allocate OT T_CALL structure, OTAlloc() = ",theOTResult);
|
|
SetErrorMessageAndBailIfNil(theSocketStruct->mRemoteAddrInfo,"MacSocket_listen: Can't allocate OT T_CALL structure, OTAlloc() returned nil");
|
|
}
|
|
|
|
|
|
if (!theSocketStruct->mEndpointIsBound)
|
|
{
|
|
InetInterfaceInfo theInetInterfaceInfo;
|
|
|
|
theOTResult = ::OTInetGetInterfaceInfo(&theInetInterfaceInfo,kDefaultInetInterface);
|
|
|
|
SetErrorMessageAndLongIntAndBailIfError(theOTResult,"MacSocket_listen: Can't determine OT interface info, OTInetGetInterfaceInfo() = ",theOTResult);
|
|
|
|
|
|
InetAddress *theInetAddress = (InetAddress *) theSocketStruct->mBindRequestedAddrInfo->addr.buf;
|
|
|
|
// theInetAddress->fAddressType = AF_INET;
|
|
// theInetAddress->fPort = inPortNum;
|
|
// theInetAddress->fHost = theInetInterfaceInfo.fAddress;
|
|
|
|
::OTInitInetAddress(theInetAddress,inPortNum,theInetInterfaceInfo.fAddress);
|
|
|
|
theSocketStruct->mBindRequestedAddrInfo->addr.len = sizeof(InetAddress);
|
|
|
|
theSocketStruct->mBindRequestedAddrInfo->qlen = 1;
|
|
|
|
|
|
theOTResult = ::OTSetSynchronous(theSocketStruct->mEndPointRef);
|
|
|
|
SetErrorMessageAndLongIntAndBailIfError(theOTResult,"MacSocket_listen: Can't set OT endpoint mode, OTSetSynchronous() = ",theOTResult);
|
|
|
|
theOTResult = NegotiateIPReuseAddrOption(theSocketStruct->mEndPointRef,true);
|
|
|
|
SetErrorMessageAndLongIntAndBailIfError(theOTResult,"MacSocket_listen: Can't set OT IP address reuse flag, NegotiateIPReuseAddrOption() = ",theOTResult);
|
|
|
|
theOTResult = ::OTSetAsynchronous(theSocketStruct->mEndPointRef);
|
|
|
|
SetErrorMessageAndLongIntAndBailIfError(theOTResult,"MacSocket_listen: Can't set OT endpoint mode, OTSetAsynchronous() = ",theOTResult);
|
|
|
|
|
|
PrepareForAsyncOperation(theSocketStruct,T_BINDCOMPLETE);
|
|
|
|
theOTResult = ::OTBind(theSocketStruct->mEndPointRef,theSocketStruct->mBindRequestedAddrInfo,theSocketStruct->mAssignedAddrInfo);
|
|
|
|
SetErrorMessageAndLongIntAndBailIfError(theOTResult,"MacSocket_listen: Can't bind OT endpoint, OTBind() = ",theOTResult);
|
|
|
|
BailIfError(MyBusyWait(theSocketStruct,false,&theOTResult,&(theSocketStruct->mReceivedTBindComplete)));
|
|
|
|
SetErrorMessageAndLongIntAndBailIfError(theOTResult,"MacSocket_listen: Can't bind OT endpoint, OTBind() = ",theOTResult);
|
|
|
|
|
|
theSocketStruct->mEndpointIsBound = true;
|
|
}
|
|
|
|
|
|
PrepareForAsyncOperation(theSocketStruct,T_LISTEN);
|
|
|
|
theOTResult = ::OTListen(theSocketStruct->mEndPointRef,theSocketStruct->mRemoteAddrInfo);
|
|
|
|
if (theOTResult == noErr)
|
|
{
|
|
PrepareForAsyncOperation(theSocketStruct,T_PASSCON);
|
|
|
|
theOTResult = ::OTAccept(theSocketStruct->mEndPointRef,theSocketStruct->mEndPointRef,theSocketStruct->mRemoteAddrInfo);
|
|
|
|
SetErrorMessageAndLongIntAndBailIfError(theOTResult,"MacSocket_listen: Can't begin OT accept, OTAccept() = ",theOTResult);
|
|
|
|
BailIfError(MyBusyWait(theSocketStruct,false,&theOTResult,&(theSocketStruct->mReceivedTPassCon)));
|
|
|
|
SetErrorMessageAndLongIntAndBailIfError(theOTResult,"MacSocket_listen: Can't accept OT connection, OTAccept() = ",theOTResult);
|
|
}
|
|
|
|
else if (theOTResult == kOTNoDataErr)
|
|
{
|
|
theOTResult = noErr;
|
|
}
|
|
|
|
else
|
|
{
|
|
SetErrorMessageAndLongIntAndBail("MacSocket_listen: Can't begin OT listen, OTListen() = ",theOTResult);
|
|
}
|
|
|
|
|
|
errCode = noErr;
|
|
|
|
|
|
EXITPOINT:
|
|
|
|
if (theSocketStruct != nil)
|
|
{
|
|
theSocketStruct->mLastError = noErr;
|
|
|
|
CopyCStrToCStr("",theSocketStruct->mErrMessage,sizeof(theSocketStruct->mErrMessage));
|
|
|
|
if (errCode != noErr)
|
|
{
|
|
theSocketStruct->mLastError = errCode;
|
|
|
|
CopyCStrToCStr(GetErrorMessage(),theSocketStruct->mErrMessage,sizeof(theSocketStruct->mErrMessage));
|
|
}
|
|
}
|
|
|
|
errno = errCode;
|
|
|
|
return(errCode);
|
|
}
|
|
|
|
|
|
|
|
|
|
OSErr MacSocket_connect(const int inSocketNum,char *inTargetAddressAndPort)
|
|
{
|
|
OSErr errCode = noErr;
|
|
SocketStruct *theSocketStruct = nil;
|
|
|
|
|
|
if (!SocketIndexIsValid(inSocketNum))
|
|
{
|
|
SetErrorMessageAndBail("MacSocket_connect: Invalid socket number specified");
|
|
}
|
|
|
|
theSocketStruct = &(sSockets[inSocketNum]);
|
|
|
|
if (theSocketStruct->mEndpointIsBound)
|
|
{
|
|
SetErrorMessageAndBail("MacSocket_connect: Socket previously bound");
|
|
}
|
|
|
|
|
|
OTResult theOTResult;
|
|
|
|
theSocketStruct->mBindRequestedAddrInfo = (TBind *) ::OTAlloc(theSocketStruct->mEndPointRef,T_BIND,T_ADDR,&theOTResult);
|
|
|
|
SetErrorMessageAndLongIntAndBailIfError(theOTResult,"MacSocket_connect: Can't allocate OT T_BIND structure, OTAlloc() = ",theOTResult);
|
|
SetErrorMessageAndBailIfNil(theSocketStruct->mBindRequestedAddrInfo,"MacSocket_connect: Can't allocate OT T_BIND structure, OTAlloc() returned nil");
|
|
|
|
|
|
theSocketStruct->mAssignedAddrInfo = (TBind *) ::OTAlloc(theSocketStruct->mEndPointRef,T_BIND,T_ADDR,&theOTResult);
|
|
|
|
SetErrorMessageAndLongIntAndBailIfError(theOTResult,"MacSocket_connect: Can't allocate OT T_BIND structure, OTAlloc() = ",theOTResult);
|
|
SetErrorMessageAndBailIfNil(theSocketStruct->mAssignedAddrInfo,"MacSocket_connect: Can't allocate OT T_BIND structure, OTAlloc() returned nil");
|
|
|
|
|
|
theSocketStruct->mRemoteAddrInfo = (TCall *) ::OTAlloc(theSocketStruct->mEndPointRef,T_CALL,T_ADDR,&theOTResult);
|
|
|
|
SetErrorMessageAndLongIntAndBailIfError(theOTResult,"MacSocket_connect: Can't allocate OT T_CALL structure, OTAlloc() = ",theOTResult);
|
|
SetErrorMessageAndBailIfNil(theSocketStruct->mRemoteAddrInfo,"MacSocket_connect: Can't allocate OT T_CALL structure, OTAlloc() returned nil");
|
|
|
|
|
|
PrepareForAsyncOperation(theSocketStruct,T_BINDCOMPLETE);
|
|
|
|
theOTResult = ::OTBind(theSocketStruct->mEndPointRef,nil,theSocketStruct->mAssignedAddrInfo);
|
|
|
|
SetErrorMessageAndLongIntAndBailIfError(theOTResult,"MacSocket_connect: Can't bind OT endpoint, OTBind() = ",theOTResult);
|
|
|
|
BailIfError(MyBusyWait(theSocketStruct,false,&theOTResult,&(theSocketStruct->mReceivedTBindComplete)));
|
|
|
|
SetErrorMessageAndLongIntAndBailIfError(theOTResult,"MacSocket_connect: Can't bind OT endpoint, OTBind() = ",theOTResult);
|
|
|
|
theSocketStruct->mEndpointIsBound = true;
|
|
|
|
|
|
TCall sndCall;
|
|
DNSAddress hostDNSAddress;
|
|
|
|
// Set up target address
|
|
|
|
sndCall.addr.buf = (UInt8 *) &hostDNSAddress;
|
|
sndCall.addr.len = ::OTInitDNSAddress(&hostDNSAddress,inTargetAddressAndPort);
|
|
sndCall.opt.buf = nil;
|
|
sndCall.opt.len = 0;
|
|
sndCall.udata.buf = nil;
|
|
sndCall.udata.len = 0;
|
|
sndCall.sequence = 0;
|
|
|
|
// Connect!
|
|
|
|
PrepareForAsyncOperation(theSocketStruct,T_CONNECT);
|
|
|
|
theOTResult = ::OTConnect(theSocketStruct->mEndPointRef,&sndCall,nil);
|
|
|
|
if (theOTResult == kOTNoDataErr)
|
|
{
|
|
theOTResult = noErr;
|
|
}
|
|
|
|
SetErrorMessageAndLongIntAndBailIfError(theOTResult,"MacSocket_connect: Can't connect OT endpoint, OTConnect() = ",theOTResult);
|
|
|
|
BailIfError(MyBusyWait(theSocketStruct,false,&theOTResult,&(theSocketStruct->mReceivedTConnect)));
|
|
|
|
if (theOTResult == kMacSocket_TimeoutErr)
|
|
{
|
|
SetErrorMessageAndBail("MacSocket_connect: Can't connect OT endpoint, OTConnect() = kMacSocket_TimeoutErr");
|
|
}
|
|
|
|
else
|
|
{
|
|
SetErrorMessageAndLongIntAndBailIfError(theOTResult,"MacSocket_connect: Can't connect OT endpoint, OTConnect() = ",theOTResult);
|
|
}
|
|
|
|
theOTResult = ::OTRcvConnect(theSocketStruct->mEndPointRef,nil);
|
|
|
|
SetErrorMessageAndLongIntAndBailIfError(theOTResult,"MacSocket_connect: Can't complete connect on OT endpoint, OTRcvConnect() = ",theOTResult);
|
|
|
|
|
|
errCode = noErr;
|
|
|
|
|
|
#ifdef MACSOCKET_DEBUG
|
|
printf("MacSocket_connect: connect completed\n");
|
|
#endif
|
|
|
|
EXITPOINT:
|
|
|
|
if (theSocketStruct != nil)
|
|
{
|
|
theSocketStruct->mLastError = noErr;
|
|
|
|
CopyCStrToCStr("",theSocketStruct->mErrMessage,sizeof(theSocketStruct->mErrMessage));
|
|
|
|
if (errCode != noErr)
|
|
{
|
|
theSocketStruct->mLastError = errCode;
|
|
|
|
CopyCStrToCStr(GetErrorMessage(),theSocketStruct->mErrMessage,sizeof(theSocketStruct->mErrMessage));
|
|
}
|
|
}
|
|
|
|
errno = errCode;
|
|
|
|
return(errCode);
|
|
}
|
|
|
|
|
|
|
|
|
|
// Close a connection
|
|
|
|
OSErr MacSocket_close(const int inSocketNum)
|
|
{
|
|
OSErr errCode = noErr;
|
|
SocketStruct *theSocketStruct = nil;
|
|
|
|
|
|
if (!SocketIndexIsValid(inSocketNum))
|
|
{
|
|
SetErrorMessageAndBail("MacSocket_close: Invalid socket number specified");
|
|
}
|
|
|
|
|
|
theSocketStruct = &(sSockets[inSocketNum]);
|
|
|
|
if (theSocketStruct->mEndPointRef != kOTInvalidEndpointRef)
|
|
{
|
|
OTResult theOTResult = noErr;
|
|
|
|
// Try to play nice
|
|
|
|
if (theSocketStruct->mReceivedTOrdRel)
|
|
{
|
|
// Already did an OTRcvOrderlyDisconnect() in the notifier
|
|
|
|
if (theSocketStruct->mLocalEndIsConnected)
|
|
{
|
|
theOTResult = ::OTSndOrderlyDisconnect(theSocketStruct->mEndPointRef);
|
|
|
|
theSocketStruct->mLocalEndIsConnected = false;
|
|
}
|
|
}
|
|
|
|
else if (theSocketStruct->mLocalEndIsConnected)
|
|
{
|
|
theOTResult = ::OTSndOrderlyDisconnect(theSocketStruct->mEndPointRef);
|
|
|
|
theSocketStruct->mLocalEndIsConnected = false;
|
|
|
|
// Wait for other end to hang up too!
|
|
|
|
// PrepareForAsyncOperation(theSocketStruct,T_ORDREL);
|
|
//
|
|
// errCode = MyBusyWait(theSocketStruct,false,&theOTResult,&(theSocketStruct->mReceivedTOrdRel));
|
|
}
|
|
|
|
|
|
if (theOTResult != noErr)
|
|
{
|
|
::OTCloseProvider(theSocketStruct->mEndPointRef);
|
|
}
|
|
|
|
else
|
|
{
|
|
theOTResult = ::OTCloseProvider(theSocketStruct->mEndPointRef);
|
|
}
|
|
|
|
theSocketStruct->mEndPointRef = kOTInvalidEndpointRef;
|
|
|
|
errCode = theOTResult;
|
|
}
|
|
|
|
|
|
theSocketStruct->mIsInUse = false;
|
|
|
|
|
|
EXITPOINT:
|
|
|
|
if (theSocketStruct != nil)
|
|
{
|
|
theSocketStruct->mLastError = noErr;
|
|
|
|
CopyCStrToCStr("",theSocketStruct->mErrMessage,sizeof(theSocketStruct->mErrMessage));
|
|
|
|
if (errCode != noErr)
|
|
{
|
|
theSocketStruct->mLastError = errCode;
|
|
|
|
CopyCStrToCStr(GetErrorMessage(),theSocketStruct->mErrMessage,sizeof(theSocketStruct->mErrMessage));
|
|
}
|
|
}
|
|
|
|
errno = errCode;
|
|
|
|
return(errCode);
|
|
}
|
|
|
|
|
|
|
|
|
|
// Receive some bytes
|
|
|
|
int MacSocket_recv(const int inSocketNum,void *outBuff,int outBuffLength,const Boolean inBlock)
|
|
{
|
|
OSErr errCode = noErr;
|
|
int totalBytesRead = 0;
|
|
SocketStruct *theSocketStruct = nil;
|
|
|
|
|
|
SetErrorMessageAndBailIfNil(outBuff,"MacSocket_recv: Bad parameter, outBuff = nil");
|
|
|
|
if (outBuffLength <= 0)
|
|
{
|
|
SetErrorMessageAndBail("MacSocket_recv: Bad parameter, outBuffLength <= 0");
|
|
}
|
|
|
|
if (!SocketIndexIsValid(inSocketNum))
|
|
{
|
|
SetErrorMessageAndBail("MacSocket_recv: Invalid socket number specified");
|
|
}
|
|
|
|
theSocketStruct = &(sSockets[inSocketNum]);
|
|
|
|
if (!theSocketStruct->mLocalEndIsConnected)
|
|
{
|
|
SetErrorMessageAndBail("MacSocket_recv: Socket not connected");
|
|
}
|
|
|
|
if (theSocketStruct->mReceivedTOrdRel)
|
|
{
|
|
totalBytesRead = 0;
|
|
|
|
goto EXITPOINT;
|
|
}
|
|
|
|
|
|
PrepareForAsyncOperation(theSocketStruct,0);
|
|
|
|
for (;;)
|
|
{
|
|
int bytesRead;
|
|
OTResult theOTResult;
|
|
|
|
|
|
theOTResult = ::OTRcv(theSocketStruct->mEndPointRef,(void *) ((unsigned long) outBuff + (unsigned long) totalBytesRead),outBuffLength - totalBytesRead,nil);
|
|
|
|
if (theOTResult >= 0)
|
|
{
|
|
bytesRead = theOTResult;
|
|
|
|
#ifdef MACSOCKET_DEBUG
|
|
printf("MacSocket_recv: read %d bytes in part\n",bytesRead);
|
|
#endif
|
|
}
|
|
|
|
else if (theOTResult == kOTNoDataErr)
|
|
{
|
|
bytesRead = 0;
|
|
}
|
|
|
|
else
|
|
{
|
|
SetErrorMessageAndLongIntAndBail("MacSocket_recv: Can't receive OT data, OTRcv() = ",theOTResult);
|
|
}
|
|
|
|
|
|
totalBytesRead += bytesRead;
|
|
|
|
|
|
if (totalBytesRead <= 0)
|
|
{
|
|
if (theSocketStruct->mReceivedTOrdRel)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// This seems pretty stupid to me now. Maybe I'll delete this blocking garbage.
|
|
|
|
if (inBlock)
|
|
{
|
|
if (TimeoutElapsed(theSocketStruct))
|
|
{
|
|
SetErrorCodeAndMessageAndBail(kMacSocket_TimeoutErr,"MacSocket_recv: Receive operation timed-out");
|
|
}
|
|
|
|
if (theSocketStruct->mIdleWaitCallback != nil)
|
|
{
|
|
theOTResult = (*(theSocketStruct->mIdleWaitCallback))(theSocketStruct->mUserRefPtr);
|
|
|
|
SetErrorMessageAndBailIfError(theOTResult,"MacSocket_recv: User cancelled operation");
|
|
}
|
|
|
|
continue;
|
|
}
|
|
}
|
|
|
|
|
|
break;
|
|
}
|
|
|
|
errCode = noErr;
|
|
|
|
|
|
#ifdef MACSOCKET_DEBUG
|
|
printf("MacSocket_recv: read %d bytes in total\n",totalBytesRead);
|
|
#endif
|
|
|
|
|
|
EXITPOINT:
|
|
|
|
if (theSocketStruct != nil)
|
|
{
|
|
theSocketStruct->mLastError = noErr;
|
|
|
|
CopyCStrToCStr("",theSocketStruct->mErrMessage,sizeof(theSocketStruct->mErrMessage));
|
|
|
|
if (errCode != noErr)
|
|
{
|
|
theSocketStruct->mLastError = errCode;
|
|
|
|
CopyCStrToCStr(GetErrorMessage(),theSocketStruct->mErrMessage,sizeof(theSocketStruct->mErrMessage));
|
|
}
|
|
}
|
|
|
|
errno = errCode;
|
|
|
|
return(totalBytesRead);
|
|
}
|
|
|
|
|
|
|
|
// Send some bytes
|
|
|
|
int MacSocket_send(const int inSocketNum,const void *inBuff,int inBuffLength)
|
|
{
|
|
OSErr errCode = noErr;
|
|
int bytesSent = 0;
|
|
SocketStruct *theSocketStruct = nil;
|
|
|
|
|
|
SetErrorMessageAndBailIfNil(inBuff,"MacSocket_send: Bad parameter, inBuff = nil");
|
|
|
|
if (inBuffLength <= 0)
|
|
{
|
|
SetErrorMessageAndBail("MacSocket_send: Bad parameter, inBuffLength <= 0");
|
|
}
|
|
|
|
if (!SocketIndexIsValid(inSocketNum))
|
|
{
|
|
SetErrorMessageAndBail("MacSocket_send: Invalid socket number specified");
|
|
}
|
|
|
|
|
|
theSocketStruct = &(sSockets[inSocketNum]);
|
|
|
|
if (!theSocketStruct->mLocalEndIsConnected)
|
|
{
|
|
SetErrorMessageAndBail("MacSocket_send: Socket not connected");
|
|
}
|
|
|
|
|
|
OTResult theOTResult;
|
|
|
|
|
|
PrepareForAsyncOperation(theSocketStruct,0);
|
|
|
|
while (bytesSent < inBuffLength)
|
|
{
|
|
if (theSocketStruct->mIdleWaitCallback != nil)
|
|
{
|
|
theOTResult = (*(theSocketStruct->mIdleWaitCallback))(theSocketStruct->mUserRefPtr);
|
|
|
|
SetErrorMessageAndBailIfError(theOTResult,"MacSocket_send: User cancelled");
|
|
}
|
|
|
|
|
|
theOTResult = ::OTSnd(theSocketStruct->mEndPointRef,(void *) ((unsigned long) inBuff + bytesSent),inBuffLength - bytesSent,0);
|
|
|
|
if (theOTResult >= 0)
|
|
{
|
|
bytesSent += theOTResult;
|
|
|
|
theOTResult = noErr;
|
|
|
|
// Reset timer....
|
|
|
|
PrepareForAsyncOperation(theSocketStruct,0);
|
|
}
|
|
|
|
if (theOTResult == kOTFlowErr)
|
|
{
|
|
if (TimeoutElapsed(theSocketStruct))
|
|
{
|
|
SetErrorCodeAndMessageAndBail(kMacSocket_TimeoutErr,"MacSocket_send: Send timed-out")
|
|
}
|
|
|
|
theOTResult = noErr;
|
|
}
|
|
|
|
SetErrorMessageAndLongIntAndBailIfError(theOTResult,"MacSocket_send: Can't send OT data, OTSnd() = ",theOTResult);
|
|
}
|
|
|
|
|
|
errCode = noErr;
|
|
|
|
#ifdef MACSOCKET_DEBUG
|
|
printf("MacSocket_send: sent %d bytes\n",bytesSent);
|
|
#endif
|
|
|
|
|
|
EXITPOINT:
|
|
|
|
if (theSocketStruct != nil)
|
|
{
|
|
theSocketStruct->mLastError = noErr;
|
|
|
|
CopyCStrToCStr("",theSocketStruct->mErrMessage,sizeof(theSocketStruct->mErrMessage));
|
|
|
|
if (errCode != noErr)
|
|
{
|
|
theSocketStruct->mLastError = errCode;
|
|
|
|
CopyCStrToCStr(GetErrorMessage(),theSocketStruct->mErrMessage,sizeof(theSocketStruct->mErrMessage));
|
|
}
|
|
}
|
|
|
|
if (errCode != noErr)
|
|
{
|
|
::SysBeep(1);
|
|
}
|
|
|
|
errno = errCode;
|
|
|
|
return(bytesSent);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static OSStatus NegotiateIPReuseAddrOption(EndpointRef inEndpoint,const Boolean inEnableReuseIP)
|
|
{
|
|
OSStatus errCode;
|
|
UInt8 buf[kOTFourByteOptionSize];
|
|
TOption* theOTOption;
|
|
TOptMgmt theOTRequest;
|
|
TOptMgmt theOTResult;
|
|
|
|
|
|
if (!OTIsSynchronous(inEndpoint))
|
|
{
|
|
SetErrorMessageAndBail("NegotiateIPReuseAddrOption: Open Transport endpoint is not synchronous");
|
|
}
|
|
|
|
theOTRequest.opt.buf = buf;
|
|
theOTRequest.opt.len = sizeof(buf);
|
|
theOTRequest.flags = T_NEGOTIATE;
|
|
|
|
theOTResult.opt.buf = buf;
|
|
theOTResult.opt.maxlen = kOTFourByteOptionSize;
|
|
|
|
|
|
theOTOption = (TOption *) buf;
|
|
|
|
theOTOption->level = INET_IP;
|
|
theOTOption->name = IP_REUSEADDR;
|
|
theOTOption->len = kOTFourByteOptionSize;
|
|
theOTOption->status = 0;
|
|
*((UInt32 *) (theOTOption->value)) = inEnableReuseIP;
|
|
|
|
errCode = ::OTOptionManagement(inEndpoint,&theOTRequest,&theOTResult);
|
|
|
|
if (errCode == kOTNoError)
|
|
{
|
|
if (theOTOption->status != T_SUCCESS)
|
|
{
|
|
errCode = theOTOption->status;
|
|
}
|
|
|
|
else
|
|
{
|
|
errCode = kOTNoError;
|
|
}
|
|
}
|
|
|
|
|
|
EXITPOINT:
|
|
|
|
errno = errCode;
|
|
|
|
return(errCode);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Some rough notes....
|
|
|
|
|
|
|
|
// OTAckSends(ep);
|
|
// OTAckSends(ep) // enable AckSend option
|
|
// ......
|
|
// buf = OTAllocMem( nbytes); // Allocate nbytes of memory from OT
|
|
// OTSnd(ep, buf, nbytes, 0); // send a packet
|
|
// ......
|
|
// NotifyProc( .... void* theParam) // Notifier Proc
|
|
// case T_MEMORYRELEASED: // process event
|
|
// OTFreeMem( theParam); // free up memory
|
|
// break;
|
|
|
|
|
|
|
|
/*
|
|
struct InetInterfaceInfo
|
|
{
|
|
InetHost fAddress;
|
|
InetHost fNetmask;
|
|
InetHost fBroadcastAddr;
|
|
InetHost fDefaultGatewayAddr;
|
|
InetHost fDNSAddr;
|
|
UInt16 fVersion;
|
|
UInt16 fHWAddrLen;
|
|
UInt8* fHWAddr;
|
|
UInt32 fIfMTU;
|
|
UInt8* fReservedPtrs[2];
|
|
InetDomainName fDomainName;
|
|
UInt32 fIPSecondaryCount;
|
|
UInt8 fReserved[252];
|
|
};
|
|
typedef struct InetInterfaceInfo InetInterfaceInfo;
|
|
|
|
|
|
|
|
((InetAddress *) addr.buf)->fHost
|
|
|
|
struct TBind
|
|
{
|
|
TNetbuf addr;
|
|
OTQLen qlen;
|
|
};
|
|
|
|
typedef struct TBind TBind;
|
|
|
|
struct TNetbuf
|
|
{
|
|
size_t maxlen;
|
|
size_t len;
|
|
UInt8* buf;
|
|
};
|
|
|
|
typedef struct TNetbuf TNetbuf;
|
|
|
|
|
|
struct InetAddress
|
|
{
|
|
OTAddressType fAddressType; // always AF_INET
|
|
InetPort fPort; // Port number
|
|
InetHost fHost; // Host address in net byte order
|
|
UInt8 fUnused[8]; // Traditional unused bytes
|
|
};
|
|
typedef struct InetAddress InetAddress;
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
static pascal void Notifier(void* context, OTEventCode event, OTResult result, void* cookie)
|
|
{
|
|
EPInfo* epi = (EPInfo*) context;
|
|
|
|
switch (event)
|
|
{
|
|
case T_LISTEN:
|
|
{
|
|
DoListenAccept();
|
|
return;
|
|
}
|
|
|
|
case T_ACCEPTCOMPLETE:
|
|
{
|
|
if (result != kOTNoError)
|
|
DBAlert1("Notifier: T_ACCEPTCOMPLETE - result %d",result);
|
|
return;
|
|
}
|
|
|
|
case T_PASSCON:
|
|
{
|
|
if (result != kOTNoError)
|
|
{
|
|
DBAlert1("Notifier: T_PASSCON result %d", result);
|
|
return;
|
|
}
|
|
|
|
OTAtomicAdd32(1, &gCntrConnections);
|
|
OTAtomicAdd32(1, &gCntrTotalConnections);
|
|
OTAtomicAdd32(1, &gCntrIntervalConnects);
|
|
|
|
if ( OTAtomicSetBit(&epi->stateFlags, kPassconBit) != 0 )
|
|
{
|
|
ReadData(epi);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
case T_DATA:
|
|
{
|
|
if ( OTAtomicSetBit(&epi->stateFlags, kPassconBit) != 0 )
|
|
{
|
|
ReadData(epi);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
case T_GODATA:
|
|
{
|
|
SendData(epi);
|
|
return;
|
|
}
|
|
|
|
case T_DISCONNECT:
|
|
{
|
|
DoRcvDisconnect(epi);
|
|
return;
|
|
}
|
|
|
|
case T_DISCONNECTCOMPLETE:
|
|
{
|
|
if (result != kOTNoError)
|
|
DBAlert1("Notifier: T_DISCONNECT_COMPLETE result %d",result);
|
|
|
|
return;
|
|
}
|
|
|
|
case T_MEMORYRELEASED:
|
|
{
|
|
OTAtomicAdd32(-1, &epi->outstandingSends);
|
|
return;
|
|
}
|
|
|
|
default:
|
|
{
|
|
DBAlert1("Notifier: unknown event <%x>", event);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
*/
|