• Hello MLAers! We've re-enabled auto-approval for accounts. If you are still waiting on account approval, please check this thread for more information.

Development of simple network packet sender (help!)

Hi folks,

I usually develop pretty extensively for Arduino microcontrollers, Python tools for Raspberry Pi and more recently Openframeworks visual processing tools.

To marry my passion for vintage computers and the other things I build, I've decided to develop a small (at first) application for vintage 68k Macs (targeting my system 7.1 Color Classics at first) to send OSC messages over networks. I'd like to get initial examples running, and of course then put the sourcecode up on github for people to remix their own OSC tools for classic macs.

For those uninitiated, OSC is a messaging protocol (Open Sound Control) that has been rising for quite some time as a replacement for classic MIDI. It allows all sorts of messaging over network ports (UDP packets) in all sorts of data types. For media artists like myself, OSC has become everything, as the glue that bonds together a wide range of different technologies and tools as well as easy method of interaction - it's on everything!

Initially I'd like to just make a simple test where I can send the output of a basic slider as integers via OSC to a set IP address, and develop it from there. I've been using Wolfgang Thaller's wonderful Retr68 build toolchain on my Linux development machine to build basic apps, and have the basics happening right now (simple window, button to send, button to quit) based on exampled provided with the tool.

I thought I could then step up to integrating simple sending of UDP packets, and then layer on an OSC message packing implementation to send through the same mechanism, but I'm stumped at level one...

I've been sifting through various developer manuals for MacTCP (using MacTCP in System 7.1) and although I have the libraries and I've been reading extensively, I can't seem to find any clear-cut examples on how to just send a byte as a UDP packet. It appears as though the developer manuals aren't keen on providing examples to work from.

I'm using C to program this application, and as mentioned above, utilising the Retro68 build toolchain to compile.

Does anybody have any examples of how to setup a port to send to, write a packet, and close the port? Anything at all would be helpful!

Many thanks
Jesse

 
Last edited by a moderator:
And for reference, here's my code so far: (two files):

Test4.c:

#include <Quickdraw.h>
#include <Dialogs.h>
#include <Fonts.h>


//MacTCP Library built into retro68:
#include <MacTCP.h>
#include <Devices.h>


#ifndef TARGET_API_MAC_CARBON
/* NOTE: this is checking whether the Dialogs.h we use *knows* about Carbon,
not whether we are actually compiling for Cabon.
If Dialogs.h is older, we add a define to be able to use the new name
for NewUserItemUPP, which used to be NewUserItemProc. */

#define NewUserItemUPP NewUserItemProc
#endif

/* global variables */

short refNum;

pascal void ButtonFrameProc(DialogRef dlg, DialogItemIndex itemNo){
DialogItemType type;
Handle itemH;
Rect box;

GetDialogItem(dlg, 1, &type, &itemH, &box);
InsetRect(&box, -4, -4);
PenSize(3,3);
FrameRoundRect(&box,16,16);
}

int main(){
#if !TARGET_API_MAC_CARBON
InitGraf(&qd.thePort);
InitFonts();
InitWindows();
InitMenus();
TEInit();
InitDialogs(NULL);
#endif
DialogPtr dlg = GetNewDialog(128,0,(WindowPtr)-1);
InitCursor();
//SelectDialogItemText(dlg,4,0,32767);

DialogItemType type;
Handle itemH;
Rect box;


//It appears we need to use the UPDCreate and UDPWrite objects to do our work, but how?
//open the connection:

//This doesn't work:
//OSErr UDPCreate(1024, 9000);

//This seems to be how the TCP object is opened:
//OSErr OpenTCPDriver(){
// OSErr err;
//
// err = OpenDriver("\p.IPP",&refNum);
// return(err);
//}


short item;
do {
ModalDialog(NULL, &item);

if(item == 2){
//Let's do work:
// declare a buffer for writing the OSC packet into
char buffer[1024];

// write the OSC packet to the buffer here

// send the data out of the socket through the UDP object here
//should this be UDPWrite?
}
} while(item != 1);

//We're finished, we should also kill off the UDP connection
FlushEvents(everyEvent, -1);
return 0;
}




