RunLoop/CFSocket sample code for RAEL apps (LONG, pt1)
RunLoop/CFSocket sample code for RAEL apps (LONG, pt1)
- Subject: RunLoop/CFSocket sample code for RAEL apps (LONG, pt1)
- From: Jeffrey Johnson <email@hidden>
- Date: Fri, 8 Feb 2002 13:12:45 -0500
From Douglas Davidson's pthreaded server sample code posted here
(macnetworkprog) on 02/04 (and spending a DTS Incident directing me
here), I've put together some sample code suitable for a Carbon app
using RunApplicationEventLoop(). This code allows a RAEL app to
listen to a TCP port and respond using CFRunLoop callbacks (i.e. no
threads required).
This code could quickly become Bottleneck City, performancewise -
it's really only sufficient for simple, small "request-reply"
transactions. If you're writing a server with lots of connections
going on, you should use threads/the threaded example previously
posted as a base.
But if you have some "backend" Unix program (that shouldn't link to
CarbonLib for one reason or another) that needs to initiate a
connection to a Carbon UI app (a CarbonLib-less pgm can't *initiate*
an AE to a CarbonLib UI app, but can receive and reply to them.
Bummer. Like a phone without a dial/keypad), using this code with a
high numbered TCP socket might work for you. I've also enclosed a
short client program ripped off from Stevens for testing.
Since this whole effort was part of a Ring-like quest for narrative
Apple documentation :-), I've probably gotten something wrong- feel
free to post corrections/suggestions (but hey, this code compiles-
and runs- apparently correctly- and has a few (gasp) comments- some
SDK code doesn't :-))))). This is in two parts (together, 12k)...
/****************
* SocketUtils.c *
****************/
// These routines form the skeleton to allow a Carbon UI app to listen
// on a TCP port (as a "server") and process data from "clients" as a
// callback attached to the normal RAEL event/run loop (so you don't
// need to make another thread just to do simple BSD socket I/O). This code
// was written for use on MacOS 10.1 and above, and was tested on a RAEL
// C app.
//
// Adapted by Jeffrey Johnson 02/08/02 from example code posted to
// macnetworkprog-list 02/04/02 by Douglas Davidson.
// All comments/editorial content is mine (JJ) and may be erroneous
// in part or in full.
//
// Posted as a public service, since as of this date (02/02) there is
// *still* no narrative documentation on CFRunLoops, CFSockets, or even
// CFData except what's in the header files or what gets posted/answered
// on the mailing lists (Thanks Douglas), and some of us would like to
// understand so we can ship (and help Apple sell boxes). :-)
// This code has *no* support- I don't work for Apple (at least, not
// when I wrote this :-)). Feel free to contribute fixes/comments to the
// macnetworkprog mailing list.
//
// See sockClient.c for a client program (which uses only BSD calls)
// which can be run out of a Terminal window for testing.
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
// Call this somewhere early (OK to call before RAEL)
void MakeTCPServerSocketForCarbonApp(int port, CFSocketRef *boundSocket);
// call this before app quit time (at least)
void ReleaseCarbonAppTCPSocket(CFSocketRef *boundSocket);
static void FESocketDataCallBack (CFSocketRef sock,
CFSocketCallBackType type,
CFDataRef theAddr,
const void * dataPtr,
void * info);
static void FESocketAcceptCallBack (CFSocketRef sock,
CFSocketCallBackType type,
CFDataRef theAddr,
const void * dataPtr,
void * info);
void MakeTCPServerSocketForCarbonApp(int port, CFSocketRef *boundSocket)
{
CFDataRef servRef;
struct sockaddr_in servAddr;
CFSocketSignature sockSig;
CFRunLoopSourceRef sourceRef;
unsigned int yes= 1;
*boundSocket = nil;
bzero(&servAddr, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_port = htons(port);
// allows any host to connect, might want to change to loopback
for security
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
// create a CFDataRef of the servAddr for the CFSocketSignature
servRef = CFDataCreate(kCFAllocatorDefault,(UInt8
*)&servAddr,sizeof(servAddr));
sockSig.protocolFamily = AF_INET;
sockSig.socketType = SOCK_STREAM;
sockSig.protocol = 0;
sockSig.address = servRef;
// make a "rendevous socket" that is bound to this TCP port
if ((*boundSocket =
CFSocketCreateWithSocketSignature(kCFAllocatorDefault,
&sockSig,
kCFSocketAcceptCallBack,
FESocketAcceptCallBack,
NULL)) != nil &&
(sourceRef =
CFSocketCreateRunLoopSource(kCFAllocatorDefault,
*boundSocket,
0)) != nil) {
// get the run loop for the main event loop (requires 10.1)
// (warned this might be necessary in future by Carbon engrs)
CFRunLoopAddSource((CFRunLoopRef)GetCFRunLoopFromEventLoop(GetMainEventLoop()),
sourceRef,
kCFRunLoopDefaultMode);
// the sourceRef is retained by the run loop- release our ref
CFRelease(sourceRef);
// As of this writing, I'm not sure why the socket needs
// REUSEADDR/REUSEPORT set
setsockopt(CFSocketGetNative(*boundSocket),
SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(yes));
setsockopt(CFSocketGetNative(*boundSocket),
SOL_SOCKET,SO_REUSEPORT,&yes,sizeof(yes));
}
CFRelease(servRef);
}
// call this when we're completely done with the port (app is quitting)
void ReleaseCarbonAppTCPSocket(CFSocketRef *boundSocket)
{
if (*boundSocket) {
CFSocketInvalidate(*boundSocket);
CFRelease(*boundSocket);
*boundSocket = nil;
}
}
// End of part 1
--
Thanks
Jeffrey Johnson
Macintosh Development
Wavefunction, Inc.
_______________________________________________
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.