1 /*
2  * oscdump - Receive and dump OpenSound Control messages.
3  *
4  * Copyright (C) 2008 Kentaro Fukuchi <kentaro@fukuchi.org>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public License
8  * as published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19  * 02110-1301 USA.
20  *
21  */
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <errno.h>
28 #include <signal.h>
29 #include <config.h>
30 #include <lo/lo.h>
31 
32 int done = 0;
33 int bundled = 0;
34 lo_timetag tt_now;
35 lo_timetag tt_bundle;
36 FILE *fout = NULL;
37 int dump_raw = 0;
38 
usage(void)39 void usage(void)
40 {
41     printf("oscdump version %s\n"
42            "Copyright (C) 2008 Kentaro Fukuchi\n\n"
43            "Usage: oscdump [-L] [-r] <port>\n"
44            "or     oscdump [-L] [-r] <url>\n"
45            "Receive OpenSound Control messages and dump to standard output.\n\n"
46            "Description\n"
47            "-L      : specifies line buffering even if stdout is a pipe or file\n"
48            "-r      : specifies to dump raw message data to stdout (binary)\n"
49            "port    : specifies the listening port number.\n"
50            "url     : specifies the server parameters using a liblo URL.\n"
51            "          e.g. UDP        \"osc.udp://:9000\"\n"
52            "               Multicast  \"osc.udp://224.0.1.9:9000\"\n"
53            "               TCP        \"osc.tcp://:9000\"\n\n", VERSION);
54 }
55 
bundleStartHandler(lo_timetag tt,void * user_data)56 int bundleStartHandler(lo_timetag tt, void *user_data)
57 {
58     if (tt.sec == LO_TT_IMMEDIATE.sec &&
59         tt.frac == LO_TT_IMMEDIATE.frac)
60     {
61         lo_timetag_now(&tt_now);
62         tt_bundle.sec = tt_now.sec;
63         tt_bundle.frac = tt_now.frac;
64     }
65     else {
66         tt_bundle.sec = tt.sec;
67         tt_bundle.frac = tt.frac;
68     }
69     bundled = 1;
70     return 0;
71 }
72 
bundleEndHandler(void * user_data)73 int bundleEndHandler(void *user_data)
74 {
75     bundled = 0;
76     return 0;
77 }
78 
errorHandler(int num,const char * msg,const char * where)79 void errorHandler(int num, const char *msg, const char *where)
80 {
81     fprintf(stderr, "liblo server error %d in path %s: %s\n", num, where, msg);
82 }
83 
messageHandler(const char * path,const char * types,lo_arg ** argv,int argc,lo_message msg,void * user_data)84 int messageHandler(const char *path, const char *types, lo_arg ** argv,
85                    int argc, lo_message msg, void *user_data)
86 {
87     int i;
88 
89     if (bundled) {
90         printf("%08x.%08x %s %s", tt_bundle.sec, tt_bundle.frac, path, types);
91     }
92     else {
93         lo_timetag tt = lo_message_get_timestamp(msg);
94         if (tt.sec == LO_TT_IMMEDIATE.sec &&
95             tt.frac == LO_TT_IMMEDIATE.frac)
96         {
97             lo_timetag_now(&tt_now);
98             printf("%08x.%08x %s %s", tt_now.sec, tt_now.frac, path, types);
99         }
100         else
101             printf("%08x.%08x %s %s", tt.sec, tt.frac, path, types);
102     }
103 
104     for (i = 0; i < argc; i++) {
105         printf(" ");
106         lo_arg_pp((lo_type) types[i], argv[i]);
107     }
108     printf("\n");
109 
110     return 0;
111 }
112 
rawMessageHandler(const char * path,const char * types,lo_arg ** argv,int argc,lo_message msg,void * user_data)113 int rawMessageHandler(const char *path, const char *types, lo_arg ** argv,
114                    int argc, lo_message msg, void *user_data)
115 {
116    size_t size;
117    void *msg_ptr;
118 
119    if(!fout){return 1;}
120 
121    msg_ptr=lo_message_serialise(msg, path, NULL, &size);
122    if(!msg_ptr){return 1;}
123 
124    fwrite(msg_ptr, 1, size, fout);
125    fflush(fout);
126    free(msg_ptr);
127 
128    return 0;
129 }
130 
ctrlc(int sig)131 void ctrlc(int sig)
132 {
133     done = 1;
134 }
135 
main(int argc,char ** argv)136 int main(int argc, char **argv)
137 {
138     lo_server server;
139     char *port=0, *group=0;
140     int i=1;
141 
142 #ifdef WIN32
143 #ifdef HAVE_SETVBUF
144     setvbuf(stdout, 0, _IONBF, BUFSIZ);
145 #endif
146 #endif
147 
148     if (argc > i && argv[i][0]=='-') {
149 #ifdef HAVE_SETVBUF
150         if (argv[i][1]=='L') { // line buffering
151             setvbuf(stdout, 0, _IOLBF, BUFSIZ);
152             i++;
153         }
154         else
155 #endif
156         if (argv[i][1]=='h') {
157             usage();
158             exit(0);
159         }
160         else if (argv[i][1]=='r') {
161             dump_raw = 1;
162             i++;
163         }
164         else {
165             fprintf(stderr, "Unknown option `%s'\n", argv[i]);
166             exit(1);
167         }
168     }
169 
170     if (argc > i) {
171         port = argv[i];
172         i++;
173     } else {
174         usage();
175         exit(1);
176     }
177 
178     if (argc > i) {
179         group = argv[i];
180     }
181 
182     if (group) {
183         server = lo_server_new_multicast(group, port, errorHandler);
184     } else if (isdigit(port[0])) {
185         server = lo_server_new(port, errorHandler);
186     } else {
187         server = lo_server_new_from_url(port, errorHandler);
188     }
189 
190     if (server == NULL) {
191         fprintf(stderr, "Could not start a server with port %s", port);
192         if (group)
193             fprintf(stderr, ", multicast group %s\n", group);
194         else
195             fprintf(stderr, "\n");
196         exit(1);
197     }
198 
199     if(!dump_raw)
200     {
201         lo_server_add_method(server, NULL, NULL, messageHandler, NULL);
202     }
203     else
204     {
205         fout = stdout;
206         lo_server_add_method(server, NULL, NULL, rawMessageHandler, NULL);
207     }
208     lo_server_add_bundle_handlers(server, bundleStartHandler, bundleEndHandler,
209                                   NULL);
210 
211     signal(SIGINT, ctrlc);
212 
213     while (!done) {
214         lo_server_recv_noblock(server, 1);
215     }
216 
217     return 0;
218 }
219