Test4.r:

#include "Dialogs.r"

resource 'DLOG' (128) {
{ 50, 100, 240, 420 },
dBoxProc,
visible,
noGoAway,
0,
128,
"",
centerMainScreen
};

resource 'DITL' (128) {
{
//Quit Button:
{ 160, 230, 180, 310 }, Button { enabled, "Quit" };

//Send Button:
{ 160, 140, 180, 220 }, Button { enabled, "Send" };

//Text info with name:
{ 10, 10, 30, 310 }, StaticText { enabled, "OSC Sender - Jesse Stevens" };

//Text info of destination of messages:
{ 50, 10, 70, 310 }, StaticText { enabled, "Sending to: 192.168.8.186" };

}
};

#include "Processes.r"

resource 'SIZE' (-1) {
reserved,
acceptSuspendResumeEvents,
reserved,
canBackground,
doesActivateOnFGSwitch,
backgroundAndForeground,
dontGetFrontClicks,
ignoreChildDiedEvents,
is32BitCompatible,
notHighLevelEventAware,
onlyLocalHLEvents,
notStationeryAware,
dontUseTextEditServices,
reserved,
reserved,
reserved,
#ifdef TARGET_API_MAC_CARBON
500 * 1024, // Carbon apparently needs additional memory.
500 * 1024
#else
100 * 1024,
100 * 1024
#endif
};


Of course it's just barebones right now, once I can initiate a UDP connection, and send a simple byte packet, then I'll expand it out, and incorporate OSC message packing.

 
Further updates, in the hopes that as I work through this, it will be useful for others googling around for answers:

I've managed to figure out the syntax, which appears to be different to what's in the manual (even the function names) by cludging away with compiler errors - still not working, but no longer getting compile errors. If anyone has some pointers to what they may have done it'd be greatly appreciated. I'm at this point just attempting to send a single byte as a UDP packet.

Here's my updated code - mind the mess, it's been a long day!

Test4.c:

#include <Quickdraw.h>
#include <Dialogs.h>
#include <Fonts.h>
#include <Sound.h>


//MacTCP Library built into retro68:
#include <MacTCP.h>
#include <Devices.h>


#ifndef TARGET_API_MAC_CARBON
/* NOTE: this is checking whether the Dialogs.h we use *knows* about Carbon,
not whether we are actually compiling for Cabon.
If Dialogs.h is older, we add a define to be able to use the new name
for NewUserItemUPP, which used to be NewUserItemProc. */

#define NewUserItemUPP NewUserItemProc
#endif

/* global variables */

short refNum;

pascal void ButtonFrameProc(DialogRef dlg, DialogItemIndex itemNo){
DialogItemType type;
Handle itemH;
Rect box;

GetDialogItem(dlg, 1, &type, &itemH, &box);
InsetRect(&box, -4, -4);
PenSize(3,3);
FrameRoundRect(&box,16,16);
}

