summaryrefslogtreecommitdiff
path: root/apps/plugins/pdbox/PDa/extra/dumpOSC.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/pdbox/PDa/extra/dumpOSC.c')
-rw-r--r--apps/plugins/pdbox/PDa/extra/dumpOSC.c1998
1 files changed, 1998 insertions, 0 deletions
diff --git a/apps/plugins/pdbox/PDa/extra/dumpOSC.c b/apps/plugins/pdbox/PDa/extra/dumpOSC.c
new file mode 100644
index 0000000000..37767c2b03
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/extra/dumpOSC.c
@@ -0,0 +1,1998 @@
1/*
2Written by Matt Wright and Adrian Freed, The Center for New Music and
3Audio Technologies, University of California, Berkeley. Copyright (c)
41992,93,94,95,96,97,98,99,2000,01,02,03,04 The Regents of the University of
5California (Regents).
6
7Permission to use, copy, modify, distribute, and distribute modified versions
8of this software and its documentation without fee and without a signed
9licensing agreement, is hereby granted, provided that the above copyright
10notice, this paragraph and the following two paragraphs appear in all copies,
11modifications, and distributions.
12
13IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
14SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
15OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
16BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17
18REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
21HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
22MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23
24
25The OSC webpage is http://cnmat.cnmat.berkeley.edu/OpenSoundControl
26*/
27
28
29 /*
30
31 dumpOSC.c
32 server that displays OpenSoundControl messages sent to it
33 for debugging client udp and UNIX protocol
34
35 by Matt Wright, 6/3/97
36 modified from dumpSC.c, by Matt Wright and Adrian Freed
37
38 version 0.2: Added "-silent" option a.k.a. "-quiet"
39
40 version 0.3: Incorporated patches from Nicola Bernardini to make
41 things Linux-friendly. Also added ntohl() in the right places
42 to support little-endian architectures.
43
44
45
46 compile:
47 cc -o dumpOSC dumpOSC.c
48
49 to-do:
50
51 More robustness in saying exactly what's wrong with ill-formed
52 messages. (If they don't make sense, show exactly what was
53 received.)
54
55 Time-based features: print time-received for each packet
56
57 Clean up to separate OSC parsing code from socket/select stuff
58
59 pd: branched from http://www.cnmat.berkeley.edu/OpenSoundControl/src/dumpOSC/dumpOSC.c
60 -------------
61 -- added pd functions
62 -- socket is made differently than original via pd mechanisms
63 -- tweaks for Win32 www.zeggz.com/raf 13-April-2002
64 -- the OSX changes from cnmat didnt make it here yet but this compiles
65 on OSX anyway.
66
67*/
68
69#if HAVE_CONFIG_H
70#include <config.h>
71#endif
72
73#include "m_pd.h"
74//#include "m_imp.h"
75#include "s_stuff.h"
76
77/* declarations */
78
79// typedef void (*t_fdpollfn)(void *ptr, int fd);
80void sys_addpollfn(int fd, t_fdpollfn fn, void *ptr);
81
82
83#if defined(__sgi) || defined(__linux) || defined(WIN32) || defined(__APPLE__)
84
85#ifdef WIN32
86 #include "OSC-common.h"
87 #include <winsock2.h>
88 #include <string.h>
89 #include <stdlib.h>
90 #include <fcntl.h>
91 #include <sys/types.h>
92 #include <sys/stat.h>
93 #include <ctype.h>
94 #include <signal.h>
95#else
96 #include <stdio.h>
97 #include <string.h>
98 #include <stdlib.h>
99 #include <unistd.h>
100 #include <fcntl.h>
101 #include <sys/types.h>
102 #include <sys/stat.h>
103 #include <netinet/in.h>
104 #include <rpc/rpc.h>
105 #include <sys/socket.h>
106 #include <sys/un.h>
107 #include <sys/times.h>
108 #include <sys/param.h>
109 #include <sys/time.h>
110 #include <sys/ioctl.h>
111 #include <ctype.h>
112 #include <arpa/inet.h>
113 #include <netdb.h>
114 #include <pwd.h>
115 #include <signal.h>
116 #include <grp.h>
117 #include <sys/file.h>
118 //#include <sys/prctl.h>
119
120 #ifdef NEED_SCHEDCTL_AND_LOCK
121 #include <sys/schedctl.h>
122 #include <sys/lock.h>
123 #endif
124#endif
125
126
127char *htm_error_string;
128typedef int Boolean;
129typedef void *OBJ;
130
131typedef struct ClientAddressStruct {
132 struct sockaddr_in cl_addr;
133 int clilen;
134 int sockfd;
135} *ClientAddr;
136
137typedef unsigned long long osc_time_t;
138
139Boolean ShowBytes = FALSE;
140Boolean Silent = FALSE;
141
142/* Declarations */
143#ifndef WIN32
144static int unixinitudp(int chan);
145#endif
146
147static int initudp(int chan);
148static void closeudp(int sockfd);
149Boolean ClientReply(int packetsize, void *packet, int socketfd,
150 void *clientaddresspointer, int clientaddressbufferlength);
151void sgi_CleanExit(void);
152Boolean sgi_HaveToQuit(void);
153int RegisterPollingDevice(int fd, void (*callbackfunction)(int , void *), void *dummy);
154static void catch_sigint();
155static int Synthmessage(char *m, int n, void *clientdesc, int clientdesclength, int fd) ;
156char *DataAfterAlignedString(char *string, char *boundary) ;
157Boolean IsNiceString(char *string, char *boundary) ;
158void complain(char *s, ...);
159
160#define MAXMESG 32768
161static char mbuf[MAXMESG];
162
163/* ----------------------------- dumpOSC ------------------------- */
164
165#define MAXOUTAT 50
166
167static t_class *dumpOSC_class;
168
169typedef struct _dumpOSC
170{
171 t_object x_obj;
172 t_outlet *x_msgout;
173 t_outlet *x_connectout;
174 t_atom x_outat[MAXOUTAT];
175 int x_outatc;
176 t_binbuf *x_b;
177 int x_connectsocket;
178 int x_nconnections;
179 int x_udp;
180 struct sockaddr_in x_server;
181 int x_clilen;
182} t_dumpOSC;
183
184void dumpOSC_ParsePacket(t_dumpOSC *x, char *buf, int n, ClientAddr returnAddr);
185Boolean dumpOSC_SendReply(char *buf, int n, void *clientDesc, int clientDescLenght, int fd);
186static void dumpOSC_Smessage(t_dumpOSC *x, char *address, void *v, int n, ClientAddr returnAddr);
187static void dumpOSC_PrintTypeTaggedArgs(t_dumpOSC *x, void *v, int n);
188static void dumpOSC_PrintHeuristicallyTypeGuessedArgs(t_dumpOSC *x, void *v, int n, int skipComma);
189
190static void dumpOSC_read(t_dumpOSC *x, int sockfd) {
191 int clilen = x->x_clilen;
192 int n;
193 struct ClientAddressStruct ras;
194 ClientAddr ra = &ras;
195
196 //catchupflag= FALSE;
197
198/* if (ShowBytes) { */
199/* int i; */
200/* printf("%d byte message:\n", n); */
201/* for (i = 0; i < n; ++i) { */
202/* printf(" %x (%c)\t", m[i], m[i]); */
203/* if (i%4 == 3) printf("\n"); */
204/* } */
205/* printf("\n"); */
206/* } */
207
208 // return catchupflag;
209 //struct sockaddr_in x->x_server;
210 //while( (n = recvfrom(sockfd, mbuf, MAXMESG, 0, &cl_addr, &clilen)) >0)
211 // while((
212
213 #ifdef WIN32
214 if ((n = recvfrom(sockfd, mbuf, MAXMESG, 0, (SOCKADDR*)&x->x_server, &clilen)) >0)
215 #else
216 if ((n = recvfrom(sockfd, mbuf, MAXMESG, 0, (struct sockaddr *)&x->x_server, &clilen)) >0)
217 #endif
218 {
219 //int r;
220 ras.cl_addr = *((struct sockaddr_in *) &x->x_server);
221 ras.clilen = x->x_clilen;
222 ras.sockfd = x->x_connectsocket;
223
224 #ifdef DEBUG
225 printf("dumpOSC_read: received UDP packet of length %d\n", n);
226 #endif
227
228 if(!dumpOSC_SendReply(mbuf, n, &x->x_server, clilen, sockfd))
229 {
230 dumpOSC_ParsePacket(x, mbuf, n, ra);
231 }
232 //r = Synthmessage(mbuf, n, &x->x_server, clilen, sockfd);
233 //post ("%d", r);
234 //outlet_anything(x->x_msgout, at[msg].a_w.w_symbol,
235 // emsg-msg-1, at + msg + 1);
236 // outlet_list(x->x_msgout, 0, n, mbuf);
237 //if( sgi_HaveToQuit()) goto out;
238 //if(r>0) goto back;
239 //clilen = maxclilen;
240 }
241}
242
243static void *dumpOSC_new(t_symbol *compatflag,
244 t_floatarg fportno) {
245 t_dumpOSC *x;
246 struct sockaddr_in server;
247 int clilen=sizeof(server);
248 int sockfd;
249 int portno=fportno;
250 int udp = 1;
251
252 //x->x_b = binbuf_new();
253 //x->x_outat = binbuf_getvec(x->x_b);
254
255 //{{raf}} pointer not valid yet...moving this down
256 //x->x_outatc = 0; {{raf}}
257
258 /* create a socket */
259 if ((sockfd = socket(AF_INET, (udp ? SOCK_DGRAM : SOCK_STREAM), 0)) == -1)
260 {
261 sys_sockerror("socket");
262 return (0);
263 }
264
265 server.sin_family = AF_INET;
266 server.sin_addr.s_addr = INADDR_ANY;
267 /* assign server port number */
268 server.sin_port = htons((u_short)portno);
269 /* name the socket */
270 if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0)
271 {
272 sys_sockerror("bind");
273 sys_closesocket(sockfd);
274 return (0);
275 }
276
277 x = (t_dumpOSC *)pd_new(dumpOSC_class);
278 x->x_outatc = 0; // {{raf}} now pointer is valid (less invalid)
279
280 x->x_msgout = outlet_new(&x->x_obj, &s_anything);
281
282 // if (udp) /* datagram protocol */
283 {
284
285 sys_addpollfn(sockfd, (t_fdpollfn)dumpOSC_read, x);
286 x->x_connectout = 0;
287 }
288 // else /* streaming protocol */
289 /* { */
290 /* if (listen(sockfd, 5) < 0) */
291 /* { */
292 /* sys_sockerror("listen"); */
293 /* sys_closesocket(sockfd); */
294 /* sockfd = -1; */
295 /* } */
296 /* else */
297 /* { */
298 /* sys_addpollfn(sockfd, (t_fdpollfn)dumpOSC_connectpoll, x); */
299 /* x->x_connectout = outlet_new(&x->x_obj, &s_float); */
300 /* } */
301 /* } */
302
303 x->x_connectsocket = sockfd;
304 x->x_server = server;
305 x->x_clilen = clilen;
306 x->x_nconnections = 0;
307 x->x_udp = udp;
308
309 return (x);
310}
311
312static void dumpOSC_free(t_dumpOSC *x)
313{
314 /* LATER make me clean up open connections */
315 if (x->x_connectsocket >= 0)
316 {
317 sys_rmpollfn(x->x_connectsocket);
318 sys_closesocket(x->x_connectsocket);
319 }
320}
321
322#ifdef WIN32
323OSC_API void dumpOSC_setup(void)
324#else
325void dumpOSC_setup(void)
326#endif
327{
328 dumpOSC_class = class_new(gensym("dumpOSC"),
329 (t_newmethod)dumpOSC_new, (t_method)dumpOSC_free,
330 sizeof(t_dumpOSC), CLASS_NOINLET, A_DEFFLOAT, A_DEFFLOAT,
331 A_DEFSYM, 0);
332 class_sethelpsymbol(dumpOSC_class, gensym("dumpOSC-help.pd"));
333}
334
335
336#ifndef WIN32
337 #define UNIXDG_PATH "/tmp/htm"
338 #define UNIXDG_TMP "/tmp/htm.XXXXXX"
339 static int unixinitudp(int chan)
340 {
341 struct sockaddr_un serv_addr;
342 int sockfd;
343
344 if((sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
345 return sockfd;
346
347 bzero((char *)&serv_addr, sizeof(serv_addr));
348 serv_addr.sun_family = AF_UNIX;
349 strcpy(serv_addr.sun_path, UNIXDG_PATH);
350 sprintf(serv_addr.sun_path+strlen(serv_addr.sun_path), "%d", chan);
351 unlink(serv_addr.sun_path);
352 if(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr.sun_family)+strlen(serv_addr.sun_path)) < 0)
353 {
354 perror("unable to bind\n");
355 return -1;
356 }
357
358 fcntl(sockfd, F_SETFL, FNDELAY);
359 return sockfd;
360 }
361#endif // #ifndef WIN32
362
363
364
365static int initudp(int chan)
366{
367
368#ifdef WIN32
369 struct sockaddr_in serv_addr;
370 unsigned int sockfd;
371 ULONG nonBlocking = (ULONG) TRUE;
372
373 if( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) != INVALID_SOCKET ) {
374 ZeroMemory((char *)&serv_addr, sizeof(serv_addr));
375 serv_addr.sin_family = AF_INET;
376 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
377 serv_addr.sin_port = htons(chan);
378 if(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) >= 0) {
379 // set for non-blocking mode
380 if(ioctlsocket(sockfd, FIONBIO, &nonBlocking) == SOCKET_ERROR) {
381 perror("unable to set non-blocking\n");
382 return -1;
383 }
384 }
385 else { perror("unable to bind\n"); return -1; }
386 }
387 return (sockfd == INVALID_SOCKET ? -1 : (int)sockfd);
388#else
389 struct sockaddr_in serv_addr;
390 int sockfd;
391
392 if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
393 return sockfd;
394
395 bzero((char *)&serv_addr, sizeof(serv_addr));
396 serv_addr.sin_family = AF_INET;
397 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
398 serv_addr.sin_port = htons(chan);
399
400 if(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
401 {
402 perror("unable to bind\n");
403 return -1;
404 }
405
406 fcntl(sockfd, F_SETFL, FNDELAY);
407 return sockfd;
408#endif
409}
410
411
412
413
414
415
416
417
418static void closeudp(int sockfd) {
419 #ifdef WIN32
420 closesocket(sockfd);
421 #else
422 close(sockfd);
423 #endif
424}
425
426static Boolean catchupflag=FALSE;
427Boolean ClientReply(int packetsize, void *packet, int socketfd,
428 void *clientaddresspointer, int clientaddressbufferlength)
429{
430 if(!clientaddresspointer) return FALSE;
431 catchupflag= TRUE;
432 return packetsize==sendto(socketfd, packet, packetsize, 0, clientaddresspointer, clientaddressbufferlength);
433}
434
435static Boolean exitflag= FALSE;
436void sgi_CleanExit(void) {
437 exitflag = TRUE;
438}
439
440Boolean sgi_HaveToQuit(void) {
441 return exitflag;
442}
443
444
445/* file descriptor poll table */
446static int npolldevs =0;
447typedef struct polldev
448{
449 int fd;
450 void (*callbackfunction)(int , void *);
451 void *dummy;
452} polldev;
453#define TABMAX 8
454static polldev polldevs[TABMAX];
455
456
457/* Register a device (referred to by a file descriptor that the caller
458 should have already successfully obtained from a system call) to be
459 polled as real-time constraints allowed.
460
461 When a select(2) call indicates activity on the file descriptor, the
462 callback function is called with the file descripter as first
463 argument and the given dummy argument (presumably a pointer to the
464 instance variables associated with the device).
465*/
466int RegisterPollingDevice(int fd, void (*callbackfunction)(int , void *), void *dummy)
467{
468 if(npolldevs<TABMAX)
469 {
470 polldevs[npolldevs].fd = fd;
471 polldevs[npolldevs].callbackfunction = callbackfunction;
472 polldevs[npolldevs].dummy = dummy;
473 }
474 else return -1;
475 return npolldevs++;
476}
477
478static int caught_sigint;
479
480static void catch_sigint() {
481 caught_sigint = 1;
482}
483static int sockfd, usockfd;
484
485
486void PrintClientAddr(ClientAddr CA) {
487 unsigned long addr = CA->cl_addr.sin_addr.s_addr;
488 printf("Client address %p:\n", CA);
489 printf(" clilen %d, sockfd %d\n", CA->clilen, CA->sockfd);
490 printf(" sin_family %d, sin_port %d\n", CA->cl_addr.sin_family,
491 CA->cl_addr.sin_port);
492 printf(" address: (%x) %s\n", addr, inet_ntoa(CA->cl_addr.sin_addr));
493
494 printf(" sin_zero = \"%c%c%c%c%c%c%c%c\"\n",
495 CA->cl_addr.sin_zero[0],
496 CA->cl_addr.sin_zero[1],
497 CA->cl_addr.sin_zero[2],
498 CA->cl_addr.sin_zero[3],
499 CA->cl_addr.sin_zero[4],
500 CA->cl_addr.sin_zero[5],
501 CA->cl_addr.sin_zero[6],
502 CA->cl_addr.sin_zero[7]);
503
504 printf("\n");
505}
506
507//*******************
508
509void WriteTime(char* dst, osc_time_t osctime)
510{
511 *(int32_t*)dst = htonl((int32_t)(osctime >> 32));
512 *(int32_t*)(dst+4) = htonl((int32_t)osctime);
513}
514
515void WriteMode(char* dst)
516{
517 *(int32_t*)dst = htonl(0);
518}
519
520osc_time_t ReadTime(const char* src)
521{
522 osc_time_t osctime = ntohl(*(int32_t*)src);
523 return (osctime << 32) + ntohl(*(int32_t*)(src+4));
524}
525
526double TimeToSeconds(osc_time_t osctime)
527{
528 return (double)osctime * 2.3283064365386962890625e-10 /* 1/2^32 */;
529}
530
531int timeRound(double x)
532{
533 return x >= 0.0 ? x+0.5 : x-0.5;
534}
535/*
536void WriteLogicalTime(char* dst)
537{
538 static double startTime = -1.0;
539 double sTime;
540
541 // Initialisierung der Startzeit.
542 // Knnte effizienter (ohne 'if') auch irgendwo vorher passieren.
543 // Knnte wahrscheinlich auch 0.0 sein.
544 if (startTime < 0.0) {
545 startTime = clock_getlogicaltime();
546 }
547
548 sTime = clock_gettimesince(startTime) * 0.001;
549 *(int32_t*)dst = hton'K l((int32_t)sTime);
550 *(int32_t*)(dst+4) = htonl((int32_t)(4294967296.0 * sTime));
551}
552*/
553
554void WriteLogicalTime(char* dst)
555{
556 double sTime = clock_gettimesince(19230720) / 1000.0;
557 double tau = sTime - timeRound(sTime);
558
559 //fprintf(stderr, "sSec = %f tau = %f\n", sTime, tau);
560
561 *(int32_t*)dst = htonl((int32_t)(sTime));
562 *(int32_t*)(dst+4) = htonl((int32_t)(4294967296 * tau));
563}
564
565Boolean dumpOSC_SendReply(char *buf, int n, void *clientDesc, int clientDescLenght, int fd)
566{
567 if((n == 24) && (strcmp(buf, "#time") == 0))
568 {
569 osc_time_t t0, t1, t2;
570 double dt0, dt1, dt2;
571
572 WriteMode(buf+6);
573
574 t0 = ReadTime(buf+8);
575
576 WriteLogicalTime(buf+16);
577 t1 = ReadTime(buf+16); // reverse
578 dt0 = TimeToSeconds(t0); // client time
579 dt1 = TimeToSeconds(t1); // server time
580
581 // fprintf(stderr, "%f\t%f\t%f\n", dt0, dt1, dt0 - dt1);
582
583 sendto(fd, buf, n, 0, (struct sockaddr *)clientDesc, clientDescLenght);
584 return TRUE;
585 }
586 else
587 {
588 return FALSE;
589 }
590}
591
592//**********************
593
594void dumpOSC_ParsePacket(t_dumpOSC *x, char *buf, int n, ClientAddr returnAddr) {
595 // t_dumpOSC *x;
596 int size, messageLen, i;
597 char *messageName;
598 char *args;
599
600 //#ifdef PRINTADDRS
601 #ifdef DEBUG
602 //PrintClientAddr(returnAddr);
603 #endif
604
605
606 if ((n%4) != 0) {
607 complain("SynthControl packet size (%d) not a multiple of 4 bytes: dropping", n);
608 return;
609 }
610
611 if ((n >= 8) && (strncmp(buf, "#bundle", 8) == 0)) {
612 /* This is a bundle message. */
613 #ifdef DEBUG
614 printf("dumpOSC_ParsePacket: bundle msg: bundles not yet supported\n");
615 #endif
616
617 if (n < 16) {
618 complain("Bundle message too small (%d bytes) for time tag", n);
619 return;
620 }
621
622 /* Print the time tag */
623 #ifdef DEBUG
624 printf("[ %lx%08lx\n", ntohl(*((unsigned long *)(buf+8))), ntohl(*((unsigned long *)(buf+12))));
625 #endif
626
627 /* Note: if we wanted to actually use the time tag as a little-endian
628 64-bit int, we'd have to word-swap the two 32-bit halves of it */
629
630 i = 16; /* Skip "#group\0" and time tag */
631
632 while(i<n) {
633 size = ntohl(*((int *) (buf + i)));
634 if ((size % 4) != 0) {
635 complain("Bad size count %d in bundle (not a multiple of 4)", size);
636 return;
637 }
638 if ((size + i + 4) > n) {
639 complain("Bad size count %d in bundle (only %d bytes left in entire bundle)",
640 size, n-i-4);
641 return;
642 }
643
644 /* Recursively handle element of bundle */
645 dumpOSC_ParsePacket(x, buf+i+4, size, returnAddr);
646 i += 4 + size;
647 }
648
649 if (i != n) {
650 complain("This can't happen");
651 }
652 #ifdef DEBUG
653 printf("]\n");
654 #endif
655
656 }
657 else if ((n == 24) && (strcmp(buf, "#time") == 0))
658 {
659 complain("Time message: %s\n :).\n", htm_error_string);
660 return;
661
662 }
663 else
664 {
665 /* This is not a bundle message */
666
667 messageName = buf;
668 args = DataAfterAlignedString(messageName, buf+n);
669 if (args == 0) {
670 complain("Bad message name string: %s\nDropping entire message.\n",
671 htm_error_string);
672 return;
673 }
674 messageLen = args-messageName;
675 dumpOSC_Smessage(x, messageName, (void *)args, n-messageLen, returnAddr);
676 }
677}
678
679#define SMALLEST_POSITIVE_FLOAT 0.000001f
680
681static void dumpOSC_Smessage(t_dumpOSC *x, char *address, void *v, int n, ClientAddr returnAddr) {
682 char *chars = v;
683 t_atom at;
684 //t_atom myargv[50];
685
686 int myargc = x->x_outatc;
687 t_atom* mya = x->x_outat;
688 int myi;
689
690#ifdef DEBUG
691 printf("%s ", address);
692#endif
693
694 // ztoln+cvt from envgen.c, ggee-0.18 ..
695 // outlet_anything's 'symbol' gets set to address
696 // so we dont need to append address to the atomlist
697 /*
698 SETSYMBOL(mya,gensym(address));myargc++;
699 x->x_outatc = myargc;
700 */
701
702 if (n != 0) {
703 if (chars[0] == ',') {
704 if (chars[1] != ',') {
705 /* This message begins with a type-tag string */
706 dumpOSC_PrintTypeTaggedArgs(x, v, n);
707 } else {
708 /* Double comma means an escaped real comma, not a type string */
709 dumpOSC_PrintHeuristicallyTypeGuessedArgs(x, v, n, 1);
710 }
711 } else {
712 dumpOSC_PrintHeuristicallyTypeGuessedArgs(x, v, n, 0);
713 }
714 }
715
716 outlet_anything(x->x_msgout,gensym(address),x->x_outatc,(t_atom*)&x->x_outat);
717 x->x_outatc = 0;
718#ifdef DEBUG
719 printf("\n");
720#endif
721 fflush(stdout); /* Added for Sami 5/21/98 */
722}
723
724static void dumpOSC_PrintTypeTaggedArgs(t_dumpOSC *x, void *v, int n) {
725 char *typeTags, *thisType;
726 char *p;
727
728 int myargc = x->x_outatc;
729 t_atom* mya = x->x_outat;
730 int myi;
731
732 typeTags = v;
733
734 if (!IsNiceString(typeTags, typeTags+n)) {
735 /* No null-termination, so maybe it wasn't a type tag
736 string after all */
737 dumpOSC_PrintHeuristicallyTypeGuessedArgs(x, v, n, 0);
738 return;
739 }
740
741 p = DataAfterAlignedString(typeTags, typeTags+n);
742
743
744 for (thisType = typeTags + 1; *thisType != 0; ++thisType) {
745 switch (*thisType) {
746 case 'i': case 'r': case 'm': case 'c':
747#ifdef DEBUG
748 //post("integer: %d", ntohl(*((int *) p)));
749#endif
750 /* Martin Peach fix for negative floats:
751 * was: SETFLOAT(mya+myargc,ntohl(*((int *) p)));
752 * now is:
753 */
754 SETFLOAT(mya+myargc,(signed)ntohl(*((int *) p)));
755 myargc++;
756
757 p += 4;
758 break;
759
760 case 'f': {
761 int i = ntohl(*((int *) p));
762 float *floatp = ((float *) (&i));
763#ifdef DEBUG
764 post("float: %f", *floatp);
765#endif
766 SETFLOAT(mya+myargc,*floatp);
767 myargc++;
768
769 p += 4;
770 }
771 break;
772
773 case 'h': case 't':
774#ifdef DEBUG
775 printf("[A 64-bit int] ");
776#endif
777 post("[A 64-bit int] not implemented");
778
779 p += 8;
780 break;
781
782 case 'd':
783#ifdef DEBUG
784 printf("[A 64-bit float] ");
785#endif
786 post("[A 64-bit float] not implemented");
787
788 p += 8;
789 break;
790
791 case 's': case 'S':
792 if (!IsNiceString(p, typeTags+n)) {
793 post("Type tag said this arg is a string but it's not!\n");
794 return;
795 } else {
796#ifdef DEBUG
797 post("string: \"%s\"", p);
798#endif
799 SETSYMBOL(mya+myargc,gensym(p));
800 myargc++;
801 //outlet_list(x->x_msgout, 0,sizeof(p), p);
802 //outlet_anything(x->x_msgout, 0, sizeof(p), p);
803 p = DataAfterAlignedString(p, typeTags+n);
804 // append to output vector ..
805 }
806 break;
807
808 case 'T':
809#ifdef DEBUG
810 printf("[True] ");
811#endif
812 SETFLOAT(mya+myargc,1.);
813 myargc++;
814 break;
815 case 'F':
816#ifdef DEBUG
817 printf("[False] ");
818#endif
819 SETFLOAT(mya+myargc,0.);
820 myargc++;
821 break;
822 case 'N':
823#ifdef DEBUG
824 printf("[Nil]");
825#endif
826 post("sendOSC: [Nil] not implemented");
827 break;
828 case 'I':
829#ifdef DEBUG
830 printf("[Infinitum]");
831#endif
832 post("sendOSC: [Infinitum] not implemented");
833 break;
834
835 default:
836 post("sendOSC: [Unrecognized type tag %c]", *thisType);
837 // return;
838 }
839 }
840 x->x_outatc = myargc;
841}
842
843static void dumpOSC_PrintHeuristicallyTypeGuessedArgs(t_dumpOSC *x, void *v, int n, int skipComma) {
844 int i, thisi;
845 float thisf;
846 int *ints;
847 char *chars;
848 char *string, *nextString;
849
850 int myargc= x->x_outatc;
851 t_atom* mya = x->x_outat;
852 int myi;
853
854
855 /* Go through the arguments 32 bits at a time */
856 ints = v;
857 chars = v;
858
859 for (i = 0; i<n/4; ) {
860 string = &chars[i*4];
861 thisi = ntohl(ints[i]);
862 /* Reinterpret the (potentially byte-reversed) thisi as a float */
863 thisf = *(((float *) (&thisi)));
864
865 if (thisi >= -1000 && thisi <= 1000000) {
866#ifdef DEBUG
867 printf("%d ", thisi);
868#endif
869 // append to output vector ..
870 SETFLOAT(mya+myargc,(t_float) (thisi));
871 myargc++;
872 // outlet_float(x->x_msgout, thisi);
873 i++;
874 } else if (thisf >= -1000.f && thisf <= 1000000.f &&
875 (thisf <=0.0f || thisf >= SMALLEST_POSITIVE_FLOAT)) {
876#ifdef DEBUG
877 printf("%f ", thisf);
878#endif
879 // append to output vector ..
880 SETFLOAT(mya+myargc,thisf);
881 myargc++;
882 //outlet_float(x->x_msgout, thisf);
883 i++;
884 } else if (IsNiceString(string, chars+n)) {
885 nextString = DataAfterAlignedString(string, chars+n);
886#ifdef DEBUG
887 printf("\"%s\" ", (i == 0 && skipComma) ? string +1 : string);
888#endif
889 // append to output vector ..
890 SETSYMBOL(mya+myargc,gensym(string));
891 myargc++;
892 //outlet_symbol(x->x_msgout, gensym((i == 0 && skipComma) ? string +1 : string));
893 i += (nextString-string) / 4;
894 } else {
895 // unhandled .. ;)
896#ifdef DEBUG
897 printf("0x%x xx", ints[i]);
898#endif
899 i++;
900 }
901 x->x_outatc = myargc;
902 }
903}
904
905
906#define STRING_ALIGN_PAD 4
907
908char *DataAfterAlignedString(char *string, char *boundary)
909{
910 /* The argument is a block of data beginning with a string. The
911 string has (presumably) been padded with extra null characters
912 so that the overall length is a multiple of STRING_ALIGN_PAD
913 bytes. Return a pointer to the next byte after the null
914 byte(s). The boundary argument points to the character after
915 the last valid character in the buffer---if the string hasn't
916 ended by there, something's wrong.
917
918 If the data looks wrong, return 0, and set htm_error_string */
919
920 int i;
921
922 if ((boundary - string) %4 != 0) {
923 fprintf(stderr, "Internal error: DataAfterAlignedString: bad boundary\n");
924 return 0;
925 }
926
927 for (i = 0; string[i] != '\0'; i++) {
928 if (string + i >= boundary) {
929 htm_error_string = "DataAfterAlignedString: Unreasonably long string";
930 return 0;
931 }
932 }
933
934 /* Now string[i] is the first null character */
935 i++;
936
937 for (; (i % STRING_ALIGN_PAD) != 0; i++) {
938 if (string + i >= boundary) {
939 htm_error_string = "DataAfterAlignedString: Unreasonably long string";
940 return 0;
941 }
942 if (string[i] != '\0') {
943 htm_error_string = "DataAfterAlignedString: Incorrectly padded string.";
944 return 0;
945 }
946 }
947
948 return string+i;
949}
950
951Boolean IsNiceString(char *string, char *boundary)
952{
953 /* Arguments same as DataAfterAlignedString(). Is the given "string"
954 really a string? I.e., is it a sequence of isprint() characters
955 terminated with 1-4 null characters to align on a 4-byte boundary? */
956
957 int i;
958
959 if ((boundary - string) %4 != 0) {
960 fprintf(stderr, "Internal error: IsNiceString: bad boundary\n");
961 return 0;
962 }
963
964 for (i = 0; string[i] != '\0'; i++) {
965 if (!isprint(string[i])) return FALSE;
966 if (string + i >= boundary) return FALSE;
967 }
968
969 /* If we made it this far, it's a null-terminated sequence of printing characters
970 in the given boundary. Now we just make sure it's null padded... */
971
972 /* Now string[i] is the first null character */
973 i++;
974 for (; (i % STRING_ALIGN_PAD) != 0; i++) {
975 if (string[i] != '\0') return FALSE;
976 }
977
978 return TRUE;
979}
980
981
982
983
984
985
986
987
988
989#include <stdarg.h>
990void complain(char *s, ...) {
991 va_list ap;
992 va_start(ap, s);
993 fprintf(stderr, "*** ERROR: ");
994 vfprintf(stderr, s, ap);
995 fprintf(stderr, "\n");
996 va_end(ap);
997}
998
999#endif /* __sgi or LINUX or WIN32 */
1000/*
1001Written by Matt Wright and Adrian Freed, The Center for New Music and
1002Audio Technologies, University of California, Berkeley. Copyright (c)
10031992,93,94,95,96,97,98,99,2000,01,02,03,04 The Regents of the University of
1004California (Regents).
1005
1006Permission to use, copy, modify, distribute, and distribute modified versions
1007of this software and its documentation without fee and without a signed
1008licensing agreement, is hereby granted, provided that the above copyright
1009notice, this paragraph and the following two paragraphs appear in all copies,
1010modifications, and distributions.
1011
1012IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
1013SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
1014OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
1015BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1016
1017REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
1018THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1019PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
1020HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
1021MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
1022
1023
1024The OSC webpage is http://cnmat.cnmat.berkeley.edu/OpenSoundControl
1025*/
1026
1027
1028 /*
1029
1030 dumpOSC.c
1031 server that displays OpenSoundControl messages sent to it
1032 for debugging client udp and UNIX protocol
1033
1034 by Matt Wright, 6/3/97
1035 modified from dumpSC.c, by Matt Wright and Adrian Freed
1036
1037 version 0.2: Added "-silent" option a.k.a. "-quiet"
1038
1039 version 0.3: Incorporated patches from Nicola Bernardini to make
1040 things Linux-friendly. Also added ntohl() in the right places
1041 to support little-endian architectures.
1042
1043
1044
1045 compile:
1046 cc -o dumpOSC dumpOSC.c
1047
1048 to-do:
1049
1050 More robustness in saying exactly what's wrong with ill-formed
1051 messages. (If they don't make sense, show exactly what was
1052 received.)
1053
1054 Time-based features: print time-received for each packet
1055
1056 Clean up to separate OSC parsing code from socket/select stuff
1057
1058 pd: branched from http://www.cnmat.berkeley.edu/OpenSoundControl/src/dumpOSC/dumpOSC.c
1059 -------------
1060 -- added pd functions
1061 -- socket is made differently than original via pd mechanisms
1062 -- tweaks for Win32 www.zeggz.com/raf 13-April-2002
1063 -- the OSX changes from cnmat didnt make it here yet but this compiles
1064 on OSX anyway.
1065
1066*/
1067
1068#if HAVE_CONFIG_H
1069#include <config.h>
1070#endif
1071
1072#include "m_pd.h"
1073//#include "m_imp.h"
1074#include "s_stuff.h"
1075
1076/* declarations */
1077
1078// typedef void (*t_fdpollfn)(void *ptr, int fd);
1079void sys_addpollfn(int fd, t_fdpollfn fn, void *ptr);
1080
1081
1082#if defined(__sgi) || defined(__linux) || defined(WIN32) || defined(__APPLE__)
1083
1084#ifdef WIN32
1085 #include "OSC-common.h"
1086 #include <winsock2.h>
1087 #include <string.h>
1088 #include <stdlib.h>
1089 #include <fcntl.h>
1090 #include <sys/types.h>
1091 #include <sys/stat.h>
1092 #include <ctype.h>
1093 #include <signal.h>
1094#else
1095 #include <stdio.h>
1096 #include <string.h>
1097 #include <stdlib.h>
1098 #include <unistd.h>
1099 #include <fcntl.h>
1100 #include <sys/types.h>
1101 #include <sys/stat.h>
1102 #include <netinet/in.h>
1103 #include <rpc/rpc.h>
1104 #include <sys/socket.h>
1105 #include <sys/un.h>
1106 #include <sys/times.h>
1107 #include <sys/param.h>
1108 #include <sys/time.h>
1109 #include <sys/ioctl.h>
1110 #include <ctype.h>
1111 #include <arpa/inet.h>
1112 #include <netdb.h>
1113 #include <pwd.h>
1114 #include <signal.h>
1115 #include <grp.h>
1116 #include <sys/file.h>
1117 //#include <sys/prctl.h>
1118
1119 #ifdef NEED_SCHEDCTL_AND_LOCK
1120 #include <sys/schedctl.h>
1121 #include <sys/lock.h>
1122 #endif
1123#endif
1124
1125
1126char *htm_error_string;
1127typedef int Boolean;
1128typedef void *OBJ;
1129
1130typedef struct ClientAddressStruct {
1131 struct sockaddr_in cl_addr;
1132 int clilen;
1133 int sockfd;
1134} *ClientAddr;
1135
1136typedef unsigned long long osc_time_t;
1137
1138Boolean ShowBytes = FALSE;
1139Boolean Silent = FALSE;
1140
1141/* Declarations */
1142#ifndef WIN32
1143static int unixinitudp(int chan);
1144#endif
1145
1146static int initudp(int chan);
1147static void closeudp(int sockfd);
1148Boolean ClientReply(int packetsize, void *packet, int socketfd,
1149 void *clientaddresspointer, int clientaddressbufferlength);
1150void sgi_CleanExit(void);
1151Boolean sgi_HaveToQuit(void);
1152int RegisterPollingDevice(int fd, void (*callbackfunction)(int , void *), void *dummy);
1153static void catch_sigint();
1154static int Synthmessage(char *m, int n, void *clientdesc, int clientdesclength, int fd) ;
1155char *DataAfterAlignedString(char *string, char *boundary) ;
1156Boolean IsNiceString(char *string, char *boundary) ;
1157void complain(char *s, ...);
1158
1159#define MAXMESG 32768
1160static char mbuf[MAXMESG];
1161
1162/* ----------------------------- dumpOSC ------------------------- */
1163
1164#define MAXOUTAT 50
1165
1166static t_class *dumpOSC_class;
1167
1168typedef struct _dumpOSC
1169{
1170 t_object x_obj;
1171 t_outlet *x_msgout;
1172 t_outlet *x_connectout;
1173 t_atom x_outat[MAXOUTAT];
1174 int x_outatc;
1175 t_binbuf *x_b;
1176 int x_connectsocket;
1177 int x_nconnections;
1178 int x_udp;
1179 struct sockaddr_in x_server;
1180 int x_clilen;
1181} t_dumpOSC;
1182
1183void dumpOSC_ParsePacket(t_dumpOSC *x, char *buf, int n, ClientAddr returnAddr);
1184Boolean dumpOSC_SendReply(char *buf, int n, void *clientDesc, int clientDescLenght, int fd);
1185static void dumpOSC_Smessage(t_dumpOSC *x, char *address, void *v, int n, ClientAddr returnAddr);
1186static void dumpOSC_PrintTypeTaggedArgs(t_dumpOSC *x, void *v, int n);
1187static void dumpOSC_PrintHeuristicallyTypeGuessedArgs(t_dumpOSC *x, void *v, int n, int skipComma);
1188
1189static void dumpOSC_read(t_dumpOSC *x, int sockfd) {
1190 int clilen = x->x_clilen;
1191 int n;
1192 struct ClientAddressStruct ras;
1193 ClientAddr ra = &ras;
1194
1195 //catchupflag= FALSE;
1196
1197/* if (ShowBytes) { */
1198/* int i; */
1199/* printf("%d byte message:\n", n); */
1200/* for (i = 0; i < n; ++i) { */
1201/* printf(" %x (%c)\t", m[i], m[i]); */
1202/* if (i%4 == 3) printf("\n"); */
1203/* } */
1204/* printf("\n"); */
1205/* } */
1206
1207 // return catchupflag;
1208 //struct sockaddr_in x->x_server;
1209 //while( (n = recvfrom(sockfd, mbuf, MAXMESG, 0, &cl_addr, &clilen)) >0)
1210 // while((
1211
1212 #ifdef WIN32
1213 if ((n = recvfrom(sockfd, mbuf, MAXMESG, 0, (SOCKADDR*)&x->x_server, &clilen)) >0)
1214 #else
1215 if ((n = recvfrom(sockfd, mbuf, MAXMESG, 0, (struct sockaddr *)&x->x_server, &clilen)) >0)
1216 #endif
1217 {
1218 //int r;
1219 ras.cl_addr = *((struct sockaddr_in *) &x->x_server);
1220 ras.clilen = x->x_clilen;
1221 ras.sockfd = x->x_connectsocket;
1222
1223 #ifdef DEBUG
1224 printf("dumpOSC_read: received UDP packet of length %d\n", n);
1225 #endif
1226
1227 if(!dumpOSC_SendReply(mbuf, n, &x->x_server, clilen, sockfd))
1228 {
1229 dumpOSC_ParsePacket(x, mbuf, n, ra);
1230 }
1231 //r = Synthmessage(mbuf, n, &x->x_server, clilen, sockfd);
1232 //post ("%d", r);
1233 //outlet_anything(x->x_msgout, at[msg].a_w.w_symbol,
1234 // emsg-msg-1, at + msg + 1);
1235 // outlet_list(x->x_msgout, 0, n, mbuf);
1236 //if( sgi_HaveToQuit()) goto out;
1237 //if(r>0) goto back;
1238 //clilen = maxclilen;
1239 }
1240}
1241
1242static void *dumpOSC_new(t_symbol *compatflag,
1243 t_floatarg fportno) {
1244 t_dumpOSC *x;
1245 struct sockaddr_in server;
1246 int clilen=sizeof(server);
1247 int sockfd;
1248 int portno=fportno;
1249 int udp = 1;
1250
1251 //x->x_b = binbuf_new();
1252 //x->x_outat = binbuf_getvec(x->x_b);
1253
1254 //{{raf}} pointer not valid yet...moving this down
1255 //x->x_outatc = 0; {{raf}}
1256
1257 /* create a socket */
1258 if ((sockfd = socket(AF_INET, (udp ? SOCK_DGRAM : SOCK_STREAM), 0)) == -1)
1259 {
1260 sys_sockerror("socket");
1261 return (0);
1262 }
1263
1264 server.sin_family = AF_INET;
1265 server.sin_addr.s_addr = INADDR_ANY;
1266 /* assign server port number */
1267 server.sin_port = htons((u_short)portno);
1268 /* name the socket */
1269 if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0)
1270 {
1271 sys_sockerror("bind");
1272 sys_closesocket(sockfd);
1273 return (0);
1274 }
1275
1276 x = (t_dumpOSC *)pd_new(dumpOSC_class);
1277 x->x_outatc = 0; // {{raf}} now pointer is valid (less invalid)
1278
1279 x->x_msgout = outlet_new(&x->x_obj, &s_anything);
1280
1281 // if (udp) /* datagram protocol */
1282 {
1283
1284 sys_addpollfn(sockfd, (t_fdpollfn)dumpOSC_read, x);
1285 x->x_connectout = 0;
1286 }
1287 // else /* streaming protocol */
1288 /* { */
1289 /* if (listen(sockfd, 5) < 0) */
1290 /* { */
1291 /* sys_sockerror("listen"); */
1292 /* sys_closesocket(sockfd); */
1293 /* sockfd = -1; */
1294 /* } */
1295 /* else */
1296 /* { */
1297 /* sys_addpollfn(sockfd, (t_fdpollfn)dumpOSC_connectpoll, x); */
1298 /* x->x_connectout = outlet_new(&x->x_obj, &s_float); */
1299 /* } */
1300 /* } */
1301
1302 x->x_connectsocket = sockfd;
1303 x->x_server = server;
1304 x->x_clilen = clilen;
1305 x->x_nconnections = 0;
1306 x->x_udp = udp;
1307
1308 return (x);
1309}
1310
1311static void dumpOSC_free(t_dumpOSC *x)
1312{
1313 /* LATER make me clean up open connections */
1314 if (x->x_connectsocket >= 0)
1315 {
1316 sys_rmpollfn(x->x_connectsocket);
1317 sys_closesocket(x->x_connectsocket);
1318 }
1319}
1320
1321#ifdef WIN32
1322OSC_API void dumpOSC_setup(void)
1323#else
1324void dumpOSC_setup(void)
1325#endif
1326{
1327 dumpOSC_class = class_new(gensym("dumpOSC"),
1328 (t_newmethod)dumpOSC_new, (t_method)dumpOSC_free,
1329 sizeof(t_dumpOSC), CLASS_NOINLET, A_DEFFLOAT, A_DEFFLOAT,
1330 A_DEFSYM, 0);
1331 class_sethelpsymbol(dumpOSC_class, gensym("dumpOSC-help.pd"));
1332}
1333
1334
1335#ifndef WIN32
1336 #define UNIXDG_PATH "/tmp/htm"
1337 #define UNIXDG_TMP "/tmp/htm.XXXXXX"
1338 static int unixinitudp(int chan)
1339 {
1340 struct sockaddr_un serv_addr;
1341 int sockfd;
1342
1343 if((sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
1344 return sockfd;
1345
1346 bzero((char *)&serv_addr, sizeof(serv_addr));
1347 serv_addr.sun_family = AF_UNIX;
1348 strcpy(serv_addr.sun_path, UNIXDG_PATH);
1349 sprintf(serv_addr.sun_path+strlen(serv_addr.sun_path), "%d", chan);
1350 unlink(serv_addr.sun_path);
1351 if(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr.sun_family)+strlen(serv_addr.sun_path)) < 0)
1352 {
1353 perror("unable to bind\n");
1354 return -1;
1355 }
1356
1357 fcntl(sockfd, F_SETFL, FNDELAY);
1358 return sockfd;
1359 }
1360#endif // #ifndef WIN32
1361
1362
1363
1364static int initudp(int chan)
1365{
1366
1367#ifdef WIN32
1368 struct sockaddr_in serv_addr;
1369 unsigned int sockfd;
1370 ULONG nonBlocking = (ULONG) TRUE;
1371
1372 if( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) != INVALID_SOCKET ) {
1373 ZeroMemory((char *)&serv_addr, sizeof(serv_addr));
1374 serv_addr.sin_family = AF_INET;
1375 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
1376 serv_addr.sin_port = htons(chan);
1377 if(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) >= 0) {
1378 // set for non-blocking mode
1379 if(ioctlsocket(sockfd, FIONBIO, &nonBlocking) == SOCKET_ERROR) {
1380 perror("unable to set non-blocking\n");
1381 return -1;
1382 }
1383 }
1384 else { perror("unable to bind\n"); return -1; }
1385 }
1386 return (sockfd == INVALID_SOCKET ? -1 : (int)sockfd);
1387#else
1388 struct sockaddr_in serv_addr;
1389 int sockfd;
1390
1391 if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
1392 return sockfd;
1393
1394 bzero((char *)&serv_addr, sizeof(serv_addr));
1395 serv_addr.sin_family = AF_INET;
1396 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
1397 serv_addr.sin_port = htons(chan);
1398
1399 if(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
1400 {
1401 perror("unable to bind\n");
1402 return -1;
1403 }
1404
1405 fcntl(sockfd, F_SETFL, FNDELAY);
1406 return sockfd;
1407#endif
1408}
1409
1410
1411
1412
1413
1414
1415
1416
1417static void closeudp(int sockfd) {
1418 #ifdef WIN32
1419 closesocket(sockfd);
1420 #else
1421 close(sockfd);
1422 #endif
1423}
1424
1425static Boolean catchupflag=FALSE;
1426Boolean ClientReply(int packetsize, void *packet, int socketfd,
1427 void *clientaddresspointer, int clientaddressbufferlength)
1428{
1429 if(!clientaddresspointer) return FALSE;
1430 catchupflag= TRUE;
1431 return packetsize==sendto(socketfd, packet, packetsize, 0, clientaddresspointer, clientaddressbufferlength);
1432}
1433
1434static Boolean exitflag= FALSE;
1435void sgi_CleanExit(void) {
1436 exitflag = TRUE;
1437}
1438
1439Boolean sgi_HaveToQuit(void) {
1440 return exitflag;
1441}
1442
1443
1444/* file descriptor poll table */
1445static int npolldevs =0;
1446typedef struct polldev
1447{
1448 int fd;
1449 void (*callbackfunction)(int , void *);
1450 void *dummy;
1451} polldev;
1452#define TABMAX 8
1453static polldev polldevs[TABMAX];
1454
1455
1456/* Register a device (referred to by a file descriptor that the caller
1457 should have already successfully obtained from a system call) to be
1458 polled as real-time constraints allowed.
1459
1460 When a select(2) call indicates activity on the file descriptor, the
1461 callback function is called with the file descripter as first
1462 argument and the given dummy argument (presumably a pointer to the
1463 instance variables associated with the device).
1464*/
1465int RegisterPollingDevice(int fd, void (*callbackfunction)(int , void *), void *dummy)
1466{
1467 if(npolldevs<TABMAX)
1468 {
1469 polldevs[npolldevs].fd = fd;
1470 polldevs[npolldevs].callbackfunction = callbackfunction;
1471 polldevs[npolldevs].dummy = dummy;
1472 }
1473 else return -1;
1474 return npolldevs++;
1475}
1476
1477static int caught_sigint;
1478
1479static void catch_sigint() {
1480 caught_sigint = 1;
1481}
1482static int sockfd, usockfd;
1483
1484
1485void PrintClientAddr(ClientAddr CA) {
1486 unsigned long addr = CA->cl_addr.sin_addr.s_addr;
1487 printf("Client address %p:\n", CA);
1488 printf(" clilen %d, sockfd %d\n", CA->clilen, CA->sockfd);
1489 printf(" sin_family %d, sin_port %d\n", CA->cl_addr.sin_family,
1490 CA->cl_addr.sin_port);
1491 printf(" address: (%x) %s\n", addr, inet_ntoa(CA->cl_addr.sin_addr));
1492
1493 printf(" sin_zero = \"%c%c%c%c%c%c%c%c\"\n",
1494 CA->cl_addr.sin_zero[0],
1495 CA->cl_addr.sin_zero[1],
1496 CA->cl_addr.sin_zero[2],
1497 CA->cl_addr.sin_zero[3],
1498 CA->cl_addr.sin_zero[4],
1499 CA->cl_addr.sin_zero[5],
1500 CA->cl_addr.sin_zero[6],
1501 CA->cl_addr.sin_zero[7]);
1502
1503 printf("\n");
1504}
1505
1506//*******************
1507
1508void WriteTime(char* dst, osc_time_t osctime)
1509{
1510 *(int32_t*)dst = htonl((int32_t)(osctime >> 32));
1511 *(int32_t*)(dst+4) = htonl((int32_t)osctime);
1512}
1513
1514void WriteMode(char* dst)
1515{
1516 *(int32_t*)dst = htonl(0);
1517}
1518
1519osc_time_t ReadTime(const char* src)
1520{
1521 osc_time_t osctime = ntohl(*(int32_t*)src);
1522 return (osctime << 32) + ntohl(*(int32_t*)(src+4));
1523}
1524
1525double TimeToSeconds(osc_time_t osctime)
1526{
1527 return (double)osctime * 2.3283064365386962890625e-10 /* 1/2^32 */;
1528}
1529
1530int timeRound(double x)
1531{
1532 return x >= 0.0 ? x+0.5 : x-0.5;
1533}
1534/*
1535void WriteLogicalTime(char* dst)
1536{
1537 static double startTime = -1.0;
1538 double sTime;
1539
1540 // Initialisierung der Startzeit.
1541 // Knnte effizienter (ohne 'if') auch irgendwo vorher passieren.
1542 // Knnte wahrscheinlich auch 0.0 sein.
1543 if (startTime < 0.0) {
1544 startTime = clock_getlogicaltime();
1545 }
1546
1547 sTime = clock_gettimesince(startTime) * 0.001;
1548 *(int32_t*)dst = hton'K l((int32_t)sTime);
1549 *(int32_t*)(dst+4) = htonl((int32_t)(4294967296.0 * sTime));
1550}
1551*/
1552
1553void WriteLogicalTime(char* dst)
1554{
1555 double sTime = clock_gettimesince(19230720) / 1000.0;
1556 double tau = sTime - timeRound(sTime);
1557
1558 //fprintf(stderr, "sSec = %f tau = %f\n", sTime, tau);
1559
1560 *(int32_t*)dst = htonl((int32_t)(sTime));
1561 *(int32_t*)(dst+4) = htonl((int32_t)(4294967296 * tau));
1562}
1563
1564Boolean dumpOSC_SendReply(char *buf, int n, void *clientDesc, int clientDescLenght, int fd)
1565{
1566 if((n == 24) && (strcmp(buf, "#time") == 0))
1567 {
1568 osc_time_t t0, t1, t2;
1569 double dt0, dt1, dt2;
1570
1571 WriteMode(buf+6);
1572
1573 t0 = ReadTime(buf+8);
1574
1575 WriteLogicalTime(buf+16);
1576 t1 = ReadTime(buf+16); // reverse
1577 dt0 = TimeToSeconds(t0); // client time
1578 dt1 = TimeToSeconds(t1); // server time
1579
1580 // fprintf(stderr, "%f\t%f\t%f\n", dt0, dt1, dt0 - dt1);
1581
1582 sendto(fd, buf, n, 0, (struct sockaddr *)clientDesc, clientDescLenght);
1583 return TRUE;
1584 }
1585 else
1586 {
1587 return FALSE;
1588 }
1589}
1590
1591//**********************
1592
1593void dumpOSC_ParsePacket(t_dumpOSC *x, char *buf, int n, ClientAddr returnAddr) {
1594 // t_dumpOSC *x;
1595 int size, messageLen, i;
1596 char *messageName;
1597 char *args;
1598
1599 //#ifdef PRINTADDRS
1600 #ifdef DEBUG
1601 //PrintClientAddr(returnAddr);
1602 #endif
1603
1604
1605 if ((n%4) != 0) {
1606 complain("SynthControl packet size (%d) not a multiple of 4 bytes: dropping", n);
1607 return;
1608 }
1609
1610 if ((n >= 8) && (strncmp(buf, "#bundle", 8) == 0)) {
1611 /* This is a bundle message. */
1612 #ifdef DEBUG
1613 printf("dumpOSC_ParsePacket: bundle msg: bundles not yet supported\n");
1614 #endif
1615
1616 if (n < 16) {
1617 complain("Bundle message too small (%d bytes) for time tag", n);
1618 return;
1619 }
1620
1621 /* Print the time tag */
1622 #ifdef DEBUG
1623 printf("[ %lx%08lx\n", ntohl(*((unsigned long *)(buf+8))), ntohl(*((unsigned long *)(buf+12))));
1624 #endif
1625
1626 /* Note: if we wanted to actually use the time tag as a little-endian
1627 64-bit int, we'd have to word-swap the two 32-bit halves of it */
1628
1629 i = 16; /* Skip "#group\0" and time tag */
1630
1631 while(i<n) {
1632 size = ntohl(*((int *) (buf + i)));
1633 if ((size % 4) != 0) {
1634 complain("Bad size count %d in bundle (not a multiple of 4)", size);
1635 return;
1636 }
1637 if ((size + i + 4) > n) {
1638 complain("Bad size count %d in bundle (only %d bytes left in entire bundle)",
1639 size, n-i-4);
1640 return;
1641 }
1642
1643 /* Recursively handle element of bundle */
1644 dumpOSC_ParsePacket(x, buf+i+4, size, returnAddr);
1645 i += 4 + size;
1646 }
1647
1648 if (i != n) {
1649 complain("This can't happen");
1650 }
1651 #ifdef DEBUG
1652 printf("]\n");
1653 #endif
1654
1655 }
1656 else if ((n == 24) && (strcmp(buf, "#time") == 0))
1657 {
1658 complain("Time message: %s\n :).\n", htm_error_string);
1659 return;
1660
1661 }
1662 else
1663 {
1664 /* This is not a bundle message */
1665
1666 messageName = buf;
1667 args = DataAfterAlignedString(messageName, buf+n);
1668 if (args == 0) {
1669 complain("Bad message name string: %s\nDropping entire message.\n",
1670 htm_error_string);
1671 return;
1672 }
1673 messageLen = args-messageName;
1674 dumpOSC_Smessage(x, messageName, (void *)args, n-messageLen, returnAddr);
1675 }
1676}
1677
1678#define SMALLEST_POSITIVE_FLOAT 0.000001f
1679
1680static void dumpOSC_Smessage(t_dumpOSC *x, char *address, void *v, int n, ClientAddr returnAddr) {
1681 char *chars = v;
1682 t_atom at;
1683 //t_atom myargv[50];
1684
1685 int myargc = x->x_outatc;
1686 t_atom* mya = x->x_outat;
1687 int myi;
1688
1689#ifdef DEBUG
1690 printf("%s ", address);
1691#endif
1692
1693 // ztoln+cvt from envgen.c, ggee-0.18 ..
1694 // outlet_anything's 'symbol' gets set to address
1695 // so we dont need to append address to the atomlist
1696 /*
1697 SETSYMBOL(mya,gensym(address));myargc++;
1698 x->x_outatc = myargc;
1699 */
1700
1701 if (n != 0) {
1702 if (chars[0] == ',') {
1703 if (chars[1] != ',') {
1704 /* This message begins with a type-tag string */
1705 dumpOSC_PrintTypeTaggedArgs(x, v, n);
1706 } else {
1707 /* Double comma means an escaped real comma, not a type string */
1708 dumpOSC_PrintHeuristicallyTypeGuessedArgs(x, v, n, 1);
1709 }
1710 } else {
1711 dumpOSC_PrintHeuristicallyTypeGuessedArgs(x, v, n, 0);
1712 }
1713 }
1714
1715 outlet_anything(x->x_msgout,gensym(address),x->x_outatc,(t_atom*)&x->x_outat);
1716 x->x_outatc = 0;
1717#ifdef DEBUG
1718 printf("\n");
1719#endif
1720 fflush(stdout); /* Added for Sami 5/21/98 */
1721}
1722
1723static void dumpOSC_PrintTypeTaggedArgs(t_dumpOSC *x, void *v, int n) {
1724 char *typeTags, *thisType;
1725 char *p;
1726
1727 int myargc = x->x_outatc;
1728 t_atom* mya = x->x_outat;
1729 int myi;
1730
1731 typeTags = v;
1732
1733 if (!IsNiceString(typeTags, typeTags+n)) {
1734 /* No null-termination, so maybe it wasn't a type tag
1735 string after all */
1736 dumpOSC_PrintHeuristicallyTypeGuessedArgs(x, v, n, 0);
1737 return;
1738 }
1739
1740 p = DataAfterAlignedString(typeTags, typeTags+n);
1741
1742
1743 for (thisType = typeTags + 1; *thisType != 0; ++thisType) {
1744 switch (*thisType) {
1745 case 'i': case 'r': case 'm': case 'c':
1746#ifdef DEBUG
1747 //post("integer: %d", ntohl(*((int *) p)));
1748#endif
1749 /* Martin Peach fix for negative floats:
1750 * was: SETFLOAT(mya+myargc,ntohl(*((int *) p)));
1751 * now is:
1752 */
1753 SETFLOAT(mya+myargc,(signed)ntohl(*((int *) p)));
1754 myargc++;
1755
1756 p += 4;
1757 break;
1758
1759 case 'f': {
1760 int i = ntohl(*((int *) p));
1761 float *floatp = ((float *) (&i));
1762#ifdef DEBUG
1763 post("float: %f", *floatp);
1764#endif
1765 SETFLOAT(mya+myargc,*floatp);
1766 myargc++;
1767
1768 p += 4;
1769 }
1770 break;
1771
1772 case 'h': case 't':
1773#ifdef DEBUG
1774 printf("[A 64-bit int] ");
1775#endif
1776 post("[A 64-bit int] not implemented");
1777
1778 p += 8;
1779 break;
1780
1781 case 'd':
1782#ifdef DEBUG
1783 printf("[A 64-bit float] ");
1784#endif
1785 post("[A 64-bit float] not implemented");
1786
1787 p += 8;
1788 break;
1789
1790 case 's': case 'S':
1791 if (!IsNiceString(p, typeTags+n)) {
1792 post("Type tag said this arg is a string but it's not!\n");
1793 return;
1794 } else {
1795#ifdef DEBUG
1796 post("string: \"%s\"", p);
1797#endif
1798 SETSYMBOL(mya+myargc,gensym(p));
1799 myargc++;
1800 //outlet_list(x->x_msgout, 0,sizeof(p), p);
1801 //outlet_anything(x->x_msgout, 0, sizeof(p), p);
1802 p = DataAfterAlignedString(p, typeTags+n);
1803 // append to output vector ..
1804 }
1805 break;
1806
1807 case 'T':
1808#ifdef DEBUG
1809 printf("[True] ");
1810#endif
1811 SETFLOAT(mya+myargc,1.);
1812 myargc++;
1813 break;
1814 case 'F':
1815#ifdef DEBUG
1816 printf("[False] ");
1817#endif
1818 SETFLOAT(mya+myargc,0.);
1819 myargc++;
1820 break;
1821 case 'N':
1822#ifdef DEBUG
1823 printf("[Nil]");
1824#endif
1825 post("sendOSC: [Nil] not implemented");
1826 break;
1827 case 'I':
1828#ifdef DEBUG
1829 printf("[Infinitum]");
1830#endif
1831 post("sendOSC: [Infinitum] not implemented");
1832 break;
1833
1834 default:
1835 post("sendOSC: [Unrecognized type tag %c]", *thisType);
1836 // return;
1837 }
1838 }
1839 x->x_outatc = myargc;
1840}
1841
1842static void dumpOSC_PrintHeuristicallyTypeGuessedArgs(t_dumpOSC *x, void *v, int n, int skipComma) {
1843 int i, thisi;
1844 float thisf;
1845 int *ints;
1846 char *chars;
1847 char *string, *nextString;
1848
1849 int myargc= x->x_outatc;
1850 t_atom* mya = x->x_outat;
1851 int myi;
1852
1853
1854 /* Go through the arguments 32 bits at a time */
1855 ints = v;
1856 chars = v;
1857
1858 for (i = 0; i<n/4; ) {
1859 string = &chars[i*4];
1860 thisi = ntohl(ints[i]);
1861 /* Reinterpret the (potentially byte-reversed) thisi as a float */
1862 thisf = *(((float *) (&thisi)));
1863
1864 if (thisi >= -1000 && thisi <= 1000000) {
1865#ifdef DEBUG
1866 printf("%d ", thisi);
1867#endif
1868 // append to output vector ..
1869 SETFLOAT(mya+myargc,(t_float) (thisi));
1870 myargc++;
1871 // outlet_float(x->x_msgout, thisi);
1872 i++;
1873 } else if (thisf >= -1000.f && thisf <= 1000000.f &&
1874 (thisf <=0.0f || thisf >= SMALLEST_POSITIVE_FLOAT)) {
1875#ifdef DEBUG
1876 printf("%f ", thisf);
1877#endif
1878 // append to output vector ..
1879 SETFLOAT(mya+myargc,thisf);
1880 myargc++;
1881 //outlet_float(x->x_msgout, thisf);
1882 i++;
1883 } else if (IsNiceString(string, chars+n)) {
1884 nextString = DataAfterAlignedString(string, chars+n);
1885#ifdef DEBUG
1886 printf("\"%s\" ", (i == 0 && skipComma) ? string +1 : string);
1887#endif
1888 // append to output vector ..
1889 SETSYMBOL(mya+myargc,gensym(string));
1890 myargc++;
1891 //outlet_symbol(x->x_msgout, gensym((i == 0 && skipComma) ? string +1 : string));
1892 i += (nextString-string) / 4;
1893 } else {
1894 // unhandled .. ;)
1895#ifdef DEBUG
1896 printf("0x%x xx", ints[i]);
1897#endif
1898 i++;
1899 }
1900 x->x_outatc = myargc;
1901 }
1902}
1903
1904
1905#define STRING_ALIGN_PAD 4
1906
1907char *DataAfterAlignedString(char *string, char *boundary)
1908{
1909 /* The argument is a block of data beginning with a string. The
1910 string has (presumably) been padded with extra null characters
1911 so that the overall length is a multiple of STRING_ALIGN_PAD
1912 bytes. Return a pointer to the next byte after the null
1913 byte(s). The boundary argument points to the character after
1914 the last valid character in the buffer---if the string hasn't
1915 ended by there, something's wrong.
1916
1917 If the data looks wrong, return 0, and set htm_error_string */
1918
1919 int i;
1920
1921 if ((boundary - string) %4 != 0) {
1922 fprintf(stderr, "Internal error: DataAfterAlignedString: bad boundary\n");
1923 return 0;
1924 }
1925
1926 for (i = 0; string[i] != '\0'; i++) {
1927 if (string + i >= boundary) {
1928 htm_error_string = "DataAfterAlignedString: Unreasonably long string";
1929 return 0;
1930 }
1931 }
1932
1933 /* Now string[i] is the first null character */
1934 i++;
1935
1936 for (; (i % STRING_ALIGN_PAD) != 0; i++) {
1937 if (string + i >= boundary) {
1938 htm_error_string = "DataAfterAlignedString: Unreasonably long string";
1939 return 0;
1940 }
1941 if (string[i] != '\0') {
1942 htm_error_string = "DataAfterAlignedString: Incorrectly padded string.";
1943 return 0;
1944 }
1945 }
1946
1947 return string+i;
1948}
1949
1950Boolean IsNiceString(char *string, char *boundary)
1951{
1952 /* Arguments same as DataAfterAlignedString(). Is the given "string"
1953 really a string? I.e., is it a sequence of isprint() characters
1954 terminated with 1-4 null characters to align on a 4-byte boundary? */
1955
1956 int i;
1957
1958 if ((boundary - string) %4 != 0) {
1959 fprintf(stderr, "Internal error: IsNiceString: bad boundary\n");
1960 return 0;
1961 }
1962
1963 for (i = 0; string[i] != '\0'; i++) {
1964 if (!isprint(string[i])) return FALSE;
1965 if (string + i >= boundary) return FALSE;
1966 }
1967
1968 /* If we made it this far, it's a null-terminated sequence of printing characters
1969 in the given boundary. Now we just make sure it's null padded... */
1970
1971 /* Now string[i] is the first null character */
1972 i++;
1973 for (; (i % STRING_ALIGN_PAD) != 0; i++) {
1974 if (string[i] != '\0') return FALSE;
1975 }
1976
1977 return TRUE;
1978}
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988#include <stdarg.h>
1989void complain(char *s, ...) {
1990 va_list ap;
1991 va_start(ap, s);
1992 fprintf(stderr, "*** ERROR: ");
1993 vfprintf(stderr, s, ap);
1994 fprintf(stderr, "\n");
1995 va_end(ap);
1996}
1997
1998#endif /* __sgi or LINUX or WIN32 */