2 var <addr=0, <>port=0, <hostname, <socket;
6 connections = IdentityDictionary.new;
9 *new { arg hostname, port=0;
11 addr = if (hostname.notNil,{ hostname.gethostbyname },{ 0 });
12 ^super.newCopyArgs(addr, port, hostname);
14 *fromIP { arg addr, port=0;
15 ^super.newCopyArgs(addr, port, addr.asIPString)
22 ^this.new("127.0.0.1", this.langPort)
24 *useDoubles_ { arg flag = false;
26 ^this.primitiveFailed;
29 _NetAddr_GetBroadcastFlag
32 *broadcastFlag_ { arg flag = true;
33 _NetAddr_SetBroadcastFlag
38 connections.keys.do({ | netAddr |
43 hostname_ { arg inHostname;
44 hostname = inHostname;
45 addr = inHostname.gethostbyname;
49 sendRaw { arg rawArray;
51 ^this.primitiveFailed;
53 sendMsg { arg ... args;
55 ^this.primitiveFailed;
57 // warning: this primitive will fail to send if the bundle size is too large
58 // but it will not throw an error. this needs to be fixed
59 sendBundle { arg time ... args;
61 ^this.primitiveFailed;
64 this.sendMsg("/status");
66 sendClumpedBundles { arg time ... args;
67 if(args.bundleSize > 65535) {// udp max size.
68 args.clumpBundles.do { |item|
69 if(time.notNil) { time = time + 1e-9 }; // make it a nanosecond later
70 this.sendBundle(time, *item)
73 this.sendBundle(time, *args)
77 sync { arg condition, bundles, latency; // array of bundles that cause async action
79 if (condition.isNil) { condition = Condition.new };
81 id = this.makeSyncResponder(condition);
82 this.sendBundle(latency, ["/sync", id]);
85 // not sure what the exact size is, but its about 20000
86 // this relates to what _NetAddr_SendBundle can send
87 if(bundles.bundleSize > 20000/*65515*/) { // 65515 = 65535 - 16 - 4 (sync msg size)
88 bundles.clumpBundles.do { |item|
89 id = this.makeSyncResponder(condition);
90 this.sendBundle(latency, *(item ++ [["/sync", id]]));
91 if(latency.notNil) { latency = latency + 1e-9 };
95 id = this.makeSyncResponder(condition);
96 this.sendBundle(latency, *(bundles ++ [["/sync", id]]));
100 // maybe needed: a timeout
103 makeSyncResponder { arg condition;
104 var id = UniqueID.next;
107 resp = OSCFunc({|msg|
110 condition.test = true;
114 condition.test = false;
121 connect { | disconnectHandler |
122 if (this.isConnected.not) {
124 connections.put(this, disconnectHandler);
128 if (this.isConnected) {
130 this.prConnectionClosed;
135 ^that respondsTo: #[\port, \addr]
136 and: { this.port == that.port and: { this.addr == that.addr} }
139 ^addr.hash bitXor: port.hash
142 // Asymmetric: "that" may be nil or have nil port (wildcards)
146 this.addr == that.addr and: { that.port.isNil }
158 super.printOn(stream);
159 stream << $( << this.ip << ", " << port << $)
162 super.storeOn(stream);
163 stream << $( << "\"" << this.ip << "\", " << port << $)
169 ^this.primitiveFailed;
173 ^this.primitiveFailed;
176 // called when connection is closed either by sclang or by peer
178 connections.removeAt(this).value(this);
183 BundleNetAddr : NetAddr {
184 var <saveAddr, <>bundle;
187 *copyFrom { arg addr, bundle;
188 ^super.newCopyArgs(addr.addr, addr.port, addr.hostname, addr.socket, addr, bundle ? []);
191 sendRaw { arg rawArray;
192 bundle = bundle.add( rawArray );
194 sendMsg { arg ... args;
195 bundle = bundle.add( args );
197 sendBundle { arg time ... args;
198 bundle = bundle.addAll( args );
200 sendClumpedBundles { arg time ... args;
201 bundle = bundle.addAll( args );
203 sendStatusMsg {} // ignore status messages
211 sync { arg condition, bundles, latency;
212 bundle = bundle.add([\syncFlag, bundles, latency]);
213 // not sure about condition. here we ignore it.
217 closeBundle { arg time;
218 var bundleList, lastBundles;
221 saveAddr.sendClumpedBundles(time, *bundle);
226 bundleList = this.splitBundles(time);
227 lastBundles = bundleList.pop;
228 bundleList.do { |bundles|
229 var t = bundles.removeAt(0);
230 saveAddr.sync(nil, bundles, t); // make an independent condition.
232 saveAddr.sendClumpedBundles(*lastBundles); // time ... args
238 splitBundles { arg time;
240 curr = [time]; // first element in the array is always the time
242 if(item[0] === \syncFlag) {
243 curr = curr.addAll(item[1]); // then comes the messages
245 curr = [item[2]]; // time
247 curr = curr.add(item)