int main(){
#if !TARGET_API_MAC_CARBON
InitGraf(&qd.thePort);
InitFonts();
InitWindows();
InitMenus();
TEInit();
InitDialogs(NULL);
#endif
DialogPtr dlg = GetNewDialog(128,0,(WindowPtr)-1);
InitCursor();
//SelectDialogItemText(dlg,4,0,32767);

DialogItemType type;
Handle itemH;
Rect box;


////////////////////////////////////////////////////////////////////////////////////
//open the connection:

//declare buffer to shove incoming data into:
unsigned char *recv;
unsigned char receivebuffer;
recv = &receivebuffer;
//This doesn't work:
UDPCreatePB(OSCDestination)={
recv, //receive buffer to put received info
2048, //size of receive buffer min 2048
0, //process to call on received buffer (0 = nothing)
0, //local UDP port to open (0 = random open port)
0, //user data ptr
0 //ending port? what is this?
};


short item;
do {
ModalDialog(NULL, &item);

if(item == 2){
//Let's do work:
// declare a buffer for writing the OSC packet into
//char buffer[1024];

/////////////////////////////////////////////////////////////
//Let's just send a byte of 64 for now - how can we do this?
char *outgoing;
char outgoingdata = 64; //this will eventually be filled by slider data
outgoing = &outgoingdata; //anchor the pointer

//IP Address:
ip_addr ipaddress = (192,168,8,6);
udp_port udpport = 1100;
unsigned short sendlength = 1;


UDPSendPB(OSCDestination)={
UDPWrite, //reserved
ipaddress, //remote IP Address
udpport, //remote port
outgoing, //wds ptr? "Write Data Structure" I'm unsure how this is constructed
0, //Checksum?
0, //filler (byte alignment
1, //send length (assume bytes?)
0, //user data Ptr - what is this data?
udpport //Local port to send from
};

//Let's beep to make sure we know we've done this function
SysBeep(30);
// write the OSC packet to the buffer here

// send the data out of the socket through the UDP object here
//should this be UDPWrite?
///////////////////////////////////////////////////////////////////
}
} while(item != 1);

//How can we close the connection? The manual talks about using UDPRelease but it's not there?

//We're finished, kill and flush
FlushEvents(everyEvent, -1);
return 0;
}


And also Test4.r:

Code:
#include "Dialogs.r"

resource 'DLOG' (128) {
	{ 50, 100, 240, 420 },
	dBoxProc,
	visible,
	noGoAway,
	0,
	128,
	"",
	centerMainScreen
};

resource 'DITL' (128) {
	{	
		//Quit Button:	
		{ 160, 230, 180, 310 }, Button { enabled, "Quit" };
		
		//Send Button:
		{ 160, 140, 180, 220 }, Button { enabled, "Send" };

		//Text info with name:
		{ 10, 10, 30, 310 }, StaticText { enabled, "OSC Sender - Jesse Stevens" };

		//Text info of destination of messages:
		{ 50, 10, 70, 310 }, StaticText { enabled, "Sending to: 192.168.8.6 Port 1100" };

	}
};

#include "Processes.r"

resource 'SIZE' (-1) {
	reserved,
	acceptSuspendResumeEvents,
	reserved,
	canBackground,
	doesActivateOnFGSwitch,
	backgroundAndForeground,
	dontGetFrontClicks,
	ignoreChildDiedEvents,
	is32BitCompatible,
	notHighLevelEventAware,
	onlyLocalHLEvents,
	notStationeryAware,
	dontUseTextEditServices,
	reserved,
	reserved,
	reserved,
#ifdef TARGET_API_MAC_CARBON
	500 * 1024,	// Carbon apparently needs additional memory.
	500 * 1024
#else
	100 * 1024,
	100 * 1024
#endif
};
 
Taking it back to basics, I've removed the complex parts for dialog boxes, and based this around the simple console example provided with Retro68 build toolchain.

I've worked on using examples from others, mostly the great work of antscode in his MacTCPHelper on github, but I can't find any examples of others sending simple packets via UDP so I'm trying to adapt code from working TCP examples.

This version is heavily stripped down, as I'm going to just work piece by piece until I can send a packet. This single c file program simply tries to open the UDP network stream (basically opening the connection) without sending anything yet, but I'm getting hard system lock ups on my mac. I've tried several different methods and added/removed calls to the provided MacTCP.h library (attached in case) but still have the same behaviour.

If anyone with experience could even glance at what I have here and let me know if there's anything glaringly faulty that'd be amazing. I'm hitting a bit of a wall here.. Thanks in advance!

Test7.c:

#include <stdio.h>
#include <Sound.h>

//MacTCP Library built into retro68:
#include <MacTCP.h>
#include <Devices.h>
#include <string.h>

// So far this code just locks up the mac. Hard lock, no mouse movement
// If I remove the code in main that opens the network stream, it runs.
// What is causing the crash? how am I calling this incorrectly?


///////////////////////////////////////////
// GLobals
///////////////////////////////////////////
short refNum = 0; //Is this right? Should we refer to a number when opening MacTCP?

