Making BSD calls from a CFM shared library - performance?
Making BSD calls from a CFM shared library - performance?
- Subject: Making BSD calls from a CFM shared library - performance?
- From: "Schaffernoth, Tom" <email@hidden>
- Date: Wed, 24 Mar 2004 11:20:14 -0800
Hey Folks,
I have implemented a Palm Conduit, which forces me into CFM, to call the
normal BSD network functions ( socket, connect, ...). Originally, I
implemented the Palm Conduit using Open Transport (OT). OT worked fine,
although some clients have complained that their 10.x box will hang.
Granted, we have never reproduce the problem in house. So as a solution, I
went ahead and removed the OT calls; implementing the BSD functionality.
Below is some code.
The question I have is regarding performance. From the initial QA
evaluation, looks like the BSD is a bit slower than the OT. Is there anyway
to speed up the network piece when I come through a CFM shared library?
The constructor basically sets up all the function pointers for the
BSD_WrapperSockets object.
OT would simply be replaced by the BSD calls. Meaning, what is outside of
the OT/BSD calls is the same for both. The code has been stripped down to
fit under the list's 16k limit.
//**************************************************************************
*******
//* Header File
//**************************************************************************
*******
//***********************************************************************
//* Create BSD socket function pointers.
//***********************************************************************
typedef int (*AcceptPtr) (int fd, struct sockaddr *sa, socklen_t *salenptr)
;
typedef void (*BindPtr) (int fd, const struct sockaddr *sa, socklen_t salen)
;
typedef void (*ConnectPtr) (int fd, struct sockaddr *sa, socklen_t salen) ;
typedef void (*GetpeernamePtr)(int fd, struct sockaddr *sa, socklen_t
*salenptr) ;
typedef void (*GetsocknamePtr) (int fd, struct sockaddr *sa, socklen_t
*salenptr) ;
typedef void (*GetsockoptPtr)(int fd, int level, int optname, void *optval,
socklen_t *optlenptr) ;
typedef int (*IsfdtypePtr)(int fd, int fdtype ) ;
typedef void(*ListenPtr) (int fd, int backlog) ;
typedef ssize_t (*RecvPtr)(int fd, void *ptr, size_t nbytes, int flags) ;
typedef ssize_t (*RecvfromPtr) (int fd, void *ptr, size_t nbytes, int flags,
struct sockaddr *sa, socklen_t *salenptr ) ;
typedef ssize_t (*RecvmsgPtr) (int fd, struct msghdr *msg, int flags ) ;
typedef int (*SelectPtr) (int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout ) ;
typedef ssize_t (*SendPtr) ( int fd, const void *ptr, size_t nbyttes, int
flags ) ;
typedef ssize_t (*SendtoPtr) (int fd, const void *ptr, size_t nbytes, int
flags, const struct sockaddr *sa, socklen_t salen) ;
typedef ssize_t (*SendmsgPtr) (int fd, const struct msghdr *msg, int flags )
;
typedef int (*SetsockoptPtr) ( int fd, int level, int optname, const void
*optval, socklen_t optlen ) ;
typedef int (*ShutdownPtr) ( int fd, int how ) ;
typedef int (*SockatmarkPtr) ( int fd ) ;
typedef int (*SocketPtr) (int family, int type, int protocol ) ;
typedef int (*SocketpairPtr) ( int family, int type, int protocol, int *fd )
;
class __declspec(dllexport) BSD_WrapperSockets
{
public :
BSD_WrapperSockets() ;
~BSD_WrapperSockets() ;
Boolean IsLoaded() { return m_isLoaded ; }
void SetIsLoaded(Boolean value) { m_isLoaded =
value ; return ; }
int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr) ;
void Bind(int fd, struct sockaddr *sa, socklen_t salen) ;
void Connect(int fd, unsigned long serverIP, unsigned short port) ;
void Getpeername(int fd, struct sockaddr *sa, socklen_t *salenptr) ;
void Getsockname(int fd, struct sockaddr *sa, socklen_t *salenptr) ;
void Getsockopt(int fd, int level, int optname, void *optval,
socklen_t *optlenptr) ;
int Isfdtype(int fd, int fdtype) ;
void Listen(int fd, int backlog) ;
ssize_t Recv(int fd, void *ptr, size_t nbytes, int flags) ;
ssize_t Recvfrom(int fd, void *ptr, size_t nbytes, int flags, struct
sockaddr *sa, socklen_t *salenptr) ;
ssize_t Recvmsg(int fd, struct msghdr *msg, int flags) ;
int Select(int nfds, fd_set *readfds, fd_set *writefds, fd_set
*exceptfds, struct timeval *timeout) ;
void Send(int fd, const void *ptr, size_t nbytes, int flags) ;
void Sendto(int fd, const void *ptr, size_t nbytes, int flags, const
struct sockaddr *sa, socklen_t salen) ;
void Sendmsg(int fd, const struct msghdr *msg, int flags) ;
void Setsockopt(int fd, int level, int optname, const void *optval,
socklen_t optlen) ;
void Shutdown(int fd, int how) ;
int Sockatmark(int fd) ;
void Socket(int family, int type, int protocol) ;
void Socketpair(int family, int type, int protocol, int *fd) ;
private:
CFBundleRef m_theBundle ;
Boolean m_isLoaded ;
CFBundleRef * m_theBundlePtr ;
struct sockaddr_in m_serverAddress ;
int m_sockfd ;
AcceptPtr m_Accept ;
BindPtr m_Bind ;
ConnectPtr m_Connect ;
GetpeernamePtr m_Getpeername ;
GetsocknamePtr m_Getsockname ;
GetsockoptPtr m_Getsockopt ;
IsfdtypePtr m_Isfdtype ;
ListenPtr m_Listen ;
RecvPtr m_Recv ;
RecvfromPtr m_Recvfrom ;
RecvmsgPtr m_Recvmsg ;
SelectPtr m_Select ;
SendPtr m_Send ;
SendtoPtr m_Sendto ;
SendmsgPtr m_Sendmsg ;
SetsockoptPtr m_Setsockopt ;
ShutdownPtr m_Shutdown ;
SockatmarkPtr m_Sockatmark ;
SocketPtr m_Socket ;
SocketpairPtr m_Socketpair ;
} ;
//**************************************************************************
*******
//* Source File
//**************************************************************************
*******
BSD_WrapperSockets::~BSD_WrapperSockets()
{
if ( m_theBundle )
{
CFBundleUnloadExecutable(m_theBundle);
CFRelease(m_theBundle);
}
}
BSD_WrapperSockets::BSD_WrapperSockets()
{
CFBundleRef * theBundlePtr ;
OSErr theErr;
FSRef theRef;
CFURLRef theFrameworkURL;
CFURLRef theBundleURL;
m_serverAddress.sin_family = AF_INET ;
m_Accept = nil ;
m_Bind = nil;
m_Connect = nil;
m_Getpeername = nil;
m_Getsockname = nil;
m_Getsockopt = nil;
m_Isfdtype = nil;
m_Listen = nil;
m_Recv = nil;
m_Recvfrom = nil;
m_Recvmsg = nil;
m_Select = nil;
m_Send = nil;
m_Sendto = nil;
m_Setsockopt = nil;
m_Shutdown = nil ;
m_Sockatmark = nil;
m_Socket = nil;
m_Socketpair = nil;
theBundlePtr = &m_theBundle ;
/* Start with no bundle */
*theBundlePtr = nil ;
/* Find the folder containing all the frameworks */
theErr = FSFindFolder(kOnAppropriateDisk, kFrameworksFolderType,
true, &theRef);
if (theErr == noErr)
{
/* Turn the framework folder FSRef into a CFURL */
theFrameworkURL =
CFURLCreateFromFSRef(kCFAllocatorSystemDefault, &theRef);
if (theFrameworkURL != NULL)
{
/* Create a CFURL pointing to the desired framework
*/
theBundleURL =
CFURLCreateCopyAppendingPathComponent( kCFAllocatorSystemDefault,
theFrameworkURL,
CFSTR("System.framework"),
false);
CFRelease(theFrameworkURL);
if (theBundleURL != NULL)
{
/* Turn the CFURL into a bundle reference */
*theBundlePtr =
CFBundleCreate(kCFAllocatorSystemDefault, theBundleURL) ;
m_isLoaded =
CFBundleLoadExecutable(m_theBundle);
if ( (m_isLoaded) && ( *theBundlePtr != nil
) )
{
/* Lookup the function in the bundle
by name */
m_Accept = (AcceptPtr)
CFBundleGetFunctionPointerForName(m_theBundle, CFSTR("accept"));
m_Bind = (BindPtr)
CFBundleGetFunctionPointerForName(m_theBundle, CFSTR("bind"));
m_Connect = (ConnectPtr)
CFBundleGetFunctionPointerForName(m_theBundle, CFSTR("connect"));
m_Getpeername = (GetpeernamePtr)
CFBundleGetFunctionPointerForName(m_theBundle, CFSTR("getpeername"));
m_Getsockname = (GetsocknamePtr)
CFBundleGetFunctionPointerForName(m_theBundle, CFSTR("getsockname"));
m_Getsockopt = (GetsockoptPtr)
CFBundleGetFunctionPointerForName(m_theBundle, CFSTR("getsockopt"));
m_Isfdtype = (IsfdtypePtr)
CFBundleGetFunctionPointerForName(m_theBundle, CFSTR("isfdtype"));
m_Listen = (ListenPtr)
CFBundleGetFunctionPointerForName(m_theBundle, CFSTR("listen"));
m_Recv = (RecvPtr)
CFBundleGetFunctionPointerForName(m_theBundle, CFSTR("recv"));
m_Recvfrom = (RecvfromPtr)
CFBundleGetFunctionPointerForName(m_theBundle, CFSTR("recvfrom"));
m_Recvmsg = (RecvmsgPtr)
CFBundleGetFunctionPointerForName(m_theBundle, CFSTR("recvmsg"));
m_Select = (SelectPtr)
CFBundleGetFunctionPointerForName(m_theBundle, CFSTR("select"));
m_Send = (SendPtr)
CFBundleGetFunctionPointerForName(m_theBundle, CFSTR("send"));
m_Sendto = (SendtoPtr)
CFBundleGetFunctionPointerForName(m_theBundle, CFSTR("connect"));
m_Setsockopt = (SetsockoptPtr)
CFBundleGetFunctionPointerForName(m_theBundle, CFSTR("sendto"));
m_Shutdown = (ShutdownPtr)
CFBundleGetFunctionPointerForName(m_theBundle, CFSTR("shutdown"));
m_Sockatmark = (SockatmarkPtr)
CFBundleGetFunctionPointerForName(m_theBundle, CFSTR("sockatmark"));
m_Socket = (SocketPtr)
CFBundleGetFunctionPointerForName(m_theBundle, CFSTR("socket"));
m_Socketpair = (SocketpairPtr)
CFBundleGetFunctionPointerForName(m_theBundle, CFSTR("socketpair"));
}
CFRelease(theBundleURL);
}
}
}
}
void BSD_WrapperSockets::Connect(int /*fd*/, unsigned long serverIP,
unsigned short port )
{
OSStatus theErr = noErr ;
std::memcpy(&m_serverAddress.sin_addr, &serverIP, sizeof
(m_serverAddress.sin_addr) );
m_serverAddress.sin_port = port ;
if (m_Connect != NULL)
{
m_Connect (m_sockfd, (sockaddr*)&m_serverAddress,
sizeof(m_serverAddress) ) ;
}
}
ssize_t BSD_WrapperSockets::Recv(int fd, void *ptr, size_t nbytes, int
flags )
{
#pragma unused (fd)
OSStatus theErr = noErr ;
ssize_t n = 0 ;
if (m_Recv != NULL)
{
n = m_Recv(m_sockfd, ptr, nbytes, flags ) ;
}
return (n) ;
}
void BSD_WrapperSockets::Send(int fd, const void *ptr, size_t nbytes, int
flags)
{
#pragma unused (fd)
OSStatus theErr = noErr ;
int n = 0 ;
if (m_Send != NULL)
{
n = m_Send(m_sockfd, ptr, nbytes, flags) ;
if ( n != nbytes )
{
}
}
}
//**************************************************************************
*******
//* Implementation File
//**************************************************************************
*******
AGSocket*
AUAGNetSocketNew(AGNetCtx* /*inCTX*/)
{
try
{
SyncYieldCycles(1) ;
AGSocket* socket = new AGSocket();
std::memset(socket, 0, sizeof (AGSocket));
StDeleter<AGSocket> delSocket(socket);
BSD_WrapperSockets* TCPSocket = new
BSD_WrapperSockets() ;
TCPSocket->Socket(AF_INET, SOCK_STREAM, 0) ;
if ( TCPSocket == nil )
{
::LogAddEntry(
"*********************************************", slWarning, false ) ;
::LogAddEntry( "* MachO BSD Library Constructor
Failed *", slWarning, false ) ;
::LogAddEntry( "* Please re-install ePocrates.
*", slWarning, false ) ;
::LogAddEntry(
"*********************************************", slWarning, false ) ;
}
socket->userData = (uint8*) TCPSocket;
delSocket.Release();
return socket;
}
catch (const LException& inErr)
{
::LogAddEntry( "AUAGNetSocketNew:: Exception in creating new
socket." , slWarning, true) ;
return NULL;
}
catch (...)
{
::LogAddEntry( "AUAGNetSocketNew:: Exception in creating new
socket." , slWarning, true) ;
return NULL;
}
}
sword
AUAGNetConnect(AGNetCtx */*inCTX*/,
AGSocket *inSocket,
uint32 inAddr,
int16 inPort,
AGBool inBlock)
{
try
{
SyncYieldCycles(1) ;
BSD_WrapperSockets* TCPSocket = (BSD_WrapperSockets*)
inSocket->userData;
TCPSocket->Connect(0, inAddr, inPort);
return 0;
}
catch (const LException& inErr)
{
::LogAddEntry( "AUAGNetConnect:: Exception in connection." ,
slWarning, true) ;
return -1; // %%% Map exception to AG
error code
}
catch (...)
{
::LogAddEntry( "AUAGNetConnect:: Exception in connection." ,
slWarning, true) ;
return -1;
}
}
sword
AUAGNetSocketClose(AGNetCtx */*inCTX*/, AGSocket *inSocket)
{
SyncYieldCycles(1) ;
if (inSocket == NULL)
return 0;
try
{
BSD_WrapperSockets* TCPSocket = (BSD_WrapperSockets*)
inSocket->userData;
TCPSocket->Shutdown(0,0);
return 0;
}
catch (const LException& inErr)
{
::LogAddEntry( "AUAGNetSocketClose:: Exception in the socket
close call." , slWarning, true) ;
return -1; // %%% Map exception to AG
error code
}
catch (...)
{
::LogAddEntry( "AUAGNetSocketClose:: Exception in the socket
close call." , slWarning, true) ;
return -1;
}
}
int32
AUAGNetSend(AGNetCtx */*inCTX*/,
AGSocket *inSocket,
const uint8 *inData,
int32 inNumBytes,
AGBool inBlock)
{
Assert_(inBlock); // Ensure only blocking attempts are
made.
try
{
SyncYieldCycles(1) ;
BSD_WrapperSockets* TCPSocket = (BSD_WrapperSockets*)
inSocket->userData;
uint8* data = const_cast<uint8*> (inData);
TCPSocket->Send(0, data, inNumBytes, 0);
return inNumBytes;
}
catch (const LException& inErr)
{
::LogAddEntry( "AUAGNetSend:: Exception in the net send
command." , slWarning, true) ;
return -1; // %%% Map exception to AG
error code
}
catch (...)
{
::LogAddEntry( "AUAGNetSend:: Exception in the net send
command." , slWarning, true) ;
return -1;
}
}
int32
AUAGNetRead(AGNetCtx */*inCTX*/,
AGSocket *inSocket,
uint8 *inData,
int32 inNumBytes,
AGBool inBlock)
{
Assert_(inBlock); // Ensure only blocking attempts are
made.
try
{
SyncYieldCycles(1) ;
BSD_WrapperSockets* TCPSocket = (BSD_WrapperSockets*)
inSocket->userData;
UInt32 numBytes = inNumBytes;
TCPSocket->Recv(0, inData, numBytes, 0 );
return numBytes;
}
catch (const LException& inErr)
{
::LogAddEntry( "AUAGNetRead:: Exception in the net read
command." , slWarning, true) ;
return -1; // %%% Map exception to AG
error code
}
catch (...)
{
::LogAddEntry( "AUAGNetRead:: Exception in the net read
command." , slWarning, true) ;
return -1;
}
}
Tom Schaffernoth
Software Engineer, ePocrates, Inc. 1800 Gateway Drive, San Mateo, CA 94404
ePocrates - The handheld network for physicians. email: email@hidden
http://www.epocrates.com
_______________________________________________
macnetworkprog mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/macnetworkprog
Do not post admin requests to the list. They will be ignored.