annotate src/liblo-0.26/src/send.c @ 33:879bdc878826

Ah, we've already done this. Merge, taking everything from the branch with the older commits.
author Chris Cannam
date Fri, 04 Jul 2014 10:37:37 +0100
parents e13257ea84a4
children
rev   line source
Chris@4 1 /*
Chris@4 2 * Copyright (C) 2004 Steve Harris
Chris@4 3 *
Chris@4 4 * This program is free software; you can redistribute it and/or modify
Chris@4 5 * it under the terms of the GNU Lesser General Public License as
Chris@4 6 * published by the Free Software Foundation; either version 2.1 of the
Chris@4 7 * License, or (at your option) any later version.
Chris@4 8 *
Chris@4 9 * This program is distributed in the hope that it will be useful,
Chris@4 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Chris@4 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Chris@4 12 * GNU Lesser General Public License for more details.
Chris@4 13 *
Chris@4 14 * $Id$
Chris@4 15 */
Chris@4 16
Chris@4 17 #ifdef HAVE_CONFIG_H
Chris@4 18 #include "config.h"
Chris@4 19 #endif
Chris@4 20
Chris@4 21 #include <stdarg.h>
Chris@4 22 #include <stdlib.h>
Chris@4 23 #include <stdio.h>
Chris@4 24 #include <string.h>
Chris@4 25 #include <errno.h>
Chris@4 26 #include <sys/types.h>
Chris@4 27
Chris@4 28 #ifdef _MSC_VER
Chris@4 29 #include <io.h>
Chris@4 30 #else
Chris@4 31 #include <unistd.h>
Chris@4 32 #endif
Chris@4 33
Chris@4 34 #ifdef WIN32
Chris@4 35 #include <winsock2.h>
Chris@4 36 #include <ws2tcpip.h>
Chris@4 37 #else
Chris@4 38 #include <netdb.h>
Chris@4 39 #include <sys/socket.h>
Chris@4 40 #include <sys/un.h>
Chris@4 41 #endif
Chris@4 42
Chris@4 43 #include "lo_types_internal.h"
Chris@4 44 #include "lo/lo.h"
Chris@4 45
Chris@4 46 #ifndef MSG_NOSIGNAL
Chris@4 47 #define MSG_NOSIGNAL 0
Chris@4 48 #endif
Chris@4 49
Chris@4 50 #ifdef WIN32
Chris@4 51 int initWSock();
Chris@4 52 #endif
Chris@4 53
Chris@4 54 #ifdef WIN32
Chris@4 55 #define geterror() WSAGetLastError()
Chris@4 56 #else
Chris@4 57 #define geterror() errno
Chris@4 58 #endif
Chris@4 59
Chris@4 60 static int resolve_address(lo_address a);
Chris@4 61 static int create_socket(lo_address a);
Chris@4 62 static int send_data(lo_address a, lo_server from, char *data, const size_t data_len);
Chris@4 63
Chris@4 64 // message.c
Chris@4 65 int lo_message_add_varargs_internal(lo_message m, const char *types, va_list ap,
Chris@4 66 const char *file, int line);
Chris@4 67
Chris@4 68
Chris@4 69
Chris@4 70 /* Don't call lo_send_internal directly, use lo_send, a macro wrapping this
Chris@4 71 * function with appropriate values for file and line */
Chris@4 72
Chris@4 73 #ifdef __GNUC__
Chris@4 74 int lo_send_internal(lo_address t, const char *file, const int line,
Chris@4 75 const char *path, const char *types, ...)
Chris@4 76 #else
Chris@4 77 int lo_send(lo_address t, const char *path, const char *types, ...)
Chris@4 78 #endif
Chris@4 79 {
Chris@4 80 va_list ap;
Chris@4 81 int ret;
Chris@4 82 #ifndef __GNUC__
Chris@4 83 const char *file = "";
Chris@4 84 int line = 0;
Chris@4 85 #endif
Chris@4 86
Chris@4 87 lo_message msg = lo_message_new();
Chris@4 88
Chris@4 89 t->errnum = 0;
Chris@4 90 t->errstr = NULL;
Chris@4 91
Chris@4 92 va_start(ap, types);
Chris@4 93 ret = lo_message_add_varargs_internal(msg, types, ap, file, line);
Chris@4 94
Chris@4 95 if (ret) {
Chris@4 96 lo_message_free(msg);
Chris@4 97 t->errnum = ret;
Chris@4 98 if (ret == -1) t->errstr = "unknown type";
Chris@4 99 else t->errstr = "bad format/args";
Chris@4 100 return ret;
Chris@4 101 }
Chris@4 102
Chris@4 103 ret = lo_send_message(t, path, msg);
Chris@4 104 lo_message_free(msg);
Chris@4 105
Chris@4 106 return ret;
Chris@4 107 }
Chris@4 108
Chris@4 109
Chris@4 110 /* Don't call lo_send_timestamped_internal directly, use lo_send_timestamped, a
Chris@4 111 * macro wrapping this function with appropriate values for file and line */
Chris@4 112
Chris@4 113 #ifdef __GNUC__
Chris@4 114 int lo_send_timestamped_internal(lo_address t, const char *file,
Chris@4 115 const int line, lo_timetag ts,
Chris@4 116 const char *path, const char *types, ...)
Chris@4 117 #else
Chris@4 118 int lo_send_timestamped(lo_address t, lo_timetag ts,
Chris@4 119 const char *path, const char *types, ...)
Chris@4 120 #endif
Chris@4 121 {
Chris@4 122 va_list ap;
Chris@4 123 int ret;
Chris@4 124
Chris@4 125 lo_message msg = lo_message_new();
Chris@4 126 lo_bundle b = lo_bundle_new(ts);
Chris@4 127
Chris@4 128 #ifndef __GNUC__
Chris@4 129 const char *file = "";
Chris@4 130 int line = 0;
Chris@4 131 #endif
Chris@4 132
Chris@4 133 t->errnum = 0;
Chris@4 134 t->errstr = NULL;
Chris@4 135
Chris@4 136 va_start(ap, types);
Chris@4 137 ret = lo_message_add_varargs_internal(msg, types, ap, file, line);
Chris@4 138
Chris@4 139 if (t->errnum) {
Chris@4 140 lo_message_free(msg);
Chris@4 141 return t->errnum;
Chris@4 142 }
Chris@4 143
Chris@4 144 lo_bundle_add_message(b, path, msg);
Chris@4 145 ret = lo_send_bundle(t, b);
Chris@4 146 lo_message_free(msg);
Chris@4 147 lo_bundle_free(b);
Chris@4 148
Chris@4 149 return ret;
Chris@4 150 }
Chris@4 151
Chris@4 152 /* Don't call lo_send_from_internal directly, use macros wrapping this
Chris@4 153 * function with appropriate values for file and line */
Chris@4 154
Chris@4 155 #ifdef __GNUC__
Chris@4 156 int lo_send_from_internal(lo_address to, lo_server from, const char *file,
Chris@4 157 const int line, lo_timetag ts,
Chris@4 158 const char *path, const char *types, ...)
Chris@4 159 #else
Chris@4 160 int lo_send_from(lo_address to, lo_server from, lo_timetag ts,
Chris@4 161 const char *path, const char *types, ...)
Chris@4 162 #endif
Chris@4 163 {
Chris@4 164 lo_bundle b = NULL;
Chris@4 165 va_list ap;
Chris@4 166 int ret;
Chris@4 167
Chris@4 168 #ifndef __GNUC__
Chris@4 169 const char *file = "";
Chris@4 170 int line = 0;
Chris@4 171 #endif
Chris@4 172
Chris@4 173 lo_message msg = lo_message_new();
Chris@4 174 if (ts.sec!=LO_TT_IMMEDIATE.sec || ts.frac!=LO_TT_IMMEDIATE.frac)
Chris@4 175 b = lo_bundle_new(ts);
Chris@4 176
Chris@4 177 // Clear any previous errors
Chris@4 178 to->errnum = 0;
Chris@4 179 to->errstr = NULL;
Chris@4 180
Chris@4 181 va_start(ap, types);
Chris@4 182 ret = lo_message_add_varargs_internal(msg, types, ap, file, line);
Chris@4 183
Chris@4 184 if (to->errnum) {
Chris@4 185 if (b) lo_bundle_free(b);
Chris@4 186 lo_message_free(msg);
Chris@4 187 return to->errnum;
Chris@4 188 }
Chris@4 189
Chris@4 190 if (b) {
Chris@4 191 lo_bundle_add_message(b, path, msg);
Chris@4 192 ret = lo_send_bundle_from(to, from, b);
Chris@4 193 } else {
Chris@4 194 ret = lo_send_message_from(to, from, path, msg);
Chris@4 195 }
Chris@4 196
Chris@4 197 // Free-up memory
Chris@4 198 lo_message_free(msg);
Chris@4 199 if (b) lo_bundle_free(b);
Chris@4 200
Chris@4 201 return ret;
Chris@4 202 }
Chris@4 203
Chris@4 204
Chris@4 205 #if 0
Chris@4 206
Chris@4 207 This (incomplete) function converts from printf-style formats to OSC typetags,
Chris@4 208 but I think its dangerous and mislieading so its not available at the moment.
Chris@4 209
Chris@4 210 static char *format_to_types(const char *format);
Chris@4 211
Chris@4 212 static char *format_to_types(const char *format)
Chris@4 213 {
Chris@4 214 const char *ptr;
Chris@4 215 char *types = malloc(sizeof(format) + 1);
Chris@4 216 char *out = types;
Chris@4 217 int inspec = 0;
Chris@4 218 int width = 0;
Chris@4 219 int number = 0;
Chris@4 220
Chris@4 221 if (!format) {
Chris@4 222 return NULL;
Chris@4 223 }
Chris@4 224
Chris@4 225 for (ptr = format; *ptr; ptr++) {
Chris@4 226 if (inspec) {
Chris@4 227 if (*ptr == 'l') {
Chris@4 228 width++;
Chris@4 229 } else if (*ptr >= '0' && *ptr <= '9') {
Chris@4 230 number *= 10;
Chris@4 231 number += *ptr - '0';
Chris@4 232 } else if (*ptr == 'd') {
Chris@4 233 if (width < 2 && number < 64) {
Chris@4 234 *out++ = LO_INT32;
Chris@4 235 } else {
Chris@4 236 *out++ = LO_INT64;
Chris@4 237 }
Chris@4 238 } else if (*ptr == 'f') {
Chris@4 239 if (width < 2 && number < 64) {
Chris@4 240 *out++ = LO_FLOAT;
Chris@4 241 } else {
Chris@4 242 *out++ = LO_DOUBLE;
Chris@4 243 }
Chris@4 244 } else if (*ptr == '%') {
Chris@4 245 fprintf(stderr, "liblo warning, unexpected '%%' in format\n");
Chris@4 246 inspec = 1;
Chris@4 247 width = 0;
Chris@4 248 number = 0;
Chris@4 249 } else {
Chris@4 250 fprintf(stderr, "liblo warning, unrecognised character '%c' "
Chris@4 251 "in format\n", *ptr);
Chris@4 252 }
Chris@4 253 } else {
Chris@4 254 if (*ptr == '%') {
Chris@4 255 inspec = 1;
Chris@4 256 width = 0;
Chris@4 257 number = 0;
Chris@4 258 } else if (*ptr == LO_TRUE || *ptr == LO_FALSE || *ptr == LO_NIL ||
Chris@4 259 *ptr == LO_INFINITUM) {
Chris@4 260 *out++ = *ptr;
Chris@4 261 } else {
Chris@4 262 fprintf(stderr, "liblo warning, unrecognised character '%c' "
Chris@4 263 "in format\n", *ptr);
Chris@4 264 }
Chris@4 265 }
Chris@4 266 }
Chris@4 267 *out++ = '\0';
Chris@4 268
Chris@4 269 return types;
Chris@4 270 }
Chris@4 271
Chris@4 272 #endif
Chris@4 273
Chris@4 274
Chris@4 275 static int resolve_address(lo_address a)
Chris@4 276 {
Chris@4 277 int ret;
Chris@4 278
Chris@4 279 if (a->protocol == LO_UDP || a->protocol == LO_TCP) {
Chris@4 280 struct addrinfo *ai;
Chris@4 281 struct addrinfo hints;
Chris@4 282
Chris@4 283 memset(&hints, 0, sizeof(hints));
Chris@4 284 #ifdef ENABLE_IPV6
Chris@4 285 hints.ai_family = PF_UNSPEC;
Chris@4 286 #else
Chris@4 287 hints.ai_family = PF_INET;
Chris@4 288 #endif
Chris@4 289 hints.ai_socktype = a->protocol == LO_UDP ? SOCK_DGRAM : SOCK_STREAM;
Chris@4 290
Chris@4 291 if ((ret = getaddrinfo(a->host, a->port, &hints, &ai))) {
Chris@4 292 a->errnum = ret;
Chris@4 293 a->errstr = gai_strerror(ret);
Chris@4 294 a->ai = NULL;
Chris@4 295 return -1;
Chris@4 296 }
Chris@4 297
Chris@4 298 a->ai = ai;
Chris@4 299 }
Chris@4 300
Chris@4 301 return 0;
Chris@4 302 }
Chris@4 303
Chris@4 304 static int create_socket(lo_address a)
Chris@4 305 {
Chris@4 306 if (a->protocol == LO_UDP || a->protocol == LO_TCP) {
Chris@4 307
Chris@4 308 a->socket = socket(a->ai->ai_family, a->ai->ai_socktype, 0);
Chris@4 309 if (a->socket == -1) {
Chris@4 310 a->errnum = geterror();
Chris@4 311 a->errstr = NULL;
Chris@4 312 return -1;
Chris@4 313 }
Chris@4 314
Chris@4 315 if (a->protocol == LO_TCP) {
Chris@4 316 // Only call connect() for TCP sockets - we use sendto() for UDP
Chris@4 317 if ((connect(a->socket, a->ai->ai_addr, a->ai->ai_addrlen))) {
Chris@4 318 a->errnum = geterror();
Chris@4 319 a->errstr = NULL;
Chris@4 320 close(a->socket);
Chris@4 321 a->socket = -1;
Chris@4 322 return -1;
Chris@4 323 }
Chris@4 324 }
Chris@4 325 // if UDP and destination address is broadcast allow broadcast on the
Chris@4 326 // socket
Chris@4 327 else if (a->protocol == LO_UDP && a->ai->ai_family == AF_INET)
Chris@4 328 {
Chris@4 329 // If UDP, and destination address is broadcast,
Chris@4 330 // then allow broadcast on the socket.
Chris@4 331 struct sockaddr_in* si = (struct sockaddr_in*)a->ai->ai_addr;
Chris@4 332 unsigned char* ip = (unsigned char*)&(si->sin_addr);
Chris@4 333
Chris@4 334 if (ip[0]==255 && ip[1]==255 && ip[2]==255 && ip[3]==255)
Chris@4 335 {
Chris@4 336 int opt = 1;
Chris@4 337 setsockopt(a->socket, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(int));
Chris@4 338 }
Chris@4 339 }
Chris@4 340
Chris@4 341 }
Chris@4 342 #ifndef WIN32
Chris@4 343 else if (a->protocol == LO_UNIX) {
Chris@4 344 struct sockaddr_un sa;
Chris@4 345
Chris@4 346 a->socket = socket(PF_UNIX, SOCK_DGRAM, 0);
Chris@4 347 if (a->socket == -1) {
Chris@4 348 a->errnum = geterror();
Chris@4 349 a->errstr = NULL;
Chris@4 350 return -1;
Chris@4 351 }
Chris@4 352
Chris@4 353 sa.sun_family = AF_UNIX;
Chris@4 354 strncpy(sa.sun_path, a->port, sizeof(sa.sun_path)-1);
Chris@4 355
Chris@4 356 if ((connect(a->socket, (struct sockaddr *)&sa, sizeof(sa))) < 0) {
Chris@4 357 a->errnum = geterror();
Chris@4 358 a->errstr = NULL;
Chris@4 359 close(a->socket);
Chris@4 360 a->socket = -1;
Chris@4 361 return -1;
Chris@4 362 }
Chris@4 363 }
Chris@4 364 #endif
Chris@4 365 else {
Chris@4 366 /* unknown protocol */
Chris@4 367 return -2;
Chris@4 368 }
Chris@4 369
Chris@4 370 return 0;
Chris@4 371 }
Chris@4 372
Chris@4 373 static int send_data(lo_address a, lo_server from, char *data, const size_t data_len)
Chris@4 374 {
Chris@4 375 int ret=0;
Chris@4 376 int sock=-1;
Chris@4 377
Chris@4 378 #ifdef WIN32
Chris@4 379 if(!initWSock()) return -1;
Chris@4 380 #endif
Chris@4 381
Chris@4 382 if (data_len > LO_MAX_MSG_SIZE) {
Chris@4 383 a->errnum = 99;
Chris@4 384 a->errstr = "Attempted to send message in excess of maximum "
Chris@4 385 "message size";
Chris@4 386 return -1;
Chris@4 387 }
Chris@4 388
Chris@4 389 // Resolve the destination address, if not done already
Chris@4 390 if (!a->ai) {
Chris@4 391 ret = resolve_address( a );
Chris@4 392 if (ret) return ret;
Chris@4 393 }
Chris@4 394
Chris@4 395 // Re-use existing socket?
Chris@4 396 if (from) {
Chris@4 397 sock = from->sockets[0].fd;
Chris@4 398 } else if (a->protocol == LO_UDP && lo_client_sockets.udp!=-1) {
Chris@4 399 sock = lo_client_sockets.udp;
Chris@4 400 } else {
Chris@4 401 if (a->socket==-1) {
Chris@4 402 ret = create_socket( a );
Chris@4 403 if (ret) return ret;
Chris@4 404 }
Chris@4 405 sock = a->socket;
Chris@4 406 }
Chris@4 407
Chris@4 408
Chris@4 409
Chris@4 410 // Send Length of the following data
Chris@4 411 if (a->protocol == LO_TCP) {
Chris@4 412 int32_t size = htonl(data_len);
Chris@4 413 ret = send(sock, &size, sizeof(size), MSG_NOSIGNAL);
Chris@4 414 }
Chris@4 415
Chris@4 416 // Send the data
Chris@4 417 if (a->protocol == LO_UDP) {
Chris@4 418 if (a->ttl >= 0) {
Chris@4 419 unsigned char ttl = (unsigned char)a->ttl;
Chris@4 420 setsockopt(sock,IPPROTO_IP,IP_MULTICAST_TTL,&ttl,sizeof(ttl));
Chris@4 421 }
Chris@4 422 ret = sendto(sock, data, data_len, MSG_NOSIGNAL,
Chris@4 423 a->ai->ai_addr, a->ai->ai_addrlen);
Chris@4 424 } else {
Chris@4 425 ret = send(sock, data, data_len, MSG_NOSIGNAL);
Chris@4 426 }
Chris@4 427
Chris@4 428 if (a->protocol == LO_TCP && ret == -1) {
Chris@4 429 close(a->socket);
Chris@4 430 a->socket=-1;
Chris@4 431 }
Chris@4 432
Chris@4 433 if (ret == -1) {
Chris@4 434 a->errnum = geterror();
Chris@4 435 a->errstr = NULL;
Chris@4 436 } else {
Chris@4 437 a->errnum = 0;
Chris@4 438 a->errstr = NULL;
Chris@4 439 }
Chris@4 440
Chris@4 441 return ret;
Chris@4 442 }
Chris@4 443
Chris@4 444
Chris@4 445 int lo_send_message(lo_address a, const char *path, lo_message msg)
Chris@4 446 {
Chris@4 447 return lo_send_message_from( a, NULL, path, msg );
Chris@4 448 }
Chris@4 449
Chris@4 450 int lo_send_message_from(lo_address a, lo_server from, const char *path, lo_message msg)
Chris@4 451 {
Chris@4 452 const size_t data_len = lo_message_length(msg, path);
Chris@4 453 char *data = lo_message_serialise(msg, path, NULL, NULL);
Chris@4 454
Chris@4 455 // Send the message
Chris@4 456 int ret = send_data( a, from, data, data_len );
Chris@4 457
Chris@4 458 // For TCP, retry once if it failed. The first try will return
Chris@4 459 // error if the connection was closed, so the second try will
Chris@4 460 // attempt to re-open the connection.
Chris@4 461 if (ret == -1 && a->protocol == LO_TCP)
Chris@4 462 ret = send_data( a, from, data, data_len );
Chris@4 463
Chris@4 464 // Free the memory allocated by lo_message_serialise
Chris@4 465 if (data) free( data );
Chris@4 466
Chris@4 467 return ret;
Chris@4 468 }
Chris@4 469
Chris@4 470
Chris@4 471 int lo_send_bundle(lo_address a, lo_bundle b)
Chris@4 472 {
Chris@4 473 return lo_send_bundle_from( a, NULL, b );
Chris@4 474 }
Chris@4 475
Chris@4 476
Chris@4 477 int lo_send_bundle_from(lo_address a, lo_server from, lo_bundle b)
Chris@4 478 {
Chris@4 479 const size_t data_len = lo_bundle_length(b);
Chris@4 480 char *data = lo_bundle_serialise(b, NULL, NULL);
Chris@4 481
Chris@4 482 // Send the bundle
Chris@4 483 int ret = send_data( a, from, data, data_len );
Chris@4 484
Chris@4 485 // Free the memory allocated by lo_bundle_serialise
Chris@4 486 if (data) free( data );
Chris@4 487
Chris@4 488 return ret;
Chris@4 489 }
Chris@4 490
Chris@4 491 /* vi:set ts=8 sts=4 sw=4: */