Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
main.c
/************************************** |
* |
* UDP chat sample |
* ©1991 Apple Computer, MacDTS |
* |
* Written by Steve Falkenburg 12/13/91 |
* |
* this sample illustrates how to send and receive MacTCP UDP packets, setting up a simple |
* connectionless chat program. Instead of an outstanding read command, an ASR is |
* used to inform the program there is data to be received. This sample is written for |
* Think C 5.0, but can be converted easily to MPW C. |
* |
*************************************/ |
#include <MacTCPCommonTypes.h> |
#include <AddressXlation.h> |
#include <UDPPB.h> |
#include <GetMyIPAddr.h> |
/* consts */ |
#define kDlgID 128 // dialog item ids |
#define kSend 1 |
#define kQuit 2 |
#define kSendData 3 |
#define kSendTo 4 |
#define kRecvData 5 |
#define kOutline 9 |
#define kErrDlg 129 |
#define kInFront (WindowPtr)-1L |
#define kUDPPort 12345 |
#define kSenderPort 0 |
#define kTimeout 5 |
/* prototypes */ |
void main(void); |
void InitStuff(void); |
void DoError(OSErr err); |
void MainLoop(void); |
OSErr DoSendData(DialogPtr theDlg); |
OSErr DoRecvData(DialogPtr theDlg); |
pascal void DNRResultProc(struct hostInfo *hInfoPtr,char *userDataPtr); |
OSErr ConvertStringToAddr(char *name,ip_addr *netNum); |
OSErr NetInitUDP(void); |
OSErr NetDoneUDP(void); |
OSErr NetSendUDP(StreamPtr sendStream,ip_addr sendAddr,udp_port sendPort,char *sendData); |
OSErr NetReadUDP(StreamPtr stream,Ptr data,unsigned short *dataLength); |
OSErr CreateUDPStream(udp_port udpPort,StreamPtr *theStream,ProcPtr asr); |
OSErr ReleaseUDPStream(StreamPtr theStream); |
pascal void MyASR( |
StreamPtr udpStream, |
unsigned short eventCode, |
Ptr userDataPtr, |
struct ICMPReport *icmpMsg); |
void DoASR(StreamPtr udpStream,unsigned short eventCode,struct ICMPReport *icmpMsg); |
OSErr GetMyIPAddr(ip_addr *addr); |
void NumToIPAddr(ip_addr addr,StringPtr ipStr); |
pascal void FrameItem(DialogPtr theDlg,short item); |
/* globals */ |
static short gMTCPDrvr; // MacTCP Driver refnum |
StreamPtr gListenerStream; // udp listener stream |
StreamPtr gSenderStream; // udp sender stream |
Boolean gDataPending; // true if data has been received |
ip_addr gMyIPAddr; // my IP address |
void main(void) |
{ |
OSErr err; |
InitStuff(); |
if ((err=NetInitUDP())==noErr) |
MainLoop(); |
else |
DoError(err); |
err = NetDoneUDP(); |
if (err!=noErr) |
DoError(err); |
ExitToShell(); |
} |
/* init the toolbox */ |
void InitStuff(void) |
{ |
InitGraf(&qd.thePort); |
InitFonts(); |
InitWindows(); |
InitMenus(); |
TEInit(); |
InitDialogs(nil); |
FlushEvents(everyEvent,0); |
InitCursor(); |
gDataPending = false; |
} |
/* display an error */ |
void DoError(OSErr err) |
{ |
Str255 errStr; |
NumToString(err,errStr); |
ParamText(errStr,"\p","\p","\p"); |
StopAlert(kErrDlg,nil); |
} |
/* main loop of execution */ |
void MainLoop(void) |
{ |
short item; |
DialogPtr theDlg; |
Handle iHndl; |
Rect iRect; |
short iType; |
OSErr err; |
Str255 ipStr; |
theDlg = GetNewDialog(kDlgID,nil,kInFront); |
GetDItem(theDlg,kOutline,&iType,&iHndl,&iRect); |
SetDItem(theDlg,kOutline,iType,FrameItem,&iRect); |
GetDItem(theDlg,kSendTo,&iType,&iHndl,&iRect); |
NumToIPAddr(gMyIPAddr,ipStr); |
SetIText(iHndl,ipStr); |
SelIText(theDlg,kSendData,0,32767); |
do { |
ModalDialog(nil,&item); |
if (item==kSend) { |
err = DoSendData(theDlg); |
if (err!=noErr) |
DoError(err); |
} |
if (gDataPending) { |
err = DoRecvData(theDlg); |
gDataPending = false; |
if (err!=noErr) |
DoError(err); |
} |
} while (item!=kQuit); |
DisposeDialog(theDlg); |
} |
/* called to initiate the sending of the UDP packet */ |
OSErr DoSendData(DialogPtr theDlg) |
{ |
Handle iHndl; |
Rect iRect; |
short iType; |
char sendTo[256],sendData[256]; |
ip_addr sendAddr; |
OSErr err; |
GetDItem(theDlg,kSendTo,&iType,&iHndl,&iRect); |
GetIText(iHndl,(StringPtr)sendTo); |
GetDItem(theDlg,kSendData,&iType,&iHndl,&iRect); |
GetIText(iHndl,(StringPtr)sendData); |
PtoCstr(sendTo); |
PtoCstr(sendData); |
err = ConvertStringToAddr(sendTo,&sendAddr); |
if (err!=noErr) |
return err; |
err = NetSendUDP(gSenderStream,sendAddr,kUDPPort,sendData); |
return err; |
} |
/* called to initiate the receiving of a UDP packet */ |
OSErr DoRecvData(DialogPtr theDlg) |
{ |
OSErr err; |
char incoming[256]; |
unsigned short dataLength; |
Handle iHndl; |
Rect iRect; |
short iType; |
dataLength = 255; |
err = NetReadUDP(gListenerStream,incoming,&dataLength); |
if (err!=noErr) |
return err; |
incoming[dataLength] = '\0'; |
CtoPstr(incoming); |
GetDItem(theDlg,kRecvData,&iType,&iHndl,&iRect); |
SetIText(iHndl,(StringPtr)incoming); |
return noErr; |
} |
/* This is the completion routine used for name-resolver calls. |
It sets the userDataPtr flag to indicate the call has completed. |
*/ |
pascal void DNRResultProc(struct hostInfo *hInfoPtr,char *userDataPtr) |
{ |
#pragma unused (hInfoPtr) |
*userDataPtr = 0xff; |
} |
/* ConvertStringToAddr is a simple call to get a host's IP number, given the name |
of the host. It copies the fully qualified name back into name, so make sure |
there's space. |
*/ |
OSErr ConvertStringToAddr(char *name,ip_addr *netNum) |
{ |
struct hostInfo hInfo; |
OSErr result; |
char done = 0x00; |
extern Boolean gCancel; |
if ((result = OpenResolver(nil)) == noErr) { |
result = StrToAddr(name,&hInfo,DNRResultProc,&done); |
if (result == cacheFault) |
while (!done) |
; /* wait for cache fault resolver to be called by interrupt */ |
CloseResolver(); |
if ((hInfo.rtnCode == noErr) || (hInfo.rtnCode == cacheFault)) { |
*netNum = hInfo.addr[0]; |
strcpy(name,hInfo.cname); |
name[strlen(name)-1] = '\0'; |
return noErr; |
} |
} |
*netNum = 0; |
return result; |
} |
/* initialize the MacTCP driver */ |
OSErr NetInitUDP(void) |
{ |
OSErr err; |
err = OpenDriver("\p.IPP",&gMTCPDrvr); |
if (err!=noErr) |
return err; |
err = CreateUDPStream(kUDPPort,&gListenerStream,MyASR); |
if (err!=noErr) |
return err; |
err = CreateUDPStream(kSenderPort,&gSenderStream,nil); |
if (err!=noErr) |
return err; |
err = GetMyIPAddr(&gMyIPAddr); |
return err; |
} |
OSErr NetDoneUDP(void) |
{ |
OSErr err,err2; |
err = ReleaseUDPStream(gSenderStream); |
err2 = ReleaseUDPStream(gListenerStream); |
if (err==noErr) |
err = err2; |
return err; |
} |
/* release a UDP Stream */ |
OSErr ReleaseUDPStream(StreamPtr theStream) |
{ |
UDPiopb udpBlock; |
OSErr err; |
udpBlock.ioCRefNum = gMTCPDrvr; |
udpBlock.csCode = UDPRelease; |
udpBlock.udpStream = theStream; |
err = PBControl(&udpBlock,false); |
if (err!=noErr) |
return err; |
DisposPtr(udpBlock.csParam.create.rcvBuff); |
return MemError(); |
} |
/* listen for incoming messages */ |
OSErr CreateUDPStream(udp_port udpPort,StreamPtr *theStream,ProcPtr asr) |
{ |
UDPiopb udpBlock; |
unsigned long bfrSize; |
Ptr buff; |
OSErr err; |
bfrSize = 2048; |
buff = NewPtr(bfrSize); |
if (MemError()!=noErr) |
return MemError(); |
udpBlock.ioCRefNum = gMTCPDrvr; |
udpBlock.csCode = UDPCreate; |
udpBlock.csParam.create.rcvBuff = buff; |
udpBlock.csParam.create.rcvBuffLen = bfrSize; |
udpBlock.csParam.create.localPort = udpPort; |
udpBlock.csParam.create.notifyProc = asr; |
#ifdef __SYSEQU__ |
udpBlock.csParam.create.userDataPtr = *(long *)CurrentA5; |
#else |
udpBlock.csParam.create.userDataPtr = CurrentA5; |
#endif |
err = PBControl(&udpBlock,false); |
if (err!=noErr) |
return err; |
*theStream = udpBlock.udpStream; |
} |
/* send an outgoing message */ |
OSErr NetSendUDP(StreamPtr sendStream,ip_addr sendAddr,udp_port sendPort,char *sendData) |
{ |
UDPiopb udpBlock; |
EventRecord ev; |
struct wdsEntry theWDS[2]; |
OSErr err; |
theWDS[0].length = strlen(sendData); |
theWDS[0].ptr = sendData; |
theWDS[1].length = 0; |
theWDS[1].ptr = nil; |
udpBlock.udpStream = sendStream; |
udpBlock.ioCompletion = nil; |
udpBlock.ioCRefNum = gMTCPDrvr; |
udpBlock.csCode = UDPWrite; |
udpBlock.csParam.send.reserved = 0; |
udpBlock.csParam.send.remoteHost = sendAddr; |
udpBlock.csParam.send.remotePort = sendPort; |
udpBlock.csParam.send.checkSum = true; |
udpBlock.csParam.send.wdsPtr = (Ptr)theWDS; |
err = PBControl(&udpBlock,true); |
while (udpBlock.ioResult>0) |
EventAvail(everyEvent,&ev); |
return udpBlock.ioResult; |
} |
/* receive an incoming packet of data */ |
OSErr NetReadUDP(StreamPtr stream,Ptr data,unsigned short *dataLength) |
{ |
UDPiopb udpBlock; |
OSErr err; |
udpBlock.udpStream = stream; |
udpBlock.ioCRefNum = gMTCPDrvr; |
udpBlock.csCode = UDPRead; |
udpBlock.csParam.receive.timeOut = kTimeout; |
udpBlock.csParam.receive.secondTimeStamp = 0; |
err = PBControl(&udpBlock,false); |
if (err!=noErr) |
return err; |
if (udpBlock.csParam.receive.rcvBuffLen==0) |
return noErr; |
if (udpBlock.csParam.receive.rcvBuffLen < *dataLength) |
*dataLength = udpBlock.csParam.receive.rcvBuffLen; |
BlockMove(udpBlock.csParam.receive.rcvBuff,data,*dataLength); |
udpBlock.csCode = UDPBfrReturn; |
err = PBControl(&udpBlock,false); |
return err; |
} |
/* our async. notification routine */ |
pascal void MyASR( |
StreamPtr udpStream, |
unsigned short eventCode, |
Ptr userDataPtr, |
struct ICMPReport *icmpMsg) |
{ |
long oldA5; |
oldA5 = SetA5((long)userDataPtr); |
DoASR(udpStream,eventCode,icmpMsg); |
SetA5(oldA5); |
} |
void DoASR(StreamPtr udpStream,unsigned short eventCode,struct ICMPReport *icmpMsg) |
{ |
if (eventCode==UDPDataArrival && udpStream==gListenerStream) { |
gDataPending = true; |
} |
} |
/* return the IP address for this machine */ |
OSErr GetMyIPAddr(ip_addr *addr) |
{ |
struct GetAddrParamBlock ipBlock; // may have to change this to IPParamBlock |
OSErr err; |
ipBlock.csCode = ipctlGetAddr; |
ipBlock.ioCRefNum = gMTCPDrvr; |
err = PBControl(&ipBlock,false); |
*addr = ipBlock.ourAddress; |
return err; |
} |
/*-------*/ |
pascal void FrameItem(DialogPtr theDlg,short item) |
{ |
Handle iHndl; |
Rect iRect; |
short iType; |
GetDItem(theDlg,item,&iType,&iHndl,&iRect); |
FrameRect(&iRect); |
} |
void NumToIPAddr(ip_addr addr,StringPtr ipStr) |
{ |
sprintf(ipStr,"%lu.%lu.%lu.%lu",( addr >> 24), |
((addr & 0x00FFFFFF) >> 16),((addr & 0x0000FFFF) >> 8), |
( addr & 0x000000FF)); |
CtoPstr(ipStr); |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14