XMMS2
socket_tcp.c
Go to the documentation of this file.
1 /* XMMS2 - X Music Multiplexer System
2  * Copyright (C) 2003-2011 XMMS2 Team
3  *
4  * PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!!
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but 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 
17 
18 #include <stdio.h>
19 #include <string.h>
20 #include <stdlib.h>
21 #include <signal.h>
22 #include <assert.h>
23 
25 #include "xmmsc/xmmsc_util.h"
26 #include "xmmsc/xmmsc_sockets.h"
27 #include "xmmsc/xmmsc_unistd.h"
28 #include "url.h"
29 #include "socket_tcp.h"
30 
31 static void
32 xmms_ipc_tcp_destroy (xmms_ipc_transport_t *ipct)
33 {
34  free (ipct->path);
35  close (ipct->fd);
36 }
37 
38 static int
39 xmms_ipc_tcp_read (xmms_ipc_transport_t *ipct, char *buffer, int len)
40 {
41  xmms_socket_t fd;
42  int ret;
43  x_return_val_if_fail (ipct, -1);
44  x_return_val_if_fail (buffer, -1);
45 
46  fd = ipct->fd;
47 
48  ret = recv (fd, buffer, len, 0);
49 
50  return ret;
51 }
52 
53 static int
54 xmms_ipc_tcp_write (xmms_ipc_transport_t *ipct, char *buffer, int len)
55 {
56  xmms_socket_t fd;
57  x_return_val_if_fail (ipct, -1);
58  x_return_val_if_fail (buffer, -1);
59 
60  fd = ipct->fd;
61 
62  return send (fd, buffer, len, 0);
63 
64 }
65 
67 xmms_ipc_tcp_client_init (const xmms_url_t *url, int ipv6)
68 {
69  xmms_socket_t fd = -1;
71  struct addrinfo hints;
72  struct addrinfo *addrinfo;
73  struct addrinfo *addrinfos;
74  int gai_errno;
75 
76  if (!xmms_sockets_initialize ()) {
77  return NULL;
78  }
79 
80  memset (&hints, 0, sizeof (hints));
81  hints.ai_flags = 0;
82  hints.ai_family = url->host[0] ? (ipv6 ? PF_INET6 : PF_INET) : PF_UNSPEC;
83  hints.ai_socktype = SOCK_STREAM;
84  hints.ai_protocol = 0;
85 
86  if ((gai_errno = xmms_getaddrinfo (url->host[0] ? url->host : NULL, url->port[0] ? url->port : XMMS_STRINGIFY (XMMS_DEFAULT_TCP_PORT), &hints, &addrinfos))) {
87  return NULL;
88  }
89 
90  for (addrinfo = addrinfos; addrinfo; addrinfo = addrinfo->ai_next) {
91  int _reuseaddr = 1;
92  const char* reuseaddr = (const char*)&_reuseaddr;
93 
94  fd = socket (addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol);
95  if (!xmms_socket_valid (fd)) {
96  return NULL;
97  }
98 
99  setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, reuseaddr, sizeof (_reuseaddr));
100 
101  if (connect (fd, addrinfo->ai_addr, addrinfo->ai_addrlen) == 0) {
102  break;
103  }
104 
105  close (fd);
106  }
107 
108  xmms_freeaddrinfo (addrinfos);
109 
110  if (!addrinfo) {
111  return NULL;
112  }
113 
114  assert (fd != -1);
115 
116  if (!xmms_socket_set_nonblock (fd)) {
117  close (fd);
118  return NULL;
119  }
120 
121  ipct = x_new0 (xmms_ipc_transport_t, 1);
122  ipct->fd = fd;
123  ipct->path = strdup (url->host);
124  ipct->read_func = xmms_ipc_tcp_read;
125  ipct->write_func = xmms_ipc_tcp_write;
126  ipct->destroy_func = xmms_ipc_tcp_destroy;
127 
128  return ipct;
129 }
130 
131 static xmms_ipc_transport_t *
132 xmms_ipc_tcp_accept (xmms_ipc_transport_t *transport)
133 {
134  xmms_socket_t fd;
135  struct sockaddr sockaddr;
136  socklen_t socklen;
137 
138  x_return_val_if_fail (transport, NULL);
139 
140  socklen = sizeof (sockaddr);
141 
142  fd = accept (transport->fd, &sockaddr, &socklen);
143  if (xmms_socket_valid (fd)) {
144  int _reuseaddr = 1;
145  int _nodelay = 1;
146  const char* reuseaddr = (const char*)&_reuseaddr;
147  const char* nodelay = (const char*)&_nodelay;
149 
150  if (!xmms_socket_set_nonblock (fd)) {
151  close (fd);
152  return NULL;
153  }
154 
155  setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, reuseaddr, sizeof (_reuseaddr));
156  setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, nodelay, sizeof (_nodelay));
157 
158  ret = x_new0 (xmms_ipc_transport_t, 1);
159  ret->fd = fd;
160  ret->read_func = xmms_ipc_tcp_read;
161  ret->write_func = xmms_ipc_tcp_write;
162  ret->destroy_func = xmms_ipc_tcp_destroy;
163 
164  return ret;
165  }
166 
167  return NULL;
168 }
169 
171 xmms_ipc_tcp_server_init (const xmms_url_t *url, int ipv6)
172 {
173  xmms_socket_t fd = -1;
174  xmms_ipc_transport_t *ipct;
175  struct addrinfo hints;
176  struct addrinfo *addrinfo;
177  struct addrinfo *addrinfos;
178  int gai_errno;
179 
180  if (!xmms_sockets_initialize ()) {
181  return NULL;
182  }
183 
184  memset (&hints, 0, sizeof (hints));
185  hints.ai_flags = AI_PASSIVE;
186  hints.ai_family = url->host[0] ? (ipv6 ? PF_INET6 : PF_INET) : PF_UNSPEC;
187  hints.ai_socktype = SOCK_STREAM;
188  hints.ai_protocol = 0;
189 
190  if ((gai_errno = xmms_getaddrinfo (url->host[0] ? url->host : NULL, url->port[0] ? url->port : XMMS_STRINGIFY (XMMS_DEFAULT_TCP_PORT), &hints, &addrinfos))) {
191  return NULL;
192  }
193 
194  for (addrinfo = addrinfos; addrinfo; addrinfo = addrinfo->ai_next) {
195  int _reuseaddr = 1;
196  int _nodelay = 1;
197  const char* reuseaddr = (const char*)&_reuseaddr;
198  const char* nodelay = (const char*)&_nodelay;
199 
200  fd = socket (addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol);
201  if (!xmms_socket_valid (fd)) {
202  return NULL;
203  }
204 
205  setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, reuseaddr, sizeof (_reuseaddr));
206  setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, nodelay, sizeof (_nodelay));
207 
208  if (bind (fd, addrinfo->ai_addr, addrinfo->ai_addrlen) != SOCKET_ERROR &&
209  listen (fd, SOMAXCONN) != SOCKET_ERROR) {
210  break;
211  }
212  close (fd);
213  }
214 
215  xmms_freeaddrinfo (addrinfos);
216 
217  if (!addrinfo) {
218  return NULL;
219  }
220 
221  assert (fd != -1);
222 
223  if (!xmms_socket_set_nonblock (fd)) {
224  close (fd);
225  return NULL;
226  }
227 
228  ipct = x_new0 (xmms_ipc_transport_t, 1);
229  ipct->fd = fd;
230  ipct->path = strdup (url->host);
231  ipct->read_func = xmms_ipc_tcp_read;
232  ipct->write_func = xmms_ipc_tcp_write;
233  ipct->accept_func = xmms_ipc_tcp_accept;
234  ipct->destroy_func = xmms_ipc_tcp_destroy;
235 
236  return ipct;
237 }
238 
#define x_return_val_if_fail(expr, val)
Definition: xmmsc_util.h:13
char * port
Definition: url.h:9
int xmms_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res)
Definition: socket_common.c:19
xmms_ipc_write_func write_func
xmms_ipc_destroy_func destroy_func
int xmms_socket_set_nonblock(xmms_socket_t socket)
Tries to set socket to non-blocking mode.
Definition: socket_unix.c:15
int xmms_sockets_initialize(void)
Definition: socket_unix.c:5
xmms_ipc_accept_func accept_func
int xmms_socket_t
Definition: xmmsc_sockets.h:37
#define XMMS_STRINGIFY(x)
Definition: xmmsc_util.h:10
#define x_new0(type, num)
Definition: xmmsc_util.h:16
#define SOCKET_ERROR
Definition: xmmsc_sockets.h:17
#define XMMS_DEFAULT_TCP_PORT
Definition: xmmsc_util.h:46
Definition: url.h:4
xmms_ipc_transport_t * xmms_ipc_tcp_server_init(const xmms_url_t *url, int ipv6)
Definition: socket_tcp.c:171
void xmms_freeaddrinfo(struct addrinfo *res)
Definition: socket_common.c:26
xmms_ipc_transport_t * xmms_ipc_tcp_client_init(const xmms_url_t *url, int ipv6)
Definition: socket_tcp.c:67
xmms_ipc_read_func read_func
char * host
Definition: url.h:9
int xmms_socket_valid(xmms_socket_t socket)
Definition: socket_unix.c:36