/*
* Copyright (C) 2004 Steve Harris
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* $Id$
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#ifdef _MSC_VER
#include <io.h>
#define snprintf _snprintf
#else
#include <unistd.h>
#endif
#ifdef WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <netdb.h>
#include <sys/socket.h>
#endif
#include "lo_types_internal.h"
#include "lo/lo.h"
#include "config.h"
lo_address lo_address_new_with_proto(int proto, const char *host, const char *port)
{
lo_address a;
if(proto != LO_UDP && proto != LO_TCP && proto != LO_UNIX) return NULL;
a = calloc(1, sizeof(struct _lo_address));
if(a == NULL) return NULL;
a->ai = NULL;
a->socket = -1;
a->protocol = proto;
switch(proto) {
default:
case LO_UDP:
case LO_TCP:
if (host) {
a->host = strdup(host);
} else {
a->host = strdup("localhost");
}
break;
case LO_UNIX:
a->host = strdup("localhost");
break;
}
if (port) {
a->port = strdup(port);
} else {
a->port = NULL;
}
a->ttl = -1;
return a;
}
lo_address lo_address_new(const char *host, const char *port)
{
return lo_address_new_with_proto(LO_UDP, host ,port);
}
lo_address lo_address_new_from_url(const char *url)
{
lo_address a;
int protocol;
char *host, *port, *proto;
if (!url || !*url) {
return NULL;
}
protocol = lo_url_get_protocol_id(url);
if (protocol == LO_UDP || protocol == LO_TCP) {
host = lo_url_get_hostname(url);
port = lo_url_get_port(url);
a = lo_address_new_with_proto(protocol, host, port);
if(host) free(host);
if(port) free(port);
#ifndef WIN32
} else if (protocol == LO_UNIX) {
port = lo_url_get_path(url);
a = lo_address_new_with_proto(LO_UNIX, NULL, port);
if(port) free(port);
#endif
} else {
proto = lo_url_get_protocol(url);
fprintf(stderr, PACKAGE_NAME ": protocol '%s' not supported by this "
"version\n", proto);
if(proto) free(proto);
return NULL;
}
return a;
}
const char *lo_address_get_hostname(lo_address a)
{
if (!a) {
return NULL;
}
return a->host;
}
int lo_address_get_protocol(lo_address a)
{
if (!a) {
return -1;
}
return a->protocol;
}
const char *lo_address_get_port(lo_address a)
{
if (!a) {
return NULL;
}
return a->port;
}
static const char* get_protocol_name(int proto)
{
switch(proto) {
case LO_UDP:
return "udp";
case LO_TCP:
return "tcp";
#ifndef WIN32
case LO_UNIX:
return "unix";
#endif
}
return NULL;
}
char *lo_address_get_url(lo_address a)
{
char *buf;
int ret=0;
int needquote = strchr(a->host, ':') ? 1 : 0;
char *fmt;
if (needquote) {
fmt = "osc.%s://[%s]:%s/";
} else {
fmt = "osc.%s://%s:%s/";
}
#ifndef _MSC_VER
ret = snprintf(NULL, 0, fmt,
get_protocol_name(a->protocol), a->host, a->port);
#endif
if (ret <= 0) {
/* this libc is not C99 compliant, guess a size */
ret = 1023;
}
buf = malloc((ret + 2) * sizeof(char));
snprintf(buf, ret+1, fmt,
get_protocol_name(a->protocol), a->host, a->port);
return buf;
}
void lo_address_free(lo_address a)
{
if (a) {
if (a->socket != -1) {
close(a->socket);
}
if (a->host) free(a->host);
if (a->port) free(a->port);
if (a->ai) freeaddrinfo(a->ai);
free(a);
}
}
int lo_address_errno(lo_address a)
{
return a->errnum;
}
const char *lo_address_errstr(lo_address a)
{
char *msg;
if (a->errstr) {
return a->errstr;
}
msg = strerror(a->errnum);
if (msg) {
return msg;
} else {
return "unknown error";
}
return "unknown error";
}
char *lo_url_get_protocol(const char *url)
{
char *protocol,*ret;
if (!url) {
return NULL;
}
protocol = malloc(strlen(url));
if (sscanf(url, "osc://%s", protocol)) {
fprintf(stderr, PACKAGE_NAME " warning: no protocol specified in URL, "
"assuming UDP.\n");
ret = strdup("udp");
} else if (sscanf(url, "osc.%[^:/[]", protocol)) {
ret = strdup(protocol);
} else {
ret = NULL;
}
free(protocol);
return ret;
}
int lo_url_get_protocol_id(const char *url)
{
if(!url) {
return -1;
}
if(!strncmp(url, "osc:", 4)) {
fprintf(stderr, PACKAGE_NAME " warning: no protocol specified in URL, "
"assuming UDP.\n");
return LO_UDP; // should be LO_DEFAULT?
} else if(!strncmp(url, "osc.udp:", 8)) {
return LO_UDP;
} else if(!strncmp(url, "osc.tcp:", 8)) {
return LO_TCP;
} else if(!strncmp(url, "osc.unix:", 9)) {
return LO_UNIX;
}
return -1;
}
char *lo_url_get_hostname(const char *url)
{
char *hostname = malloc(strlen(url));
if (sscanf(url, "osc://%[^[:/]", hostname)) {
return hostname;
}
if (sscanf(url, "osc.%*[^:/]://[%[^]/]]", hostname)) {
return hostname;
}
if (sscanf(url, "osc.%*[^:/]://%[^[:/]", hostname)) {
return hostname;
}
/* doesnt look like an OSC URL */
free(hostname);
return NULL;
}
char *lo_url_get_port(const char *url)
{
char *port = malloc(strlen(url));
if (sscanf(url, "osc://%*[^:]:%[0-9]", port)) {
return port;
}
if (sscanf(url, "osc.%*[^:]://%*[^:]:%[0-9]", port)) {
return port;
}
if (sscanf(url, "osc://[%*[^]]]:%[0-9]", port)) {
return port;
}
if (sscanf(url, "osc.%*[^:]://[%*[^]]]:%[0-9]", port)) {
return port;
}
/* doesnt look like an OSC URL with port number */
free(port);
return NULL;
}
char *lo_url_get_path(const char *url)
{
char *path = malloc(strlen(url));
if (sscanf(url, "osc://%*[^:]:%*[0-9]%s", path)) {
return path;
}
if (sscanf(url, "osc.%*[^:]://%*[^:]:%*[0-9]%s", path) == 1) {
return path;
}
if (sscanf(url, "osc.unix://%*[^/]%s", path) == 1) {
return path;
}
if (sscanf(url, "osc.%*[^:]://%s", path)) {
return path;
}
/* doesnt look like an OSC URL with port number and path*/
free(path);
return NULL;
}
void lo_address_set_ttl(lo_address t, int ttl)
{
if (t->protocol == LO_UDP)
t->ttl = ttl;
}
int lo_address_get_ttl(lo_address t)
{
return t->ttl;
}
/* vi:set ts=8 sts=4 sw=4: */