From 189c0787586602185fea7dcbc3ef37665b75ba45 Mon Sep 17 00:00:00 2001 From: jdl Date: Tue, 6 Aug 2002 12:13:57 +0000 Subject: This commit was generated by cvs2svn to compensate for changes in r75, which included commits to RCS files with non-trunk default branches. svn path=/trunk/externals/OSCx/; revision=76 --- send+dump/dumpOSC.c | 716 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 716 insertions(+) create mode 100644 send+dump/dumpOSC.c (limited to 'send+dump/dumpOSC.c') diff --git a/send+dump/dumpOSC.c b/send+dump/dumpOSC.c new file mode 100644 index 0000000..143a994 --- /dev/null +++ b/send+dump/dumpOSC.c @@ -0,0 +1,716 @@ +/* +Copyright (c) 1992,1993,1994,1995,1996,1997,2000. +The Regents of the University of California (Regents). +All Rights Reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for educational, research, and not-for-profit purposes, without +fee and without a signed licensing agreement, is hereby granted, provided that +the above copyright notice, this paragraph and the following two paragraphs +appear in all copies, modifications, and distributions. Contact The Office of +Technology Licensing, UC Berkeley, 2150 Shattuck Avenue, Suite 510, Berkeley, +CA 94720-1620, (510) 643-7201, for commercial licensing opportunities. + +Written by Matt Wright and Adrian Freed, The Center for New Music and Audio +Technologies, University of California, Berkeley. + + IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, + SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, + ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF + REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING + DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". + REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, + ENHANCEMENTS, OR MODIFICATIONS. +*/ + + /* + + dumpOSC.c + server that displays OpenSoundControl messages sent to it + for debugging client udp and UNIX protocol + + by Matt Wright, 6/3/97 + modified from dumpSC.c, by Matt Wright and Adrian Freed + + version 0.2: Added "-silent" option a.k.a. "-quiet" + + version 0.3: Incorporated patches from Nicola Bernardini to make + things Linux-friendly. Also added ntohl() in the right places + to support little-endian architectures. + + + + compile: + cc -o dumpOSC dumpOSC.c + + to-do: + + More robustness in saying exactly what's wrong with ill-formed + messages. (If they don't make sense, show exactly what was + received.) + + Time-based features: print time-received for each packet + + Clean up to separate OSC parsing code from socket/select stuff + +*/ + + +#if defined(__sgi) || defined(__linux) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef NEED_SCHEDCTL_AND_LOCK +#include +#include +#endif + + +char *htm_error_string; +typedef int Boolean; +typedef void *OBJ; + +typedef struct ClientAddressStruct { + struct sockaddr_in cl_addr; + int clilen; + int sockfd; +} *ClientAddr; + +Boolean ShowBytes = FALSE; +Boolean Silent = FALSE; + +/* Declarations */ +static int unixinitudp(int chan); +static int initudp(int chan); +static void closeudp(int sockfd); +Boolean ClientReply(int packetsize, void *packet, int socketfd, + void *clientaddresspointer, int clientaddressbufferlength); +void sgi_CleanExit(void); +Boolean sgi_HaveToQuit(void); +int RegisterPollingDevice(int fd, void (*callbackfunction)(int , void *), void *dummy); +static void catch_sigint(); +static int Synthmessage(char *m, int n, void *clientdesc, int clientdesclength, int fd) ; +void ParseOSCPacket(char *buf, int n, ClientAddr returnAddr); +static void Smessage(char *address, void *v, int n, ClientAddr returnAddr); +static void PrintTypeTaggedArgs(void *v, int n); +static void PrintHeuristicallyTypeGuessedArgs(void *v, int n, int skipComma); +char *DataAfterAlignedString(char *string, char *boundary) ; +Boolean IsNiceString(char *string, char *boundary) ; +void complain(char *s, ...); + + +#define UNIXDG_PATH "/tmp/htm" +#define UNIXDG_TMP "/tmp/htm.XXXXXX" +static int unixinitudp(int chan) +{ + struct sockaddr_un serv_addr; + int sockfd; + + if((sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) + return sockfd; + + bzero((char *)&serv_addr, sizeof(serv_addr)); + serv_addr.sun_family = AF_UNIX; + strcpy(serv_addr.sun_path, UNIXDG_PATH); + sprintf(serv_addr.sun_path+strlen(serv_addr.sun_path), "%d", chan); + unlink(serv_addr.sun_path); + if(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr.sun_family)+strlen(serv_addr.sun_path)) < 0) + { + perror("unable to bind\n"); + return -1; + } + + fcntl(sockfd, F_SETFL, FNDELAY); + return sockfd; +} + +static int initudp(int chan) +{ + struct sockaddr_in serv_addr; + int sockfd; + + if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + return sockfd; + bzero((char *)&serv_addr, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); + serv_addr.sin_port = htons(chan); + + if(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) + { + perror("unable to bind\n"); + return -1; + } + + fcntl(sockfd, F_SETFL, FNDELAY); + return sockfd; +} + +static void closeudp(int sockfd) { + close(sockfd); +} + +static Boolean catchupflag=FALSE; +Boolean ClientReply(int packetsize, void *packet, int socketfd, + void *clientaddresspointer, int clientaddressbufferlength) +{ + if(!clientaddresspointer) return FALSE; + catchupflag= TRUE; + return packetsize==sendto(socketfd, packet, packetsize, 0, clientaddresspointer, clientaddressbufferlength); +} + +static Boolean exitflag= FALSE; +void sgi_CleanExit(void) { + exitflag = TRUE; +} + +Boolean sgi_HaveToQuit(void) { + return exitflag; +} + + +/* file descriptor poll table */ +static int npolldevs =0; +typedef struct polldev +{ + int fd; + void (*callbackfunction)(int , void *); + void *dummy; +} polldev; +#define TABMAX 8 +static polldev polldevs[TABMAX]; + + +/* Register a device (referred to by a file descriptor that the caller + should have already successfully obtained from a system call) to be + polled as real-time constraints allowed. + + When a select(2) call indicates activity on the file descriptor, the + callback function is called with the file descripter as first + argument and the given dummy argument (presumably a pointer to the + instance variables associated with the device). +*/ +int RegisterPollingDevice(int fd, void (*callbackfunction)(int , void *), void *dummy) +{ + if(npolldevscl_addr.sin_addr.s_addr; + printf("Client address %p:\n", CA); + printf(" clilen %d, sockfd %d\n", CA->clilen, CA->sockfd); + printf(" sin_family %d, sin_port %d\n", CA->cl_addr.sin_family, + CA->cl_addr.sin_port); + printf(" address: (%x) %s\n", addr, inet_ntoa(CA->cl_addr.sin_addr)); + + printf(" sin_zero = \"%c%c%c%c%c%c%c%c\"\n", + CA->cl_addr.sin_zero[0], + CA->cl_addr.sin_zero[1], + CA->cl_addr.sin_zero[2], + CA->cl_addr.sin_zero[3], + CA->cl_addr.sin_zero[4], + CA->cl_addr.sin_zero[5], + CA->cl_addr.sin_zero[6], + CA->cl_addr.sin_zero[7]); + + printf("\n"); +} + + +void ParseOSCPacket(char *buf, int n, ClientAddr returnAddr) { + int size, messageLen, i; + char *messageName; + char *args; + +#ifdef PRINTADDRS + PrintClientAddr(returnAddr); +#endif + + + if ((n%4) != 0) { + complain("SynthControl packet size (%d) not a multiple of 4 bytes: dropping", + n); + return; + } + + if ((n >= 8) && (strncmp(buf, "#bundle", 8) == 0)) { + /* This is a bundle message. */ + + if (n < 16) { + complain("Bundle message too small (%d bytes) for time tag", n); + return; + } + + /* Print the time tag */ + printf("[ %lx%08lx\n", ntohl(*((unsigned long *)(buf+8))), + ntohl(*((unsigned long *)(buf+12)))); + /* Note: if we wanted to actually use the time tag as a little-endian + 64-bit int, we'd have to word-swap the two 32-bit halves of it */ + + i = 16; /* Skip "#group\0" and time tag */ + while(i n) { + complain("Bad size count %d in bundle (only %d bytes left in entire bundle)", + size, n-i-4); + return; + } + + /* Recursively handle element of bundle */ + ParseOSCPacket(buf+i+4, size, returnAddr); + i += 4 + size; + } + if (i != n) { + complain("This can't happen"); + } + printf("]\n"); + } else { + /* This is not a bundle message */ + + messageName = buf; + args = DataAfterAlignedString(messageName, buf+n); + if (args == 0) { + complain("Bad message name string: %s\nDropping entire message.\n", + htm_error_string); + return; + } + messageLen = args-messageName; + Smessage(messageName, (void *)args, n-messageLen, returnAddr); + } +} + +#define SMALLEST_POSITIVE_FLOAT 0.000001f + +static void Smessage(char *address, void *v, int n, ClientAddr returnAddr) { + char *chars = v; + + printf("%s ", address); + + if (n != 0) { + if (chars[0] == ',') { + if (chars[1] != ',') { + /* This message begins with a type-tag string */ + PrintTypeTaggedArgs(v, n); + } else { + /* Double comma means an escaped real comma, not a type string */ + PrintHeuristicallyTypeGuessedArgs(v, n, 1); + } + } else { + PrintHeuristicallyTypeGuessedArgs(v, n, 0); + } + } + + printf("\n"); + fflush(stdout); /* Added for Sami 5/21/98 */ +} + +static void PrintTypeTaggedArgs(void *v, int n) { + char *typeTags, *thisType; + char *p; + + typeTags = v; + + if (!IsNiceString(typeTags, typeTags+n)) { + /* No null-termination, so maybe it wasn't a type tag + string after all */ + PrintHeuristicallyTypeGuessedArgs(v, n, 0); + return; + } + + p = DataAfterAlignedString(typeTags, typeTags+n); + + + for (thisType = typeTags + 1; *thisType != 0; ++thisType) { + switch (*thisType) { + case 'i': case 'r': case 'm': case 'c': + printf("%d ", ntohl(*((int *) p))); + p += 4; + break; + + case 'f': { + int i = ntohl(*((int *) p)); + float *floatp = ((float *) (&i)); + printf("%f ", *floatp); + p += 4; + } + break; + + case 'h': case 't': + printf("[A 64-bit int] "); + p += 8; + break; + + case 'd': + printf("[A 64-bit float] "); + p += 8; + break; + + case 's': case 'S': + if (!IsNiceString(p, typeTags+n)) { + printf("Type tag said this arg is a string but it's not!\n"); + return; + } else { + printf("\"%s\" ", p); + p = DataAfterAlignedString(p, typeTags+n); + } + break; + + case 'T': printf("[True] "); break; + case 'F': printf("[False] "); break; + case 'N': printf("[Nil]"); break; + case 'I': printf("[Infinitum]"); break; + + default: + printf("[Unrecognized type tag %c]", *thisType); + return; + } + } +} + +static void PrintHeuristicallyTypeGuessedArgs(void *v, int n, int skipComma) { + int i, thisi; + float thisf; + int *ints; + char *chars; + char *string, *nextString; + + + /* Go through the arguments 32 bits at a time */ + ints = v; + chars = v; + + for (i = 0; i= -1000 && thisi <= 1000000) { + printf("%d ", thisi); + i++; + } else if (thisf >= -1000.f && thisf <= 1000000.f && + (thisf <=0.0f || thisf >= SMALLEST_POSITIVE_FLOAT)) { + printf("%f ", thisf); + i++; + } else if (IsNiceString(string, chars+n)) { + nextString = DataAfterAlignedString(string, chars+n); + printf("\"%s\" ", (i == 0 && skipComma) ? string +1 : string); + i += (nextString-string) / 4; + } else { + printf("0x%x ", ints[i]); + i++; + } + } +} + + +#define STRING_ALIGN_PAD 4 + +char *DataAfterAlignedString(char *string, char *boundary) +{ + /* The argument is a block of data beginning with a string. The + string has (presumably) been padded with extra null characters + so that the overall length is a multiple of STRING_ALIGN_PAD + bytes. Return a pointer to the next byte after the null + byte(s). The boundary argument points to the character after + the last valid character in the buffer---if the string hasn't + ended by there, something's wrong. + + If the data looks wrong, return 0, and set htm_error_string */ + + int i; + + if ((boundary - string) %4 != 0) { + fprintf(stderr, "Internal error: DataAfterAlignedString: bad boundary\n"); + return 0; + } + + for (i = 0; string[i] != '\0'; i++) { + if (string + i >= boundary) { + htm_error_string = "DataAfterAlignedString: Unreasonably long string"; + return 0; + } + } + + /* Now string[i] is the first null character */ + i++; + + for (; (i % STRING_ALIGN_PAD) != 0; i++) { + if (string + i >= boundary) { + htm_error_string = "DataAfterAlignedString: Unreasonably long string"; + return 0; + } + if (string[i] != '\0') { + htm_error_string = "DataAfterAlignedString: Incorrectly padded string."; + return 0; + } + } + + return string+i; +} + +Boolean IsNiceString(char *string, char *boundary) +{ + /* Arguments same as DataAfterAlignedString(). Is the given "string" + really a string? I.e., is it a sequence of isprint() characters + terminated with 1-4 null characters to align on a 4-byte boundary? */ + + int i; + + if ((boundary - string) %4 != 0) { + fprintf(stderr, "Internal error: IsNiceString: bad boundary\n"); + return 0; + } + + for (i = 0; string[i] != '\0'; i++) { + if (!isprint(string[i])) return FALSE; + if (string + i >= boundary) return FALSE; + } + + /* If we made it this far, it's a null-terminated sequence of printing characters + in the given boundary. Now we just make sure it's null padded... */ + + /* Now string[i] is the first null character */ + i++; + for (; (i % STRING_ALIGN_PAD) != 0; i++) { + if (string[i] != '\0') return FALSE; + } + + return TRUE; +} + + + + + + + +#define MAXMESG 32768 +static char mbuf[MAXMESG]; + +int main(int argc, char **argv) { + int udp_port; /* port to receive parameter updates from */ + + struct sockaddr_in cl_addr; + int clilen,maxclilen=sizeof(cl_addr); + struct sockaddr_un ucl_addr; + int uclilen,umaxclilen=sizeof(ucl_addr); + int i,n; + + + clilen = maxclilen; + uclilen = umaxclilen; + + udp_port = -1; + for (i=1; i < argc; ++i) { + if (strcmp(argv[i], "-showbytes") == 0) { + ShowBytes = TRUE; + } else if (strcmp(argv[i], "-silent") == 0 || + strcmp(argv[i], "-quiet") == 0) { + Silent = TRUE; + } else if (udp_port != -1) { + goto usageError; + } else { + udp_port = atoi(argv[i]); + if (udp_port == 0) { + goto usageError; + } + } + } + + if (udp_port == -1) { + usageError: + fprintf(stderr, "Usage\n\tdumpOSC portno [-showbytes] [-quiet]\n\t(responds to udp and UNIX packets on that port no)\n"); + exit(1); + } + + + n = recvfrom(0, mbuf, MAXMESG, 0, &cl_addr, &clilen); + if(n>0) + { + sockfd = 0; + udp_port = -1; + Synthmessage(mbuf, n, &cl_addr, clilen,sockfd) ; + } + else + { sockfd=initudp(udp_port); + usockfd=unixinitudp(udp_port); + } + + if (!Silent) { + printf("dumpOSC version 0.2 (6/18/97 Matt Wright). Unix/UDP Port %d \n", udp_port); + printf("Copyright (c) 1992,1996,1997 Regents of the University of California.\n"); + } + if(sockfd>=0 && usockfd>=0) + { + fd_set read_fds, write_fds; + int nfds; +#define max(a,b) (((a) > (b)) ? (a) : (b)) + nfds = max(sockfd, usockfd)+ 1; + { + int j; + for(j=0;j=nfds) + { + nfds = polldevs[j].fd+1; +/* +printf("polldev %d\n", polldevs[j].fd); +*/ + } + } +/* + printf("nfds %d\n", nfds); +*/ + caught_sigint = 0; + sigset(SIGINT, catch_sigint); /* set sig handler */ + + while(!caught_sigint) + { + + int r; + + back: + + FD_ZERO(&read_fds); /* clear read_fds */ + FD_ZERO(&write_fds); /* clear write_fds */ + FD_SET(sockfd, &read_fds); + FD_SET(usockfd, &read_fds); + { + int j; + + for(j=0;j0) + { + int r; + /* printf("received UDP packet of length %d\n", n); */ + r = Synthmessage(mbuf, n, &cl_addr, clilen, sockfd) ; + + if( sgi_HaveToQuit()) goto out; + if(r>0) goto back; + clilen = maxclilen; + } + } + if(FD_ISSET(usockfd, &read_fds)) + { + uclilen = umaxclilen; + while( (n = recvfrom(usockfd, mbuf, MAXMESG, 0, &ucl_addr, &uclilen)) >0) + { + int r; + /* printf("received UNIX packet of length %d\n", n); */ + + r=Synthmessage(mbuf, n, &ucl_addr, uclilen,usockfd) ; + + if( sgi_HaveToQuit()) goto out; + if(r>0) goto back; + uclilen = umaxclilen; + } + } + } /* End of while(!caught_sigint) */ + + +out: ; + } + else + perror("initudp"); + + return 0; +} + + +#include +void complain(char *s, ...) { + va_list ap; + va_start(ap, s); + fprintf(stderr, "*** ERROR: "); + vfprintf(stderr, s, ap); + fprintf(stderr, "\n"); + va_end(ap); +} + +#endif /* __sgi or LINUX */ -- cgit v1.2.1