MODULE OSCNet;
IMPORT
OSC, OSCService, IP, UDP, TCP, Network, TCPServices,
Kernel, KernelLog , Strings;
CONST
Ok* = 0;
Timeout* = 4401;
ParseError* = 4402;
PacketTooBig* = 4403;
BadReturnData* = 4404;
MaxUDPPacketLength* = 10000H;
MaxTCPPacketLength = MaxUDPPacketLength;
ReceiveTimeout* = 1000;
NotImplemented* = 101;
Trace* = FALSE;
UDPHack = TRUE;
TYPE
OSCClient = OBJECT
PROCEDURE Send*(p: OSC.OSCPacket): LONGINT;
BEGIN HALT(NotImplemented); END Send;
PROCEDURE Receive*(VAR p: OSC.OSCPacket): LONGINT;
BEGIN HALT(NotImplemented); END Receive;
PROCEDURE Close*;
BEGIN HALT(NotImplemented); END Close;
END OSCClient;
OSCUDPData = OBJECT
VAR
fip*: IP.Adr;
fport*: LONGINT;
END OSCUDPData;
OSCUDPClient* = OBJECT(OSCClient)
VAR
s: UDP.Socket;
fip: IP.Adr;
fport: LONGINT;
PROCEDURE &InitUDP*(fip: IP.Adr; fport, lport: LONGINT; VAR res: LONGINT);
BEGIN
SELF.fip := fip;
SELF.fport := fport;
NEW(s, lport, res);
END InitUDP;
PROCEDURE Send*(p: OSC.OSCPacket): LONGINT;
BEGIN
RETURN SendUDP(s, fip, fport, p);
END Send;
PROCEDURE Recieve*(VAR p: OSC.OSCPacket; timeout : LONGINT): LONGINT;
VAR
fip2: IP.Adr; fport2: LONGINT;
size: LONGINT;
buffer: Strings.String;
got, res: LONGINT;
endticks: LONGINT;
istimeout: BOOLEAN;
BEGIN
IF timeout # -1 THEN
istimeout := TRUE;
endticks := Kernel.GetTicks () + timeout;
END;
NEW(buffer, MaxUDPPacketLength);
REPEAT
IF istimeout THEN timeout := endticks - Kernel.GetTicks (); END;
s.Receive(buffer^, 0, MaxUDPPacketLength, timeout, fip2, fport2, got, res);
UNTIL (res # UDP.Ok) OR (IP.AdrsEqual(fip, fip2) & (fport = fport2));
IF res # UDP.Ok THEN RETURN res; END;
size := got;
p := OSC.ParseOSCPacket(buffer^, size);
IF p = NIL THEN RETURN ParseError; END;
RETURN Ok;
END Recieve;
PROCEDURE Close*;
BEGIN
s.Close();
END Close;
END OSCUDPClient;
OSCUDPServer* = OBJECT
VAR
s: UDP.Socket;
serror: BOOLEAN;
oscservice: OSCService.OSCService;
stopping: BOOLEAN;
newPacket: OSC.OSCPacket;
newUDPData: OSCUDPData;
buffer: OSC.String;
receivefip: IP.Adr; receivefport: LONGINT;
got, res: LONGINT;
PROCEDURE Stop*;
BEGIN { EXCLUSIVE }
stopping := TRUE;
END Stop;
PROCEDURE &InitUDPServer*(service: OSCService.OSCService; lport: LONGINT; VAR res: LONGINT);
BEGIN
ASSERT(service # NIL);
oscservice := service;
NEW(buffer, MaxUDPPacketLength);
NEW(s, lport, res);
IF(res # UDP.Ok) THEN serror := TRUE; ELSE serror := FALSE; END;
stopping := FALSE;
END InitUDPServer;
PROCEDURE return(p: OSC.OSCPacket; data: OBJECT): LONGINT;
BEGIN
IF data IS OSCUDPData THEN
WITH data: OSCUDPData DO
IF Trace THEN KernelLog.String('UDPServer.Return called'); KernelLog.Ln;
IP.OutAdr(data.fip); KernelLog.String(' Port: '); KernelLog.Int(data.fport, 10);
KernelLog.Ln; END;
RETURN SendUDP(s, data.fip, data.fport, p);
END;
ELSE
IF Trace THEN KernelLog.String('UDPServer.Return: BadReturnData received'); KernelLog.Ln; END;
RETURN BadReturnData;
END;
END return;
BEGIN { ACTIVE }
IF (~serror) THEN
REPEAT
(* receive packets and parse them *)
s.Receive(buffer^, 0, MaxUDPPacketLength, ReceiveTimeout, receivefip, receivefport, got, res);
IF res = UDP.Ok THEN
newPacket := OSC.ParseOSCPacket(buffer^, got);
IF newPacket # NIL THEN
NEW(newUDPData);
IF Trace THEN
KernelLog.String('OSCUDPServer: Received Packet from: '); KernelLog.Hex(receivefip.ipv4Adr, 10);
KernelLog.Hex(receivefip.usedProtocol, 10);
KernelLog.Hex(receivefip.data, 10);
KernelLog.String(' port: '); KernelLog.Int(receivefport, 10); KernelLog.Ln;
END;
IF UDPHack THEN
newUDPData.fip := IP.StrToAdr('192.168.150.1');
ELSE
newUDPData.fip := receivefip;
END;
newUDPData.fport := receivefport;
newPacket.SetReturner(return, newUDPData);
oscservice.NewPacket(newPacket);
END;
ELSIF res # UDP.Timeout THEN
(* closing service *)
BEGIN { EXCLUSIVE }
stopping := TRUE;
END;
END;
UNTIL stopping;
(* cleanup *)
s.Close();
END;
END OSCUDPServer;
OSCTCPClient* = OBJECT(OSCClient)
VAR
connection: TCP.Connection;
PROCEDURE &InitTCP*(fip: IP.Adr; fport, lport: LONGINT; VAR res: LONGINT);
BEGIN
NEW(connection);
connection.Open(lport, fip, fport, res);
END InitTCP;
PROCEDURE Close*;
BEGIN
connection.Close;
END Close;
PROCEDURE Send*(p: OSC.OSCPacket): LONGINT;
BEGIN
RETURN SendTCP(connection, p);
END Send;
PROCEDURE Receive*(VAR p: OSC.OSCPacket): LONGINT;
BEGIN
RETURN ReceiveTCP(connection, p);
END Receive;
END OSCTCPClient;
OSCTCPAgent = OBJECT(TCPServices.Agent);
VAR
oscservice: OSCService.OSCService;
newpacket: OSC.OSCPacket;
res: LONGINT;
PROCEDURE &StartOSCAgent*(oscs: OSCService.OSCService; c: TCP.Connection; s: TCPServices.Service);
BEGIN
ASSERT(oscs # NIL);
oscservice := oscs;
Start(c,s);
END StartOSCAgent;
PROCEDURE return*(p: OSC.OSCPacket; data: OBJECT): LONGINT;
BEGIN
IF Trace THEN KernelLog.String('TCPServer.Return called IP: ');
IP.OutAdr(client.fip); KernelLog.String(' Port: '); KernelLog.Int(client.fport, 10);
KernelLog.Ln; END;
RETURN SendTCP(client, p);
END return;
BEGIN { ACTIVE }
LOOP
res := ReceiveTCP(client, newpacket);
IF res = Ok THEN
ASSERT(newpacket # NIL);
newpacket.SetReturner(return, NIL);
oscservice.NewPacket(newpacket);
ELSIF res # ParseError THEN EXIT END; (* Closing Connection on unrecoverableerror *)
END;
Terminate;
END OSCTCPAgent;
OSCTCPServer* = OBJECT
VAR
tcpservice: TCPServices.Service;
service: OSCService.OSCService;
PROCEDURE &InitTCPServer*(s: OSCService.OSCService; lport: LONGINT; VAR res: LONGINT);
BEGIN
ASSERT(s # NIL);
service := s;
NEW(tcpservice, lport, newAgent, res);
END InitTCPServer;
PROCEDURE newAgent(c: TCP.Connection; s: TCPServices.Service): TCPServices.Agent;
VAR agent: OSCTCPAgent;
BEGIN
NEW(agent, service, c, s);
RETURN agent;
END newAgent;
PROCEDURE Stop*;
BEGIN
tcpservice.Stop;
END Stop;
END OSCTCPServer;
PROCEDURE SendTCP(client: TCP.Connection; p: OSC.OSCPacket): LONGINT;
VAR
buffer: OSC.String;
size: ARRAY 4 OF CHAR;
res: LONGINT;
BEGIN
ASSERT(p # NIL);
buffer := p.GetBytes();
ASSERT(buffer # NIL);
Network.PutNet4(size, 0, p.GetSize());
client.Send(size, 0, 4, FALSE, res);
IF(res # TCP.Ok) THEN RETURN res; END;
client.Send(buffer^, 0, LEN(buffer^), FALSE, res);
RETURN res;
END SendTCP;
PROCEDURE ReceiveTCP(client: TCP.Connection; VAR p: OSC.OSCPacket): LONGINT;
VAR
res, len: LONGINT;
buffer: POINTER TO ARRAY OF CHAR;
sizebuf: ARRAY 4 OF CHAR;
packetsize: LONGINT;
BEGIN
client.Receive(sizebuf, 0, LEN(sizebuf), 4, len, res);
IF res # TCP.Ok THEN RETURN res END;
ASSERT(len = 4);
packetsize := Network.GetNet4(sizebuf, 0);
IF (packetsize < 0) OR (packetsize > MaxTCPPacketLength) THEN
IF Trace THEN KernelLog.String('OSCTCPAgent: Packet too big: '); KernelLog.Hex(packetsize, 10); KernelLog.Ln; END;
RETURN PacketTooBig;
END;
NEW(buffer, packetsize);
client.Receive(buffer^, 0, packetsize, packetsize, len, res);
IF res # TCP.Ok THEN RETURN res; END;
ASSERT(len = packetsize);
p := OSC.ParseOSCPacket(buffer^, packetsize);
IF p = NIL THEN RETURN ParseError; END;
RETURN Ok;
END ReceiveTCP;
PROCEDURE SendUDP(s: UDP.Socket; fip: IP.Adr; fport: LONGINT; p: OSC.OSCPacket): LONGINT;
VAR
buffer: OSC.String;
res: LONGINT;
BEGIN
ASSERT(p # NIL);
buffer := p.GetBytes();
ASSERT(buffer # NIL);
s.Send(fip, fport, buffer^, 0, LEN(buffer^), res);
IF Trace THEN KernelLog.String('SendUDP: buffer: '); KernelLog.Buffer(buffer^, 0, LEN(buffer^)); KernelLog.String( ' fip '); IP.OutAdr(fip);
KernelLog.String(' fport: '); KernelLog.Int(fport, 10); KernelLog.Ln; END;
RETURN res;
END SendUDP;
PROCEDURE TestUDPSend*;
VAR
socket: OSCUDPClient;
p, p2: OSC.OSCMessage;
attri: OSC.OSCParamInteger;
attrs: OSC.OSCParamString;
b: OSC.OSCBundle;
tt: OSC.OSCTimeTag;
ip: IP.Adr;
res: LONGINT;
BEGIN
ip := IP.StrToAdr('192.168.150.1'); KernelLog.Int(res, 4);
NEW(socket, ip, 57110, 57110, res); KernelLog.Int(res, 4);
NEW(p, Strings.NewString('/abc/def/ghi'));
NEW(attri, 01234H); p.AddArgument(attri);
res := socket.Send(p);
KernelLog.Int(res, 4); KernelLog.Ln;
NEW(p2, Strings.NewString('/xyz'));
NEW(attrs, Strings.NewString('<== This is a stirng in a Message ==>'));
p2.AddArgument(attrs);
NEW(tt); tt.SetLow(2005,12,26,18,12,15,999);
NEW(b, tt, NIL, 0); b.AddPacket(p); b.AddPacket(p2);
res := socket.Send(b);
socket.Close;
KernelLog.String('TestUDPSend done'); KernelLog.Ln;
END TestUDPSend;
PROCEDURE TestTCPSend*;
VAR
c: OSCTCPClient;
p, p2: OSC.OSCMessage;
attri: OSC.OSCParamInteger;
attrs: OSC.OSCParamString;
b: OSC.OSCBundle;
tt: OSC.OSCTimeTag;
ip: IP.Adr;
res: LONGINT;
BEGIN
ip := IP.StrToAdr('192.168.150.1'); KernelLog.Int(res, 4);
NEW(c, ip, 2009, TCP.NilPort, res); KernelLog.Int(res, 4);
NEW(p, Strings.NewString('/abc/def/ghi'));
NEW(attri, 01234H); p.AddArgument(attri);
res := c.Send(p);
KernelLog.Int(res, 4); KernelLog.Ln;
NEW(p2, Strings.NewString('/xyz'));
NEW(attrs, Strings.NewString('<== This is a stirng in a Message ==>'));
p2.AddArgument(attrs);
NEW(tt); tt.SetLow(2005,12,26,18,12,15,999);
NEW(b, tt, NIL, 0); b.AddPacket(p); b.AddPacket(p2);
res := c.Send(b);
KernelLog.String('TestTCPSend done'); KernelLog.Ln;
c.Close;
END TestTCPSend;
END OSCNet.
OSCNet.TestUDPSend ~
OSCNet.TestTCPSend ~
OSCNet.TestUDPReceive ~
*)