diff options
author | Peter D'Hoye <peter.dhoye@gmail.com> | 2009-05-22 21:58:48 +0000 |
---|---|---|
committer | Peter D'Hoye <peter.dhoye@gmail.com> | 2009-05-22 21:58:48 +0000 |
commit | 513389b4c1bc8afe4b2dc9947c534bfeb105e3da (patch) | |
tree | 10e673b35651ac567fed2eda0c679c7ade64cbc6 /apps/plugins/pdbox/PDa/extra/dumpOSC.c | |
parent | 95fa7f6a2ef466444fbe3fe87efc6d5db6b77b36 (diff) | |
download | rockbox-513389b4c1bc8afe4b2dc9947c534bfeb105e3da.tar.gz rockbox-513389b4c1bc8afe4b2dc9947c534bfeb105e3da.zip |
Add FS #10214. Initial commit of the original PDa code for the GSoC Pure Data plugin project of Wincent Balin. Stripped some non-sourcefiles and added a rockbox readme that needs a bit more info from Wincent. Is added to CATEGORIES and viewers, but not yet to SUBDIRS (ie doesn't build yet)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@21044 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/pdbox/PDa/extra/dumpOSC.c')
-rw-r--r-- | apps/plugins/pdbox/PDa/extra/dumpOSC.c | 1998 |
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 | /* | ||
2 | Written by Matt Wright and Adrian Freed, The Center for New Music and | ||
3 | Audio Technologies, University of California, Berkeley. Copyright (c) | ||
4 | 1992,93,94,95,96,97,98,99,2000,01,02,03,04 The Regents of the University of | ||
5 | California (Regents). | ||
6 | |||
7 | Permission to use, copy, modify, distribute, and distribute modified versions | ||
8 | of this software and its documentation without fee and without a signed | ||
9 | licensing agreement, is hereby granted, provided that the above copyright | ||
10 | notice, this paragraph and the following two paragraphs appear in all copies, | ||
11 | modifications, and distributions. | ||
12 | |||
13 | IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, | ||
14 | SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING | ||
15 | OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS | ||
16 | BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
17 | |||
18 | REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | ||
19 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||
20 | PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED | ||
21 | HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE | ||
22 | MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. | ||
23 | |||
24 | |||
25 | The 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); | ||
80 | void 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 | |||
127 | char *htm_error_string; | ||
128 | typedef int Boolean; | ||
129 | typedef void *OBJ; | ||
130 | |||
131 | typedef struct ClientAddressStruct { | ||
132 | struct sockaddr_in cl_addr; | ||
133 | int clilen; | ||
134 | int sockfd; | ||
135 | } *ClientAddr; | ||
136 | |||
137 | typedef unsigned long long osc_time_t; | ||
138 | |||
139 | Boolean ShowBytes = FALSE; | ||
140 | Boolean Silent = FALSE; | ||
141 | |||
142 | /* Declarations */ | ||
143 | #ifndef WIN32 | ||
144 | static int unixinitudp(int chan); | ||
145 | #endif | ||
146 | |||
147 | static int initudp(int chan); | ||
148 | static void closeudp(int sockfd); | ||
149 | Boolean ClientReply(int packetsize, void *packet, int socketfd, | ||
150 | void *clientaddresspointer, int clientaddressbufferlength); | ||
151 | void sgi_CleanExit(void); | ||
152 | Boolean sgi_HaveToQuit(void); | ||
153 | int RegisterPollingDevice(int fd, void (*callbackfunction)(int , void *), void *dummy); | ||
154 | static void catch_sigint(); | ||
155 | static int Synthmessage(char *m, int n, void *clientdesc, int clientdesclength, int fd) ; | ||
156 | char *DataAfterAlignedString(char *string, char *boundary) ; | ||
157 | Boolean IsNiceString(char *string, char *boundary) ; | ||
158 | void complain(char *s, ...); | ||
159 | |||
160 | #define MAXMESG 32768 | ||
161 | static char mbuf[MAXMESG]; | ||
162 | |||
163 | /* ----------------------------- dumpOSC ------------------------- */ | ||
164 | |||
165 | #define MAXOUTAT 50 | ||
166 | |||
167 | static t_class *dumpOSC_class; | ||
168 | |||
169 | typedef 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 | |||
184 | void dumpOSC_ParsePacket(t_dumpOSC *x, char *buf, int n, ClientAddr returnAddr); | ||
185 | Boolean dumpOSC_SendReply(char *buf, int n, void *clientDesc, int clientDescLenght, int fd); | ||
186 | static void dumpOSC_Smessage(t_dumpOSC *x, char *address, void *v, int n, ClientAddr returnAddr); | ||
187 | static void dumpOSC_PrintTypeTaggedArgs(t_dumpOSC *x, void *v, int n); | ||
188 | static void dumpOSC_PrintHeuristicallyTypeGuessedArgs(t_dumpOSC *x, void *v, int n, int skipComma); | ||
189 | |||
190 | static 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 | |||
243 | static 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 | |||
312 | static 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 | ||
323 | OSC_API void dumpOSC_setup(void) | ||
324 | #else | ||
325 | void 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 | |||
365 | static 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 | |||
418 | static void closeudp(int sockfd) { | ||
419 | #ifdef WIN32 | ||
420 | closesocket(sockfd); | ||
421 | #else | ||
422 | close(sockfd); | ||
423 | #endif | ||
424 | } | ||
425 | |||
426 | static Boolean catchupflag=FALSE; | ||
427 | Boolean 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 | |||
435 | static Boolean exitflag= FALSE; | ||
436 | void sgi_CleanExit(void) { | ||
437 | exitflag = TRUE; | ||
438 | } | ||
439 | |||
440 | Boolean sgi_HaveToQuit(void) { | ||
441 | return exitflag; | ||
442 | } | ||
443 | |||
444 | |||
445 | /* file descriptor poll table */ | ||
446 | static int npolldevs =0; | ||
447 | typedef struct polldev | ||
448 | { | ||
449 | int fd; | ||
450 | void (*callbackfunction)(int , void *); | ||
451 | void *dummy; | ||
452 | } polldev; | ||
453 | #define TABMAX 8 | ||
454 | static 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 | */ | ||
466 | int 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 | |||
478 | static int caught_sigint; | ||
479 | |||
480 | static void catch_sigint() { | ||
481 | caught_sigint = 1; | ||
482 | } | ||
483 | static int sockfd, usockfd; | ||
484 | |||
485 | |||
486 | void 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 | |||
509 | void 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 | |||
515 | void WriteMode(char* dst) | ||
516 | { | ||
517 | *(int32_t*)dst = htonl(0); | ||
518 | } | ||
519 | |||
520 | osc_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 | |||
526 | double TimeToSeconds(osc_time_t osctime) | ||
527 | { | ||
528 | return (double)osctime * 2.3283064365386962890625e-10 /* 1/2^32 */; | ||
529 | } | ||
530 | |||
531 | int timeRound(double x) | ||
532 | { | ||
533 | return x >= 0.0 ? x+0.5 : x-0.5; | ||
534 | } | ||
535 | /* | ||
536 | void 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 | |||
554 | void 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 | |||
565 | Boolean 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 | |||
594 | void 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 | |||
681 | static 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 | |||
724 | static 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 | |||
843 | static 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 | |||
908 | char *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 | |||
951 | Boolean 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> | ||
990 | void 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 | /* | ||
1001 | Written by Matt Wright and Adrian Freed, The Center for New Music and | ||
1002 | Audio Technologies, University of California, Berkeley. Copyright (c) | ||
1003 | 1992,93,94,95,96,97,98,99,2000,01,02,03,04 The Regents of the University of | ||
1004 | California (Regents). | ||
1005 | |||
1006 | Permission to use, copy, modify, distribute, and distribute modified versions | ||
1007 | of this software and its documentation without fee and without a signed | ||
1008 | licensing agreement, is hereby granted, provided that the above copyright | ||
1009 | notice, this paragraph and the following two paragraphs appear in all copies, | ||
1010 | modifications, and distributions. | ||
1011 | |||
1012 | IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, | ||
1013 | SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING | ||
1014 | OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS | ||
1015 | BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
1016 | |||
1017 | REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | ||
1018 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||
1019 | PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED | ||
1020 | HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE | ||
1021 | MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. | ||
1022 | |||
1023 | |||
1024 | The 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); | ||
1079 | void 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 | |||
1126 | char *htm_error_string; | ||
1127 | typedef int Boolean; | ||
1128 | typedef void *OBJ; | ||
1129 | |||
1130 | typedef struct ClientAddressStruct { | ||
1131 | struct sockaddr_in cl_addr; | ||
1132 | int clilen; | ||
1133 | int sockfd; | ||
1134 | } *ClientAddr; | ||
1135 | |||
1136 | typedef unsigned long long osc_time_t; | ||
1137 | |||
1138 | Boolean ShowBytes = FALSE; | ||
1139 | Boolean Silent = FALSE; | ||
1140 | |||
1141 | /* Declarations */ | ||
1142 | #ifndef WIN32 | ||
1143 | static int unixinitudp(int chan); | ||
1144 | #endif | ||
1145 | |||
1146 | static int initudp(int chan); | ||
1147 | static void closeudp(int sockfd); | ||
1148 | Boolean ClientReply(int packetsize, void *packet, int socketfd, | ||
1149 | void *clientaddresspointer, int clientaddressbufferlength); | ||
1150 | void sgi_CleanExit(void); | ||
1151 | Boolean sgi_HaveToQuit(void); | ||
1152 | int RegisterPollingDevice(int fd, void (*callbackfunction)(int , void *), void *dummy); | ||
1153 | static void catch_sigint(); | ||
1154 | static int Synthmessage(char *m, int n, void *clientdesc, int clientdesclength, int fd) ; | ||
1155 | char *DataAfterAlignedString(char *string, char *boundary) ; | ||
1156 | Boolean IsNiceString(char *string, char *boundary) ; | ||
1157 | void complain(char *s, ...); | ||
1158 | |||
1159 | #define MAXMESG 32768 | ||
1160 | static char mbuf[MAXMESG]; | ||
1161 | |||
1162 | /* ----------------------------- dumpOSC ------------------------- */ | ||
1163 | |||
1164 | #define MAXOUTAT 50 | ||
1165 | |||
1166 | static t_class *dumpOSC_class; | ||
1167 | |||
1168 | typedef 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 | |||
1183 | void dumpOSC_ParsePacket(t_dumpOSC *x, char *buf, int n, ClientAddr returnAddr); | ||
1184 | Boolean dumpOSC_SendReply(char *buf, int n, void *clientDesc, int clientDescLenght, int fd); | ||
1185 | static void dumpOSC_Smessage(t_dumpOSC *x, char *address, void *v, int n, ClientAddr returnAddr); | ||
1186 | static void dumpOSC_PrintTypeTaggedArgs(t_dumpOSC *x, void *v, int n); | ||
1187 | static void dumpOSC_PrintHeuristicallyTypeGuessedArgs(t_dumpOSC *x, void *v, int n, int skipComma); | ||
1188 | |||
1189 | static 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 | |||
1242 | static 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 | |||
1311 | static 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 | ||
1322 | OSC_API void dumpOSC_setup(void) | ||
1323 | #else | ||
1324 | void 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 | |||
1364 | static 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 | |||
1417 | static void closeudp(int sockfd) { | ||
1418 | #ifdef WIN32 | ||
1419 | closesocket(sockfd); | ||
1420 | #else | ||
1421 | close(sockfd); | ||
1422 | #endif | ||
1423 | } | ||
1424 | |||
1425 | static Boolean catchupflag=FALSE; | ||
1426 | Boolean 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 | |||
1434 | static Boolean exitflag= FALSE; | ||
1435 | void sgi_CleanExit(void) { | ||
1436 | exitflag = TRUE; | ||
1437 | } | ||
1438 | |||
1439 | Boolean sgi_HaveToQuit(void) { | ||
1440 | return exitflag; | ||
1441 | } | ||
1442 | |||
1443 | |||
1444 | /* file descriptor poll table */ | ||
1445 | static int npolldevs =0; | ||
1446 | typedef struct polldev | ||
1447 | { | ||
1448 | int fd; | ||
1449 | void (*callbackfunction)(int , void *); | ||
1450 | void *dummy; | ||
1451 | } polldev; | ||
1452 | #define TABMAX 8 | ||
1453 | static 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 | */ | ||
1465 | int 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 | |||
1477 | static int caught_sigint; | ||
1478 | |||
1479 | static void catch_sigint() { | ||
1480 | caught_sigint = 1; | ||
1481 | } | ||
1482 | static int sockfd, usockfd; | ||
1483 | |||
1484 | |||
1485 | void 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 | |||
1508 | void 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 | |||
1514 | void WriteMode(char* dst) | ||
1515 | { | ||
1516 | *(int32_t*)dst = htonl(0); | ||
1517 | } | ||
1518 | |||
1519 | osc_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 | |||
1525 | double TimeToSeconds(osc_time_t osctime) | ||
1526 | { | ||
1527 | return (double)osctime * 2.3283064365386962890625e-10 /* 1/2^32 */; | ||
1528 | } | ||
1529 | |||
1530 | int timeRound(double x) | ||
1531 | { | ||
1532 | return x >= 0.0 ? x+0.5 : x-0.5; | ||
1533 | } | ||
1534 | /* | ||
1535 | void 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 | |||
1553 | void 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 | |||
1564 | Boolean 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 | |||
1593 | void 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 | |||
1680 | static 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 | |||
1723 | static 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 | |||
1842 | static 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 | |||
1907 | char *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 | |||
1950 | Boolean 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> | ||
1989 | void 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 */ | ||