2 Written by Matt Wright, The Center for New Music and Audio Technologies,
3 University of California, Berkeley. Copyright (c) 1996,97,98,99,2000,01,02,03
4 The Regents of the University of California (Regents).
6 Permission to use, copy, modify, distribute, and distribute modified versions
7 of this software and its documentation without fee and without a signed
8 licensing agreement, is hereby granted, provided that the above copyright
9 notice, this paragraph and the following two paragraphs appear in all copies,
10 modifications, and distributions.
12 IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
13 SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
14 OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
15 BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17 REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
20 HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
21 MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24 The OSC webpage is http://cnmat.cnmat.berkeley.edu/OpenSoundControl
31 based on sendOSC.c, which was based on a version by Adrian Freed
33 Text-based OpenSoundControl client. User can enter messages via command
34 line arguments or standard input.
36 Version 0.1: "play" feature
37 Version 0.2: Message type tags.
39 pd version branched from http://www.cnmat.berkeley.edu/OpenSoundControl/src/sendOSC/sendOSC.c
41 -- added bundle stuff to send. jdl 20020416
42 -- tweaks for Win32 www.zeggz.com/raf 13-April-2002
43 -- ost_at_test.at + i22_at_test.at, 2000-2002
44 modified to compile as pd externel
48 #define SC_BUFFER_SIZE 64000
50 #include "../src/m_pd.h"
51 #include "OSC-client.h"
54 #include <sys/types.h>
58 #include <sys/types.h>
69 #include <sys/socket.h>
70 #include <netinet/in.h>
72 #include <sys/times.h>
73 #include <sys/param.h>
75 #include <sys/ioctl.h>
83 #define UNIXDG_PATH "/tmp/htm"
84 #define UNIXDG_TMP "/tmp/htm.XXXXXX"
88 OSCTimeTag
OSCTT_Immediately(void) {
96 OSCTimeTag
OSCTT_CurrentTime(void) {
103 OSCTimeTag
OSCTT_PlusSeconds(OSCTimeTag original
, float secondsOffset
) {
117 struct sockaddr_in serv_addr
; /* udp socket */
119 struct sockaddr_un userv_addr
; /* UNIX socket */
121 int sockfd
; /* socket file descriptor */
122 int index
, len
,uservlen
;
128 /* open a socket for HTM communication to given host on given portnumber */
129 /* if host is 0 then UNIX protocol is used (i.e. local communication */
130 void *OpenHTMSocket(char *host
, int portnumber
)
132 struct sockaddr_in cl_addr
;
135 struct sockaddr_un ucl_addr
;
142 o
= malloc(sizeof(*o
));
149 char *mktemp(char *);
151 o
->len
= sizeof(ucl_addr
);
153 * Fill in the structure "userv_addr" with the address of the
154 * server that we want to send to.
157 bzero((char *) &o
->userv_addr
, sizeof(o
->userv_addr
));
158 o
->userv_addr
.sun_family
= AF_UNIX
;
159 strcpy(o
->userv_addr
.sun_path
, UNIXDG_PATH
);
160 sprintf(o
->userv_addr
.sun_path
+strlen(o
->userv_addr
.sun_path
), "%d", portnumber
);
161 o
->uservlen
= sizeof(o
->userv_addr
.sun_family
) + strlen(o
->userv_addr
.sun_path
);
162 o
->addr
= &(o
->userv_addr
);
164 * Open a socket (a UNIX domain datagram socket).
167 if ( (sockfd
= socket(AF_UNIX
, SOCK_DGRAM
, 0)) >= 0)
170 * Bind a local address for us.
171 * In the UNIX domain we have to choose our own name (that
172 * should be unique). We'll use mktemp() to create a unique
173 * pathname, based on our process id.
176 bzero((char *) &ucl_addr
, sizeof(ucl_addr
)); /* zero out */
177 ucl_addr
.sun_family
= AF_UNIX
;
178 strcpy(ucl_addr
.sun_path
, UNIXDG_TMP
);
180 mktemp(ucl_addr
.sun_path
);
181 clilen
= sizeof(ucl_addr
.sun_family
) + strlen(ucl_addr
.sun_path
);
183 if (bind(sockfd
, (struct sockaddr
*) &ucl_addr
, clilen
) < 0)
185 perror("client: can't bind local address");
191 perror("unable to make socket\n");
199 * Fill in the structure "serv_addr" with the address of the
200 * server that we want to send to.
202 o
->len
= sizeof(cl_addr
);
205 ZeroMemory((char *)&o
->serv_addr
, sizeof(o
->serv_addr
));
207 bzero((char *)&o
->serv_addr
, sizeof(o
->serv_addr
));
210 o
->serv_addr
.sin_family
= AF_INET
;
212 /* MW 6/6/96: Call gethostbyname() instead of inet_addr(),
213 so that host can be either an Internet host name (e.g.,
214 "les") or an Internet address in standard dot notation
215 (e.g., "128.32.122.13") */
217 struct hostent
*hostsEntry
;
218 unsigned long address
;
220 hostsEntry
= gethostbyname(host
);
221 if (hostsEntry
== NULL
) {
222 fprintf(stderr
, "Couldn't decipher host name \"%s\"\n", host
);
228 address
= *((unsigned long *) hostsEntry
->h_addr_list
[0]);
229 o
->serv_addr
.sin_addr
.s_addr
= address
;
232 /* was: o->serv_addr.sin_addr.s_addr = inet_addr(host); */
237 * Open a socket (a UDP domain datagram socket).
242 o
->serv_addr
.sin_port
= htons((USHORT
)portnumber
);
243 o
->addr
= &(o
->serv_addr
);
244 if((sockfd
= socket(AF_INET
, SOCK_DGRAM
, 0)) != INVALID_SOCKET
) {
245 ZeroMemory((char *)&cl_addr
, sizeof(cl_addr
));
246 cl_addr
.sin_family
= AF_INET
;
247 cl_addr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
248 cl_addr
.sin_port
= htons(0);
250 // enable broadcast: jdl ~2003
251 if(setsockopt(sockfd
, SOL_SOCKET
, SO_BROADCAST
, &oval
, sizeof(int)) == -1) {
252 perror("setsockopt");
255 if(bind(sockfd
, (struct sockaddr
*) &cl_addr
, sizeof(cl_addr
)) < 0) {
256 perror("could not bind\n");
261 else { perror("unable to make socket\n");}
263 o
->serv_addr
.sin_port
= htons(portnumber
);
264 o
->addr
= &(o
->serv_addr
);
265 if((sockfd
= socket(AF_INET
, SOCK_DGRAM
, 0)) >= 0) {
266 bzero((char *)&cl_addr
, sizeof(cl_addr
));
267 cl_addr
.sin_family
= AF_INET
;
268 cl_addr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
269 cl_addr
.sin_port
= htons(0);
271 // enable broadcast: jdl ~2003
272 if(setsockopt(sockfd
, SOL_SOCKET
, SO_BROADCAST
, &oval
, sizeof(int)) == -1) {
273 perror("setsockopt");
276 if(bind(sockfd
, (struct sockaddr
*) &cl_addr
, sizeof(cl_addr
)) < 0) {
277 perror("could not bind\n");
282 else { perror("unable to make socket\n");}
286 if(sockfd
== INVALID_SOCKET
) {
298 static bool sendudp(const struct sockaddr
*sp
, int sockfd
,int length
, int count
, void *b
)
301 if((rcount
=sendto(sockfd
, b
, count
, 0, sp
, length
)) != count
)
303 printf("sockfd %d count %d rcount %dlength %d\n", sockfd
,count
,rcount
,length
);
309 bool SendHTMSocket(void *htmsendhandle
, int length_in_bytes
, void *buffer
)
311 desc
*o
= (desc
*)htmsendhandle
;
312 return sendudp(o
->addr
, o
->sockfd
, o
->len
, length_in_bytes
, buffer
);
314 void CloseHTMSocket(void *htmsendhandle
)
316 desc
*o
= (desc
*)htmsendhandle
;
318 if(SOCKET_ERROR
== closesocket(o
->sockfd
)) {
319 perror("CloseHTMSocket::closesocket failed\n");
323 if(close(o
->sockfd
) == -1)
325 perror("CloseHTMSocket::closesocket failed");
334 ///////////////////////
338 //enum {INT, FLOAT, STRING} type;
339 enum {INT_osc
, FLOAT_osc
, STRING_osc
} type
;
347 void CommandLineMode(int argc
, char *argv
[], void *htmsocket
);
348 OSCTimeTag
ParseTimeTag(char *s
);
349 void ParseInteractiveLine(OSCbuf
*buf
, char *mesg
);
350 typedArg
ParseToken(char *token
);
351 int WriteMessage(OSCbuf
*buf
, char *messageName
, int numArgs
, typedArg
*args
);
352 void SendBuffer(void *htmsocket
, OSCbuf
*buf
);
353 void SendData(void *htmsocket
, int size
, char *data
);
354 /* defined in OSC-system-dependent.c now */
356 //static void *htmsocket;
357 static int exitStatus
= 0;
358 static int useTypeTags
= 0;
360 static char bufferForOSCbuf
[SC_BUFFER_SIZE
];
366 static t_class
*sendOSC_class
;
368 typedef struct _sendOSC
371 int x_protocol
; // UDP/TCP (udp only atm)
372 t_int x_typetags
; // typetag flag
373 void *x_htmsocket
; // sending socket
374 int x_bundle
; // bundle open flag
375 OSCbuf x_oscbuf
[1]; // OSCbuffer
376 t_outlet
*x_bdpthout
;// bundle-depth floatoutlet
379 static void *sendOSC_new(t_floatarg udpflag
)
381 t_sendOSC
*x
= (t_sendOSC
*)pd_new(sendOSC_class
);
382 outlet_new(&x
->x_obj
, &s_float
);
383 x
->x_htmsocket
= 0; // {{raf}}
385 x
->x_protocol
= SOCK_STREAM
;
386 // set typetags to 1 by default
390 OSC_initBuffer(x
->x_oscbuf
, SC_BUFFER_SIZE
, bufferForOSCbuf
);
391 x
->x_bdpthout
= outlet_new(&x
->x_obj
, 0); // outlet_float();
397 void sendOSC_openbundle(t_sendOSC
*x
)
399 if (x
->x_oscbuf
->bundleDepth
+ 1 >= MAX_BUNDLE_NESTING
||
400 OSC_openBundle(x
->x_oscbuf
, OSCTT_Immediately()))
402 post("Problem opening bundle: %s\n", OSC_errorMessage
);
406 outlet_float(x
->x_bdpthout
, (float)x
->x_oscbuf
->bundleDepth
);
409 static void sendOSC_closebundle(t_sendOSC
*x
)
411 if (OSC_closeBundle(x
->x_oscbuf
)) {
412 post("Problem closing bundle: %s\n", OSC_errorMessage
);
415 outlet_float(x
->x_bdpthout
, (float)x
->x_oscbuf
->bundleDepth
);
416 // in bundle mode we send when bundle is closed?
417 if(!OSC_isBufferEmpty(x
->x_oscbuf
) > 0 && OSC_isBufferDone(x
->x_oscbuf
)) {
418 // post("x_oscbuf: something inside me?");
419 if (x
->x_htmsocket
) {
420 SendBuffer(x
->x_htmsocket
, x
->x_oscbuf
);
422 post("sendOSC: not connected");
424 OSC_initBuffer(x
->x_oscbuf
, SC_BUFFER_SIZE
, bufferForOSCbuf
);
428 // post("x_oscbuf: something went wrong");
431 static void sendOSC_settypetags(t_sendOSC
*x
, t_float
*f
)
433 x
->x_typetags
= (int)f
;
434 post("sendOSC.c: setting typetags %d",x
->x_typetags
);
438 static void sendOSC_connect(t_sendOSC
*x
, t_symbol
*hostname
,
441 int portno
= fportno
;
442 /* create a socket */
444 // make sure handle is available
445 if(x
->x_htmsocket
== 0) {
447 x
->x_htmsocket
= OpenHTMSocket(hostname
->s_name
, portno
);
449 post("Couldn't open socket: ");
451 post("connected to port %s:%d (hSock=%d)", hostname
->s_name
, portno
, x
->x_htmsocket
);
452 outlet_float(x
->x_obj
.ob_outlet
, 1);
456 perror("call to sendOSC_connect() against UNavailable socket handle");
459 void sendOSC_disconnect(t_sendOSC
*x
)
463 post("disconnecting htmsock (hSock=%d)...", x
->x_htmsocket
);
464 CloseHTMSocket(x
->x_htmsocket
);
465 x
->x_htmsocket
= 0; // {{raf}} semi-quasi-semaphorize this
466 outlet_float(x
->x_obj
.ob_outlet
, 0);
469 perror("call to sendOSC_disconnect() against unused socket handle");
473 void sendOSC_senduntyped(t_sendOSC
*x
, t_symbol
*s
, int argc
, t_atom
*argv
)
475 char* targv
[MAXPDARG
];
476 char tmparg
[MAXPDSTRING
];
478 //char testarg[MAXPDSTRING];
481 post("sendOSC: use typetags 0/1 message and plain send method so send untypetagged...");
484 //atom_string(argv,testarg, MAXPDSTRING);
485 for (c
=0;c
<argc
;c
++) {
486 atom_string(argv
+c
,tmp
, 80);
488 tmp
+= strlen(tmp
)+1;
491 // this sock needs to be larger than 0, not >= ..
494 CommandLineMode(argc
, targv
, x
->x_htmsocket
);
495 // post("test %d", c);
498 post("sendOSC: not connected");
502 //////////////////////////////////////////////////////////////////////
503 // this is the real and only sending routine now, for both typed and
506 static void sendOSC_sendtyped(t_sendOSC
*x
, t_symbol
*s
, int argc
, t_atom
*argv
)
508 char* targv
[MAX_ARGS
];
509 char tmparg
[MAXPDSTRING
];
515 typedArg args
[MAX_ARGS
];
521 post ("sendOSC: messageName: %s", messageName
);
526 for (c
=0;c
<argc
;c
++) {
527 atom_string(argv
+c
,tmp
, 80);
530 // post ("sendOSC: %d, %s",c, tmp);
534 tmp
+= strlen(tmp
)+1;
537 // post ("sendOSC: %d, %s",c, targv[c]);
541 // this sock needs to be larger than 0, not >= ..
542 if (x
->x_htmsocket
> 0)
545 post ("sendOSC: type tags? %d", useTypeTags
);
548 messageName
= strtok(targv
[0], ",");
550 for (i
= j
; i
< argc
; i
++) {
551 token
= strtok(targv
[i
],",");
552 args
[i
-j
] = ParseToken(token
);
554 printf("cell-cont: %s\n", targv
[i
]);
555 printf(" type-id: %d\n", args
[i
-j
]);
561 if(WriteMessage(x
->x_oscbuf
, messageName
, numArgs
, args
)) {
562 post("sendOSC: usage error, write-msg failed: %s", OSC_errorMessage
);
567 SendBuffer(x
->x_htmsocket
, x
->x_oscbuf
);
568 OSC_initBuffer(x
->x_oscbuf
, SC_BUFFER_SIZE
, bufferForOSCbuf
);
571 //CommandLineMode(argc, targv, x->x_htmsocket);
575 post("sendOSC: not connected");
579 void sendOSC_send(t_sendOSC
*x
, t_symbol
*s
, int argc
, t_atom
*argv
)
582 post("not sending empty message.");
587 sendOSC_sendtyped(x
,s
,argc
,argv
);
590 sendOSC_sendtyped(x
,s
,argc
,argv
);
594 static void sendOSC_free(t_sendOSC
*x
)
596 sendOSC_disconnect(x
);
600 OSC_API
void sendOSC_setup(void) {
602 void sendOSC_setup(void) {
604 sendOSC_class
= class_new(gensym("sendOSC"), (t_newmethod
)sendOSC_new
,
605 (t_method
)sendOSC_free
,
606 sizeof(t_sendOSC
), 0, A_DEFFLOAT
, 0);
607 class_addmethod(sendOSC_class
, (t_method
)sendOSC_connect
,
608 gensym("connect"), A_SYMBOL
, A_FLOAT
, 0);
609 class_addmethod(sendOSC_class
, (t_method
)sendOSC_disconnect
,
610 gensym("disconnect"), 0);
611 class_addmethod(sendOSC_class
, (t_method
)sendOSC_settypetags
,
614 class_addmethod(sendOSC_class
, (t_method
)sendOSC_send
,
617 class_addmethod(sendOSC_class
, (t_method
)sendOSC_send
,
618 gensym("senduntyped"),
620 class_addmethod(sendOSC_class
, (t_method
)sendOSC_send
,
623 class_addmethod(sendOSC_class
, (t_method
)sendOSC_openbundle
,
626 class_addmethod(sendOSC_class
, (t_method
)sendOSC_closebundle
,
629 class_sethelpsymbol(sendOSC_class
, gensym("sendOSC-help.pd"));
636 /* Exit status codes:
638 2: Message(s) dropped because of buffer overflow
644 void CommandLineMode(int argc
, char *argv
[], void *htmsocket
) {
647 typedArg args
[MAX_ARGS
];
651 OSC_initBuffer(buf
, SC_BUFFER_SIZE
, bufferForOSCbuf
);
654 post("argc (%d) > 1", argc
);
657 // ParseInteractiveLine(buf, argv);
658 messageName
= strtok(argv
[0], ",");
661 for (i
= j
; i
< argc
; i
++) {
662 token
= strtok(argv
[i
],",");
663 args
[i
-j
] = ParseToken(token
);
665 printf("cell-cont: %s\n", argv
[i
]);
666 printf(" type-id: %d\n", args
[i
-j
]);
671 if(WriteMessage(buf
, messageName
, numArgs
, args
)) {
672 post("sendOSC: usage error. write-msg failed: %s", OSC_errorMessage
);
676 SendBuffer(htmsocket
, buf
);
681 void InteractiveMode(void *htmsocket
) {
684 int bundleDepth
= 0; /* At first, we haven't seen "[". */
686 OSC_initBuffer(buf
, SC_BUFFER_SIZE
, bufferForOSCbuf
);
688 while (fgets(mesg
, MAXMESG
, stdin
) != NULL
) {
689 if (mesg
[0] == '\n') {
690 if (bundleDepth
> 0) {
691 /* Ignore blank lines inside a group. */
693 /* blank line => repeat previous send */
694 SendBuffer(htmsocket
, buf
);
699 if (bundleDepth
== 0) {
700 OSC_resetBuffer(buf
);
703 if (mesg
[0] == '[') {
704 OSCTimeTag tt
= ParseTimeTag(mesg
+1);
705 if (OSC_openBundle(buf
, tt
)) {
706 post("Problem opening bundle: %s\n", OSC_errorMessage
);
707 OSC_resetBuffer(buf
);
712 } else if (mesg
[0] == ']' && mesg
[1] == '\n' && mesg
[2] == '\0') {
713 if (bundleDepth
== 0) {
714 post("Unexpected ']': not currently in a bundle.\n");
716 if (OSC_closeBundle(buf
)) {
717 post("Problem closing bundle: %s\n", OSC_errorMessage
);
718 OSC_resetBuffer(buf
);
724 if (bundleDepth
== 0) {
725 SendBuffer(htmsocket
, buf
);
729 ParseInteractiveLine(buf
, mesg
);
730 if (bundleDepth
!= 0) {
731 /* Don't send anything until we close all bundles */
733 SendBuffer(htmsocket
, buf
);
739 OSCTimeTag
ParseTimeTag(char *s
) {
744 while (isspace(*p
)) p
++;
745 if (*p
== '\0') return OSCTT_Immediately();
748 /* Time tag is for some time in the future. It should be a
749 number of seconds as an int or float */
751 newline
= strchr(s
, '\n');
752 if (newline
!= NULL
) *newline
= '\0';
755 while (isspace(*p
)) p
++;
758 if (arg
.type
== STRING_osc
) {
759 post("warning: inscrutable time tag request: %s\n", s
);
760 return OSCTT_Immediately();
761 } else if (arg
.type
== INT_osc
) {
762 return OSCTT_PlusSeconds(OSCTT_CurrentTime(),
763 (float) arg
.datum
.i
);
764 } else if (arg
.type
== FLOAT_osc
) {
765 return OSCTT_PlusSeconds(OSCTT_CurrentTime(), arg
.datum
.f
);
767 error("This can't happen!");
771 if (isdigit(*p
) || (*p
>= 'a' && *p
<='f') || (*p
>= 'A' && *p
<='F')) {
772 /* They specified the 8-byte tag in hex */
774 if (sscanf(p
, "%llx", &tt
) != 1) {
775 post("warning: couldn't parse time tag %s\n", s
);
776 return OSCTT_Immediately();
780 /* tt is a struct of seconds and fractional part,
781 and this machine is little-endian, so sscanf
782 wrote each half of the time tag in the wrong half
786 tt
.seconds
= tt
.fraction
;
793 post("warning: invalid time tag: %s\n", s
);
794 return OSCTT_Immediately();
798 void ParseInteractiveLine(OSCbuf
*buf
, char *mesg
) {
799 char *messageName
, *token
, *p
;
800 typedArg args
[MAX_ARGS
];
804 while (isspace(*p
)) p
++;
805 if (*p
== '\0') return;
809 if (strcmp(messageName
, "play\n") == 0) {
810 /* Special kludge feature to save typing */
813 if (OSC_openBundle(buf
, OSCTT_Immediately())) {
814 post("Problem opening bundle: %s\n", OSC_errorMessage
);
820 WriteMessage(buf
, "/voices/0/tp/timbre_index", 1, &arg
);
822 arg
.type
= FLOAT_osc
;
824 WriteMessage(buf
, "/voices/0/tm/goto", 1, &arg
);
826 if (OSC_closeBundle(buf
)) {
827 post("Problem closing bundle: %s\n", OSC_errorMessage
);
833 while (!isspace(*p
) && *p
!= '\0') p
++;
841 /* flush leading whitespace */
842 while (isspace(*p
)) p
++;
843 if (*p
== '\0') break;
846 /* A string argument: scan for close quotes */
848 args
[thisArg
].type
= STRING_osc
;
849 args
[thisArg
].datum
.s
= p
;
853 post("Unterminated quote mark: ignoring line\n");
862 while (!isspace(*p
) && (*p
!= '\0')) p
++;
867 args
[thisArg
] = ParseToken(token
);
870 if (thisArg
>= MAX_ARGS
) {
871 post("Sorry, your message has more than MAX_ARGS (%d) arguments; ignoring the rest.\n",
877 if (WriteMessage(buf
, messageName
, thisArg
, args
) != 0) {
878 post("Problem sending message: %s\n", OSC_errorMessage
);
882 typedArg
ParseToken(char *token
) {
886 /* It might be an int, a float, or a string */
890 if (isdigit(*p
) || *p
== '.') {
891 while (isdigit(*p
)) p
++;
893 returnVal
.type
= INT_osc
;
894 returnVal
.datum
.i
= atoi(token
);
899 while (isdigit(*p
)) p
++;
901 returnVal
.type
= FLOAT_osc
;
902 returnVal
.datum
.f
= atof(token
);
908 returnVal
.type
= STRING_osc
;
909 returnVal
.datum
.s
= token
;
913 int WriteMessage(OSCbuf
*buf
, char *messageName
, int numArgs
, typedArg
*args
) {
915 const int wmERROR
= -1;
920 printf("WriteMessage: %s ", messageName
);
922 for (j
= 0; j
< numArgs
; j
++) {
923 switch (args
[j
].type
) {
925 printf("%d ", args
[j
].datum
.i
);
929 printf("%f ", args
[j
].datum
.f
);
933 printf("%s ", args
[j
].datum
.s
);
937 error("Unrecognized arg type, (not exiting)");
945 returnVal
= OSC_writeAddress(buf
, messageName
);
947 post("Problem writing address: %s\n", OSC_errorMessage
);
950 /* First figure out the type tags */
951 char typeTags
[MAX_ARGS
+2];
956 for (i
= 0; i
< numArgs
; ++i
) {
957 switch (args
[i
].type
) {
971 error("Unrecognized arg type (not exiting)");
975 typeTags
[i
+1] = '\0';
977 returnVal
= OSC_writeAddressAndTypes(buf
, messageName
, typeTags
);
979 post("Problem writing address: %s\n", OSC_errorMessage
);
983 for (j
= 0; j
< numArgs
; j
++) {
984 switch (args
[j
].type
) {
986 if ((returnVal
= OSC_writeIntArg(buf
, args
[j
].datum
.i
)) != 0) {
992 if ((returnVal
= OSC_writeFloatArg(buf
, args
[j
].datum
.f
)) != 0) {
998 if ((returnVal
= OSC_writeStringArg(buf
, args
[j
].datum
.s
)) != 0) {
1004 error("Unrecognized arg type (not exiting)");
1005 returnVal
= wmERROR
;
1011 void SendBuffer(void *htmsocket
, OSCbuf
*buf
) {
1013 printf("Sending buffer...\n");
1015 if (OSC_isBufferEmpty(buf
)) {
1016 post("SendBuffer() called but buffer empty");
1019 if (!OSC_isBufferDone(buf
)) {
1020 error("SendBuffer() called but buffer not ready!, not exiting");
1023 SendData(htmsocket
, OSC_packetSize(buf
), OSC_getPacket(buf
));
1026 void SendData(void *htmsocket
, int size
, char *data
) {
1027 if (!SendHTMSocket(htmsocket
, size
, data
)) {
1028 post("SendData::SendHTMSocket()failure -- not connected");
1029 CloseHTMSocket(htmsocket
);
1035 /* ----------------------
1040 /* Here are the possible values of the state field: */
1042 #define EMPTY 0 /* Nothing written to packet yet */
1043 #define ONE_MSG_ARGS 1 /* Packet has a single message; gathering arguments */
1044 #define NEED_COUNT 2 /* Just opened a bundle; must write message name or
1045 open another bundle */
1046 #define GET_ARGS 3 /* Getting arguments to a message. If we see a message
1047 name or a bundle open/close then the current message
1049 #define DONE 4 /* All open bundles have been closed, so can't write
1053 #include <winsock2.h>
1058 #include <sys/types.h>
1059 #include <sys/stat.h>
1063 #include <sys/types.h>
1067 #include <netinet/in.h>
1072 char *OSC_errorMessage
;
1074 static int OSC_padString(char *dest
, char *str
);
1075 static int OSC_padStringWithAnExtraStupidComma(char *dest
, char *str
);
1076 static int OSC_WritePadding(char *dest
, int i
);
1077 static int CheckTypeTag(OSCbuf
*buf
, char expectedType
);
1079 void OSC_initBuffer(OSCbuf
*buf
, int size
, char *byteArray
) {
1080 buf
->buffer
= byteArray
;
1082 OSC_resetBuffer(buf
);
1085 void OSC_resetBuffer(OSCbuf
*buf
) {
1086 buf
->bufptr
= buf
->buffer
;
1088 buf
->bundleDepth
= 0;
1089 buf
->prevCounts
[0] = 0;
1090 buf
->gettingFirstUntypedArg
= 0;
1091 buf
->typeStringPtr
= 0;
1094 int OSC_isBufferEmpty(OSCbuf
*buf
) {
1095 return buf
->bufptr
== buf
->buffer
;
1098 int OSC_freeSpaceInBuffer(OSCbuf
*buf
) {
1099 return buf
->size
- (buf
->bufptr
- buf
->buffer
);
1102 int OSC_isBufferDone(OSCbuf
*buf
) {
1103 return (buf
->state
== DONE
|| buf
->state
== ONE_MSG_ARGS
);
1106 char *OSC_getPacket(OSCbuf
*buf
) {
1107 #ifdef ERROR_CHECK_GETPACKET
1108 if (buf
->state
== DONE
|| buf
->state
== ONE_MSG_ARGS
) {
1111 OSC_errorMessage
= "Packet has unterminated bundles";
1119 int OSC_packetSize(OSCbuf
*buf
) {
1120 #ifdef ERROR_CHECK_PACKETSIZE
1121 if (buf
->state
== DONE
|| buf
->state
== ONE_MSG_ARGS
) {
1122 return (buf
->bufptr
- buf
->buffer
);
1124 OSC_errorMessage
= "Packet has unterminated bundles";
1128 return (buf
->bufptr
- buf
->buffer
);
1132 #define CheckOverflow(buf, bytesNeeded) { if ((bytesNeeded) > OSC_freeSpaceInBuffer(buf)) {OSC_errorMessage = "buffer overflow"; return 1;}}
1134 static void PatchMessageSize(OSCbuf
*buf
) {
1136 size
= buf
->bufptr
- ((char *) buf
->thisMsgSize
) - 4;
1137 *(buf
->thisMsgSize
) = htonl(size
);
1140 int OSC_openBundle(OSCbuf
*buf
, OSCTimeTag tt
) {
1141 if (buf
->state
== ONE_MSG_ARGS
) {
1142 OSC_errorMessage
= "Can't open a bundle in a one-message packet";
1146 if (buf
->state
== DONE
) {
1147 OSC_errorMessage
= "This packet is finished; can't open a new bundle";
1151 if (++(buf
->bundleDepth
) >= MAX_BUNDLE_NESTING
) {
1152 OSC_errorMessage
= "Bundles nested too deeply; change MAX_BUNDLE_NESTING in OpenSoundControl.h";
1156 if (CheckTypeTag(buf
, '\0')) return 9;
1158 if (buf
->state
== GET_ARGS
) {
1159 PatchMessageSize(buf
);
1162 if (buf
->state
== EMPTY
) {
1163 /* Need 16 bytes for "#bundle" and time tag */
1164 CheckOverflow(buf
, 16);
1166 /* This bundle is inside another bundle, so we need to leave
1167 a blank size count for the size of this current bundle. */
1168 CheckOverflow(buf
, 20);
1169 *((int4byte
*)buf
->bufptr
) = 0xaaaaaaaa;
1170 buf
->prevCounts
[buf
->bundleDepth
] = (int4byte
*)buf
->bufptr
;
1175 buf
->bufptr
+= OSC_padString(buf
->bufptr
, "#bundle");
1178 *((OSCTimeTag
*) buf
->bufptr
) = tt
;
1180 if (htonl(1) != 1) {
1181 /* Byte swap the 8-byte integer time tag */
1182 int4byte
*intp
= (int4byte
*)buf
->bufptr
;
1183 intp
[0] = htonl(intp
[0]);
1184 intp
[1] = htonl(intp
[1]);
1187 { /* tt is a 64-bit int so we have to swap the two 32-bit words.
1188 (Otherwise tt is a struct of two 32-bit words, and even though
1189 each word was wrong-endian, they were in the right order
1191 int4byte temp
= intp
[0];
1198 buf
->bufptr
+= sizeof(OSCTimeTag
);
1200 buf
->state
= NEED_COUNT
;
1202 buf
->gettingFirstUntypedArg
= 0;
1203 buf
->typeStringPtr
= 0;
1208 int OSC_closeBundle(OSCbuf
*buf
) {
1209 if (buf
->bundleDepth
== 0) {
1210 /* This handles EMPTY, ONE_MSG, ARGS, and DONE */
1211 OSC_errorMessage
= "Can't close bundle; no bundle is open!";
1215 if (CheckTypeTag(buf
, '\0')) return 9;
1217 if (buf
->state
== GET_ARGS
) {
1218 PatchMessageSize(buf
);
1221 if (buf
->bundleDepth
== 1) {
1222 /* Closing the last bundle: No bundle size to patch */
1225 /* Closing a sub-bundle: patch bundle size */
1226 int size
= buf
->bufptr
- ((char *) buf
->prevCounts
[buf
->bundleDepth
]) - 4;
1227 *(buf
->prevCounts
[buf
->bundleDepth
]) = htonl(size
);
1228 buf
->state
= NEED_COUNT
;
1232 buf
->gettingFirstUntypedArg
= 0;
1233 buf
->typeStringPtr
= 0;
1238 int OSC_closeAllBundles(OSCbuf
*buf
) {
1239 if (buf
->bundleDepth
== 0) {
1240 /* This handles EMPTY, ONE_MSG, ARGS, and DONE */
1241 OSC_errorMessage
= "Can't close all bundles; no bundle is open!";
1245 if (CheckTypeTag(buf
, '\0')) return 9;
1247 while (buf
->bundleDepth
> 0) {
1248 OSC_closeBundle(buf
);
1250 buf
->typeStringPtr
= 0;
1254 int OSC_writeAddress(OSCbuf
*buf
, char *name
) {
1255 int4byte paddedLength
;
1257 if (buf
->state
== ONE_MSG_ARGS
) {
1258 OSC_errorMessage
= "This packet is not a bundle, so you can't write another address";
1262 if (buf
->state
== DONE
) {
1263 OSC_errorMessage
= "This packet is finished; can't write another address";
1267 if (CheckTypeTag(buf
, '\0')) return 9;
1269 paddedLength
= OSC_effectiveStringLength(name
);
1271 if (buf
->state
== EMPTY
) {
1272 /* This will be a one-message packet, so no sizes to worry about */
1273 CheckOverflow(buf
, paddedLength
);
1274 buf
->state
= ONE_MSG_ARGS
;
1276 /* GET_ARGS or NEED_COUNT */
1277 CheckOverflow(buf
, 4+paddedLength
);
1278 if (buf
->state
== GET_ARGS
) {
1279 /* Close the old message */
1280 PatchMessageSize(buf
);
1282 buf
->thisMsgSize
= (int4byte
*)buf
->bufptr
;
1283 *(buf
->thisMsgSize
) = 0xbbbbbbbb;
1285 buf
->state
= GET_ARGS
;
1288 /* Now write the name */
1289 buf
->bufptr
+= OSC_padString(buf
->bufptr
, name
);
1290 buf
->typeStringPtr
= 0;
1291 buf
->gettingFirstUntypedArg
= 1;
1296 int OSC_writeAddressAndTypes(OSCbuf
*buf
, char *name
, char *types
) {
1298 int4byte paddedLength
;
1300 if (CheckTypeTag(buf
, '\0')) return 9;
1302 result
= OSC_writeAddress(buf
, name
);
1304 if (result
) return result
;
1306 paddedLength
= OSC_effectiveStringLength(types
);
1308 CheckOverflow(buf
, paddedLength
);
1310 buf
->typeStringPtr
= buf
->bufptr
+ 1; /* skip comma */
1311 buf
->bufptr
+= OSC_padString(buf
->bufptr
, types
);
1313 buf
->gettingFirstUntypedArg
= 0;
1317 static int CheckTypeTag(OSCbuf
*buf
, char expectedType
) {
1318 if (buf
->typeStringPtr
) {
1319 if (*(buf
->typeStringPtr
) != expectedType
) {
1320 if (expectedType
== '\0') {
1322 "According to the type tag I expected more arguments.";
1323 } else if (*(buf
->typeStringPtr
) == '\0') {
1325 "According to the type tag I didn't expect any more arguments.";
1328 "According to the type tag I expected an argument of a different type.";
1329 printf("* Expected %c, string now %s\n", expectedType
, buf
->typeStringPtr
);
1333 ++(buf
->typeStringPtr
);
1339 int OSC_writeFloatArg(OSCbuf
*buf
, float arg
) {
1343 CheckOverflow(buf
, 4);
1345 if (CheckTypeTag(buf
, 'f')) return 9;
1347 /* Pretend arg is a long int so we can use htonl() */
1348 intp
= ((int4byte
*) &arg
);
1349 *((int4byte
*) buf
->bufptr
) = htonl(*intp
);
1353 buf
->gettingFirstUntypedArg
= 0;
1359 int OSC_writeFloatArgs(OSCbuf
*buf
, int numFloats
, float *args
) {
1363 CheckOverflow(buf
, 4 * numFloats
);
1365 /* Pretend args are long ints so we can use htonl() */
1366 intp
= ((int4byte
*) args
);
1368 for (i
= 0; i
< numFloats
; i
++) {
1369 if (CheckTypeTag(buf
, 'f')) return 9;
1370 *((int4byte
*) buf
->bufptr
) = htonl(intp
[i
]);
1374 buf
->gettingFirstUntypedArg
= 0;
1378 int OSC_writeIntArg(OSCbuf
*buf
, int4byte arg
) {
1379 CheckOverflow(buf
, 4);
1380 if (CheckTypeTag(buf
, 'i')) return 9;
1382 *((int4byte
*) buf
->bufptr
) = htonl(arg
);
1385 buf
->gettingFirstUntypedArg
= 0;
1389 int OSC_writeStringArg(OSCbuf
*buf
, char *arg
) {
1392 if (CheckTypeTag(buf
, 's')) return 9;
1394 len
= OSC_effectiveStringLength(arg
);
1396 if (buf
->gettingFirstUntypedArg
&& arg
[0] == ',') {
1397 /* This un-type-tagged message starts with a string
1398 that starts with a comma, so we have to escape it
1399 (with a double comma) so it won't look like a type
1402 CheckOverflow(buf
, len
+4); /* Too conservative */
1404 OSC_padStringWithAnExtraStupidComma(buf
->bufptr
, arg
);
1407 CheckOverflow(buf
, len
);
1408 buf
->bufptr
+= OSC_padString(buf
->bufptr
, arg
);
1411 buf
->gettingFirstUntypedArg
= 0;
1416 /* String utilities */
1418 #define STRING_ALIGN_PAD 4
1419 int OSC_effectiveStringLength(char *string
) {
1420 int len
= strlen(string
) + 1; /* We need space for the null char. */
1422 /* Round up len to next multiple of STRING_ALIGN_PAD to account for alignment padding */
1423 if ((len
% STRING_ALIGN_PAD
) != 0) {
1424 len
+= STRING_ALIGN_PAD
- (len
% STRING_ALIGN_PAD
);
1429 static int OSC_padString(char *dest
, char *str
) {
1432 for (i
= 0; str
[i
] != '\0'; i
++) {
1436 return OSC_WritePadding(dest
, i
);
1439 static int OSC_padStringWithAnExtraStupidComma(char *dest
, char *str
) {
1443 for (i
= 0; str
[i
] != '\0'; i
++) {
1447 return OSC_WritePadding(dest
, i
+1);
1450 static int OSC_WritePadding(char *dest
, int i
) {
1454 for (; (i
% STRING_ALIGN_PAD
) != 0; i
++) {