//vio_socket.c: /* * Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2009 * * This file is part of libroar a part of RoarAudio, * a cross-platform sound system for both, home and professional use. * See README for details. * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 * as published by the Free Software Foundation. * * libroar 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * * NOTE for everyone want's to change something and send patches: * read README and HACKING! There a addition information on * the license of this document you need to read before you send * any patches. * * NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc * or libpulse*: * The libs libroaresd, libroararts and libroarpulse link this lib * and are therefore GPL. Because of this it may be illigal to use * them with any software that uses libesd, libartsc or libpulse*. */ #include "libroar.h" int roar_vio_open_def_socket (struct roar_vio_calls * calls, struct roar_vio_defaults * def) { int fh = -1; socklen_t len = 0; if ( calls == NULL || def == NULL ) return -1; if ( def->type != ROAR_VIO_DEF_TYPE_SOCKET ) return -1; switch (def->d.socket.domain) { case AF_INET: len = sizeof(struct sockaddr_in); if ( roar_vio_socket_init_inet4host_def(def) == -1 ) return -1; switch (def->d.socket.type) { case SOCK_STREAM: fh = roar_socket_new_tcp(); break; case SOCK_DGRAM: fh = roar_socket_new_udp(); break; default: return -1; } break; #ifdef ROAR_HAVE_UNIX case AF_UNIX: len = sizeof(struct sockaddr_un); switch (def->d.socket.type) { case SOCK_STREAM: fh = roar_socket_new_unix(); break; case SOCK_DGRAM: return -1; break; default: return -1; } break; #endif #ifdef ROAR_HAVE_LIBDNET case AF_DECnet: len = sizeof(struct sockaddr_dn); return -1; break; #endif #ifdef ROAR_HAVE_IPV6 case AF_INET6: len = sizeof(struct sockaddr_in6); switch (def->d.socket.type) { case SOCK_STREAM: fh = roar_socket_new_tcp6(); break; case SOCK_DGRAM: fh = roar_socket_new_udp6(); break; default: return -1; } break; #endif #ifdef ROAR_HAVE_IPX case AF_IPX: len = sizeof(struct sockaddr_ipx); return -1; break; #endif default: return -1; } if ( fh == -1 ) return -1; if ( connect(fh, &(def->d.socket.sa.sa), len) == -1 ) { close(fh); return -1; } if ( roar_vio_open_fh_socket(calls, fh) == -1 ) { close(fh); return -1; } return 0; } int roar_vio_socket_init_socket_def (struct roar_vio_defaults * def, int domain, int type) { if ( def == NULL || domain == -1 || type == -1 ) return -1; // we do not memset(def, 0, sizeof(...)) here // because this is allready done in roar_vio_dstr_init_defaults() // if we would be would override o_flags/o_mode and maybe others memset(&(def->d.socket.sa), 0, sizeof(def->d.socket.sa)); def->type = ROAR_VIO_DEF_TYPE_SOCKET; def->d.socket.domain = domain; def->d.socket.type = type; def->d.socket.sa.sa.sa_family = domain; return 0; } int roar_vio_socket_init_dstr_def (struct roar_vio_defaults * def, char * dstr, int hint, int type, struct roar_vio_defaults * odef) { char * host; int port; if ( def == NULL || dstr == NULL ) return -1; ROAR_WARN("roar_vio_socket_init_dstr_def(def=%p, dstr='%s', hint=%i, type=%i, odef=%p) = ?", def, dstr, hint, type, odef); if ( hint == -1 ) { if ( 0 ) { // this is needed to keep the syntx ok, compiler will throw it away #ifdef ROAR_HAVE_IPV6 } else if ( strstr(dstr, "[") != NULL ) { // [ip]:service hint = AF_INET6; #endif #ifdef ROAR_HAVE_LIBDNET } else if ( strstr(dstr, "::") != NULL ) { // node::object hint = AF_DECnet; #endif #ifdef ROAR_HAVE_IPX } else if ( strstr(dstr, "(") != NULL ) { // net:mac(service) hint = AF_IPX; #endif #ifdef ROAR_HAVE_UNIX } else if ( strstr(dstr, "/") != NULL ) { // /path/to/sock hint = AF_UNIX; #endif } else if ( strstr(dstr, ":") != NULL ) { // host:port hint = AF_INET; } } if ( hint == -1 && odef != NULL ) { // if we still don't know what this is we try // to use the parent objects request if ( odef->type == ROAR_VIO_DEF_TYPE_SOCKET ) { hint = odef->d.socket.domain; } } if ( hint == -1 ) /* we really have no glue what this is... */ return -1; #ifdef ROAR_HAVE_UNIX if ( hint == AF_UNIX ) { if ( *dstr != 0 && strcmp(dstr, "//") != 0 ) { return roar_vio_socket_init_unix_def(def, dstr); } else { if ( roar_vio_socket_conv_def(odef, AF_UNIX) == -1 ) return -1; return roar_vio_socket_init_unix_def(def, odef->d.socket.sa.un.sun_path); } } #endif for (; *dstr == '/'; dstr++); switch (hint) { case AF_INET: host = dstr; for (; *dstr != 0 && *dstr != ':'; dstr++); if ( *dstr == ':' ) { // we have a port :) *dstr++ = 0; if ( (port = roar_vio_socket_get_port(dstr, AF_INET, type)) == -1 ) return -1; return roar_vio_socket_init_inet4_def(def, host, port, type); } else { if ( roar_vio_socket_conv_def(odef, AF_INET) == -1 ) return -1; return roar_vio_socket_init_inet4_def(def, host, ROAR_NET2HOST16(odef->d.socket.sa.in.sin_port), type); } break; #ifdef ROAR_HAVE_LIBDNET case AF_DECnet: return -1; break; #endif #ifdef ROAR_HAVE_IPV6 case AF_INET6: return -1; break; #endif #ifdef ROAR_HAVE_IPX case AF_IPX: return -1; break; #endif default: return -1; } return 0; } int roar_vio_socket_conv_def (struct roar_vio_defaults * def, int domain) { return -1; } int roar_vio_socket_get_port (char * service, int domain, int type) { if ( service == NULL || domain == -1 || type == -1 ) return -1; // TODO: we should write something better return atoi(service); } // AF_UNIX: int roar_vio_socket_init_unix_def (struct roar_vio_defaults * def, char * path) { #ifdef ROAR_HAVE_UNIX if ( roar_vio_socket_init_socket_def(def, AF_UNIX, SOCK_STREAM) == -1 ) return -1; strncpy(def->d.socket.sa.un.sun_path, path, sizeof(def->d.socket.sa.un.sun_path) - 1); return 0; #else return -1; #endif } // AF_DECnet: int roar_vio_socket_init_decnet_def (struct roar_vio_defaults * def, char * node, int object, char * objname); // AF_INET: int roar_vio_socket_init_inet4host_def(struct roar_vio_defaults * def) { struct hostent * he; if ( def == NULL ) return -1; if ( def->d.socket.host == NULL ) return -1; if ( (he = gethostbyname(def->d.socket.host)) == NULL ) { ROAR_ERR("roar_vio_socket_init_inet4host_def(*): Can\'t resolve host name '%s'", def->d.socket.host); return -1; } memcpy((struct in_addr *)&def->d.socket.sa.in.sin_addr, he->h_addr, sizeof(struct in_addr)); return 0; } int roar_vio_socket_init_inet4_def (struct roar_vio_defaults * def, char * host, int port, int type) { if ( roar_vio_socket_init_socket_def(def, AF_INET, type) == -1 ) return -1; def->d.socket.host = host; def->d.socket.sa.in.sin_port = ROAR_HOST2NET16(port); return 0; } int roar_vio_socket_init_tcp4_def (struct roar_vio_defaults * def, char * host, int port) { return roar_vio_socket_init_inet4_def(def, host, port, SOCK_STREAM); } int roar_vio_socket_init_udp4_def (struct roar_vio_defaults * def, char * host, int port) { return roar_vio_socket_init_inet4_def(def, host, port, SOCK_DGRAM); } // AF_INET6: int roar_vio_socket_init_inet6host_def(struct roar_vio_defaults * def); int roar_vio_socket_init_inet6_def (struct roar_vio_defaults * def, char * host, int port, int type) { return -1; } int roar_vio_socket_init_tcp6_def (struct roar_vio_defaults * def, char * host, int port) { return roar_vio_socket_init_inet6_def(def, host, port, SOCK_STREAM); } int roar_vio_socket_init_udp6_def (struct roar_vio_defaults * def, char * host, int port) { return roar_vio_socket_init_inet6_def(def, host, port, SOCK_DGRAM); } //ll