//related to opening connections:
unsigned long _stream = 0;
static const int BUF_SIZE = 8192;


////////////////////////////////////////////////
// Functions to call for setting up the network
////////////////////////////////////////////////

//////////////////////////////////////////
// Opens the MacTCP driver.
// Call this first - gleaned from antscode MacTCPHelper
//////////////////////////////////////////

OSErr OpenUDPDriver(){
OSErr err;
err = OpenDriver("\p.IPP",&refNum);
return(err);

}


///////////////////////////////////////////////
// This was gleaned from antscode MacTCPHelper
// Is this required?
///////////////////////////////////////////////
OSErr NewBlock(UDPiopb **pBlock){
*pBlock = (UDPiopb *)NewPtr(sizeof(UDPiopb));
if (MemError() != noErr)
return MemError();
(*pBlock)->ioCompletion = 0L;
(*pBlock)->ioCRefNum = refNum;
return noErr;
}

//////////////////////////////////////////
// InitNetwork opens the network driver
//////////////////////////////////////////

OSErr InitNetwork(void){
return OpenUDPDriver();
}



////////////////////////////////////////////////////////////////////////////////////////
//MAIN loop
///////////////////////////////////////////////////////////////////////////////////////

int main(int argc, char** argv){

////////////////////////////////////////////////////////////////////////////////
/* Opens the MacTCP driver.
This routine must be called prior to any of the below functions. */
////////////////////////////////////////////////////////////////////////////////
InitNetwork();

////////////////////////////////////////////////////////////////////////////////
// Open a UDP stream (connection) - on numbered stream?
////////////////////////////////////////////////////////////////////////////////

OSErr err;
UDPiopb *pBlock;

if ((err = NewBlock(&pBlock)) != noErr){
SysBeep(30);}

Ptr recvBuffer;
StreamPtr *streamPtr;

pBlock->csCode = UDPCreate;
pBlock->ioResult = 1;
pBlock->csParam.create.rcvBuff = recvBuffer;
pBlock->csParam.create.rcvBuffLen = 2048;
pBlock->csParam.create.notifyProc = 0;
PBControl((ParmBlkPtr)pBlock,true);

//the stream identifier
*streamPtr = pBlock->udpStream;
err = pBlock->ioResult;
DisposePtr((Ptr)pBlock);


printf("Hello, world.\n");
printf("\n(Press Return)\n");
getchar();
return 0;
}



View attachment MacTCP.h

 
Thanks @Dog Cow - I've worked through those and have done my best to cobble this little test together and although I'm now using the driver properly, and appear to be sending a packet properly, I don't seem to get anything out of the machine.

Do you have any experience with using the MacTCP driver? Have I missed something in my code here? I've simplified it and commented it all through. It compiles, runs and shows feedback on screen. I've even been error checking each step of the way and intentionally tried incorrect values and gotten response through the error checking so I think I'm using it properly, but still no UDP packet gets sent.

Any assistance would be wonderful! (C file attached)

View attachment Test8.c

 
No, I've never developed for MacTCP, but I have experience programming the Mac, so I will take a look at your code as soon as I can.

 
I looked over your code and didn't see anything. I thought maybe you weren't correctly returning the stream identifier, but it looks like you are. In the mean time, I found a UDP sample on an Apple Developer CD-ROM, and I have attached it here.

View attachment UDPSample.zip

 
Hello, I have been writing a P2P chat application. I have builds working for Ubuntu and Mac OS System 7.5.3 using MacTCP. I found this thread as I was also looking for examples of how to do UDP and TCP communication. I've been using AI to help me trawl through all the Inside Macintosh books as well as MacTCP books and finally got to a point where my Performa 6200 is able to talk to my Ubuntu machine via my app.

There is code in my project for peer discovery over UDP and sending/receive messages over TCP. I'm working to tidy up the code for the Mac build some more and then refactor/package up the TCP/UDP send/receive stuff as a library for future projects.

Bit late to the party I know.... ;-)

 
Back
Top