XMMS2
src/lib/xmmsipc/socket_tcp.c
Go to the documentation of this file.
00001 /*  XMMS2 - X Music Multiplexer System
00002  *  Copyright (C) 2003-2011 XMMS2 Team
00003  *
00004  *  PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!!
00005  *
00006  *  This library is free software; you can redistribute it and/or
00007  *  modify it under the terms of the GNU Lesser General Public
00008  *  License as published by the Free Software Foundation; either
00009  *  version 2.1 of the License, or (at your option) any later version.
00010  *
00011  *  This library is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  *  Lesser General Public License for more details.
00015  */
00016 
00017 
00018 #include <stdio.h>
00019 #include <string.h>
00020 #include <stdlib.h>
00021 #include <signal.h>
00022 #include <assert.h>
00023 
00024 #include "xmmsc/xmmsc_ipc_transport.h"
00025 #include "xmmsc/xmmsc_util.h"
00026 #include "xmmsc/xmmsc_sockets.h"
00027 #include "xmmsc/xmmsc_unistd.h"
00028 #include "url.h"
00029 #include "socket_tcp.h"
00030 
00031 static void
00032 xmms_ipc_tcp_destroy (xmms_ipc_transport_t *ipct)
00033 {
00034     free (ipct->path);
00035     close (ipct->fd);
00036 }
00037 
00038 static int
00039 xmms_ipc_tcp_read (xmms_ipc_transport_t *ipct, char *buffer, int len)
00040 {
00041     xmms_socket_t fd;
00042     int ret;
00043     x_return_val_if_fail (ipct, -1);
00044     x_return_val_if_fail (buffer, -1);
00045 
00046     fd = ipct->fd;
00047 
00048     ret =  recv (fd, buffer, len, 0);
00049 
00050     return ret;
00051 }
00052 
00053 static int
00054 xmms_ipc_tcp_write (xmms_ipc_transport_t *ipct, char *buffer, int len)
00055 {
00056     xmms_socket_t fd;
00057     x_return_val_if_fail (ipct, -1);
00058     x_return_val_if_fail (buffer, -1);
00059 
00060     fd = ipct->fd;
00061 
00062     return send (fd, buffer, len, 0);
00063 
00064 }
00065 
00066 xmms_ipc_transport_t *
00067 xmms_ipc_tcp_client_init (const xmms_url_t *url, int ipv6)
00068 {
00069     xmms_socket_t fd = -1;
00070     xmms_ipc_transport_t *ipct;
00071     struct addrinfo hints;
00072     struct addrinfo *addrinfo;
00073     struct addrinfo *addrinfos;
00074     int gai_errno;
00075 
00076     if (!xmms_sockets_initialize ()) {
00077         return NULL;
00078     }
00079 
00080     memset (&hints, 0, sizeof (hints));
00081     hints.ai_flags = 0;
00082     hints.ai_family = url->host[0] ? (ipv6 ? PF_INET6 : PF_INET) : PF_UNSPEC;
00083     hints.ai_socktype = SOCK_STREAM;
00084     hints.ai_protocol = 0;
00085 
00086     if ((gai_errno = xmms_getaddrinfo (url->host[0] ? url->host : NULL, url->port[0] ? url->port : XMMS_STRINGIFY (XMMS_DEFAULT_TCP_PORT), &hints, &addrinfos))) {
00087         return NULL;
00088     }
00089 
00090     for (addrinfo = addrinfos; addrinfo; addrinfo = addrinfo->ai_next) {
00091         int _reuseaddr = 1;
00092         const char* reuseaddr = (const char*)&_reuseaddr;
00093 
00094         fd = socket (addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol);
00095         if (!xmms_socket_valid (fd)) {
00096             return NULL;
00097         }
00098 
00099         setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, reuseaddr, sizeof (_reuseaddr));
00100 
00101         if (connect (fd, addrinfo->ai_addr, addrinfo->ai_addrlen) == 0) {
00102             break;
00103         }
00104 
00105         close (fd);
00106     }
00107 
00108     xmms_freeaddrinfo (addrinfos);
00109 
00110     if (!addrinfo) {
00111         return NULL;
00112     }
00113 
00114     assert (fd != -1);
00115 
00116     if (!xmms_socket_set_nonblock (fd)) {
00117         close (fd);
00118         return NULL;
00119     }
00120 
00121     ipct = x_new0 (xmms_ipc_transport_t, 1);
00122     ipct->fd = fd;
00123     ipct->path = strdup (url->host);
00124     ipct->read_func = xmms_ipc_tcp_read;
00125     ipct->write_func = xmms_ipc_tcp_write;
00126     ipct->destroy_func = xmms_ipc_tcp_destroy;
00127 
00128     return ipct;
00129 }
00130 
00131 static xmms_ipc_transport_t *
00132 xmms_ipc_tcp_accept (xmms_ipc_transport_t *transport)
00133 {
00134     xmms_socket_t fd;
00135     struct sockaddr sockaddr;
00136     socklen_t socklen;
00137 
00138     x_return_val_if_fail (transport, NULL);
00139 
00140     socklen = sizeof (sockaddr);
00141 
00142     fd = accept (transport->fd, &sockaddr, &socklen);
00143     if (xmms_socket_valid (fd)) {
00144         int _reuseaddr = 1;
00145         int _nodelay = 1;
00146         const char* reuseaddr = (const char*)&_reuseaddr;
00147         const char* nodelay = (const char*)&_nodelay;
00148         xmms_ipc_transport_t *ret;
00149 
00150         if (!xmms_socket_set_nonblock (fd)) {
00151             close (fd);
00152             return NULL;
00153         }
00154 
00155         setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, reuseaddr, sizeof (_reuseaddr));
00156         setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, nodelay, sizeof (_nodelay));
00157 
00158         ret = x_new0 (xmms_ipc_transport_t, 1);
00159         ret->fd = fd;
00160         ret->read_func = xmms_ipc_tcp_read;
00161         ret->write_func = xmms_ipc_tcp_write;
00162         ret->destroy_func = xmms_ipc_tcp_destroy;
00163 
00164         return ret;
00165     }
00166 
00167     return NULL;
00168 }
00169 
00170 xmms_ipc_transport_t *
00171 xmms_ipc_tcp_server_init (const xmms_url_t *url, int ipv6)
00172 {
00173     xmms_socket_t fd = -1;
00174     xmms_ipc_transport_t *ipct;
00175     struct addrinfo hints;
00176     struct addrinfo *addrinfo;
00177     struct addrinfo *addrinfos;
00178     int gai_errno;
00179 
00180     if (!xmms_sockets_initialize ()) {
00181         return NULL;
00182     }
00183 
00184     memset (&hints, 0, sizeof (hints));
00185     hints.ai_flags = AI_PASSIVE;
00186     hints.ai_family = url->host[0] ? (ipv6 ? PF_INET6 : PF_INET) : PF_UNSPEC;
00187     hints.ai_socktype = SOCK_STREAM;
00188     hints.ai_protocol = 0;
00189 
00190     if ((gai_errno = xmms_getaddrinfo (url->host[0] ? url->host : NULL, url->port[0] ? url->port : XMMS_STRINGIFY (XMMS_DEFAULT_TCP_PORT), &hints, &addrinfos))) {
00191         return NULL;
00192     }
00193 
00194     for (addrinfo = addrinfos; addrinfo; addrinfo = addrinfo->ai_next) {
00195         int _reuseaddr = 1;
00196         int _nodelay = 1;
00197         const char* reuseaddr = (const char*)&_reuseaddr;
00198         const char* nodelay = (const char*)&_nodelay;
00199 
00200         fd = socket (addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol);
00201         if (!xmms_socket_valid (fd)) {
00202             return NULL;
00203         }
00204 
00205         setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, reuseaddr, sizeof (_reuseaddr));
00206         setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, nodelay, sizeof (_nodelay));
00207 
00208         if (bind (fd, addrinfo->ai_addr, addrinfo->ai_addrlen) != SOCKET_ERROR &&
00209             listen (fd, SOMAXCONN) != SOCKET_ERROR) {
00210             break;
00211         }
00212         close (fd);
00213     }
00214 
00215     xmms_freeaddrinfo (addrinfos);
00216 
00217     if (!addrinfo) {
00218         return NULL;
00219     }
00220 
00221     assert (fd != -1);
00222 
00223     if (!xmms_socket_set_nonblock (fd)) {
00224         close (fd);
00225         return NULL;
00226     }
00227 
00228     ipct = x_new0 (xmms_ipc_transport_t, 1);
00229     ipct->fd = fd;
00230     ipct->path = strdup (url->host);
00231     ipct->read_func = xmms_ipc_tcp_read;
00232     ipct->write_func = xmms_ipc_tcp_write;
00233     ipct->accept_func = xmms_ipc_tcp_accept;
00234     ipct->destroy_func = xmms_ipc_tcp_destroy;
00235 
00236     return ipct;
00237 }
00238