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);
}