PageRenderTime 45ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 0ms

/src/network/io.c

https://gitlab.com/evilbinary/vlc
C | 411 lines | 293 code | 51 blank | 67 comment | 72 complexity | 7e6f5e67e63f175645455e03b1f83cfb MD5 | raw file
  1. /*****************************************************************************
  2. * io.c: network I/O functions
  3. *****************************************************************************
  4. * Copyright (C) 2004-2005, 2007 VLC authors and VideoLAN
  5. * Copyright © 2005-2006 Rémi Denis-Courmont
  6. * $Id: 20a01adb893e5720aa144f2256a8375c0cdac5aa $
  7. *
  8. * Authors: Laurent Aimar <fenrir@videolan.org>
  9. * Rémi Denis-Courmont <rem # videolan.org>
  10. * Christophe Mutricy <xtophe at videolan dot org>
  11. *
  12. * This program is free software; you can redistribute it and/or modify it
  13. * under the terms of the GNU Lesser General Public License as published by
  14. * the Free Software Foundation; either version 2.1 of the License, or
  15. * (at your option) any later version.
  16. *
  17. * This program is distributed in the hope that it will be useful,
  18. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. * GNU Lesser General Public License for more details.
  21. *
  22. * You should have received a copy of the GNU Lesser General Public License
  23. * along with this program; if not, write to the Free Software Foundation,
  24. * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  25. *****************************************************************************/
  26. /*****************************************************************************
  27. * Preamble
  28. *****************************************************************************/
  29. #ifdef HAVE_CONFIG_H
  30. # include "config.h"
  31. #endif
  32. #include <stdlib.h>
  33. #include <stdio.h>
  34. #include <limits.h>
  35. #include <errno.h>
  36. #include <assert.h>
  37. #include <unistd.h>
  38. #ifdef HAVE_LINUX_DCCP_H
  39. /* TODO: use glibc instead of linux-kernel headers */
  40. # include <linux/dccp.h>
  41. # define SOL_DCCP 269
  42. #endif
  43. #include <vlc_common.h>
  44. #include <vlc_network.h>
  45. #include <vlc_interrupt.h>
  46. extern int rootwrap_bind (int family, int socktype, int protocol,
  47. const struct sockaddr *addr, size_t alen);
  48. int net_Socket (vlc_object_t *p_this, int family, int socktype,
  49. int protocol)
  50. {
  51. int fd = vlc_socket (family, socktype, protocol, true);
  52. if (fd == -1)
  53. {
  54. if (net_errno != EAFNOSUPPORT)
  55. msg_Err (p_this, "cannot create socket: %s",
  56. vlc_strerror_c(net_errno));
  57. return -1;
  58. }
  59. setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof (int));
  60. #ifdef IPV6_V6ONLY
  61. /*
  62. * Accepts only IPv6 connections on IPv6 sockets.
  63. * If possible, we should open two sockets, but it is not always possible.
  64. */
  65. if (family == AF_INET6)
  66. setsockopt (fd, IPPROTO_IPV6, IPV6_V6ONLY, &(int){ 1 }, sizeof (int));
  67. #endif
  68. #if defined (_WIN32)
  69. # ifndef IPV6_PROTECTION_LEVEL
  70. # warning Please update your C library headers.
  71. # define IPV6_PROTECTION_LEVEL 23
  72. # define PROTECTION_LEVEL_UNRESTRICTED 10
  73. # endif
  74. if (family == AF_INET6)
  75. setsockopt (fd, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL,
  76. &(int){ PROTECTION_LEVEL_UNRESTRICTED }, sizeof (int));
  77. #endif
  78. #ifdef DCCP_SOCKOPT_SERVICE
  79. if (socktype == SOL_DCCP)
  80. {
  81. char *dccps = var_InheritString (p_this, "dccp-service");
  82. if (dccps != NULL)
  83. {
  84. setsockopt (fd, SOL_DCCP, DCCP_SOCKOPT_SERVICE, dccps,
  85. (strlen (dccps) + 3) & ~3);
  86. free (dccps);
  87. }
  88. }
  89. #endif
  90. return fd;
  91. }
  92. int *net_Listen (vlc_object_t *p_this, const char *psz_host,
  93. int i_port, int type, int protocol)
  94. {
  95. struct addrinfo hints = {
  96. .ai_socktype = type,
  97. .ai_protocol = protocol,
  98. .ai_flags = AI_PASSIVE | AI_NUMERICSERV | AI_IDN,
  99. }, *res;
  100. msg_Dbg (p_this, "net: listening to %s port %d",
  101. (psz_host != NULL) ? psz_host : "*", i_port);
  102. int i_val = vlc_getaddrinfo (psz_host, i_port, &hints, &res);
  103. if (i_val)
  104. {
  105. msg_Err (p_this, "Cannot resolve %s port %d : %s",
  106. (psz_host != NULL) ? psz_host : "", i_port,
  107. gai_strerror (i_val));
  108. return NULL;
  109. }
  110. int *sockv = NULL;
  111. unsigned sockc = 0;
  112. for (struct addrinfo *ptr = res; ptr != NULL; ptr = ptr->ai_next)
  113. {
  114. int fd = net_Socket (p_this, ptr->ai_family, ptr->ai_socktype,
  115. ptr->ai_protocol);
  116. if (fd == -1)
  117. {
  118. msg_Dbg (p_this, "socket error: %s", vlc_strerror_c(net_errno));
  119. continue;
  120. }
  121. /* Bind the socket */
  122. #if defined (_WIN32)
  123. /*
  124. * Under Win32 and for multicasting, we bind to INADDR_ANY.
  125. * This is of course a severe bug, since the socket would logically
  126. * receive unicast traffic, and multicast traffic of groups subscribed
  127. * to via other sockets.
  128. */
  129. if (net_SockAddrIsMulticast (ptr->ai_addr, ptr->ai_addrlen)
  130. && (sizeof (struct sockaddr_storage) >= ptr->ai_addrlen))
  131. {
  132. // This works for IPv4 too - don't worry!
  133. struct sockaddr_in6 dumb =
  134. {
  135. .sin6_family = ptr->ai_addr->sa_family,
  136. .sin6_port = ((struct sockaddr_in *)(ptr->ai_addr))->sin_port
  137. };
  138. bind (fd, (struct sockaddr *)&dumb, ptr->ai_addrlen);
  139. }
  140. else
  141. #endif
  142. if (bind (fd, ptr->ai_addr, ptr->ai_addrlen))
  143. {
  144. net_Close (fd);
  145. #if !defined(_WIN32)
  146. fd = rootwrap_bind (ptr->ai_family, ptr->ai_socktype,
  147. ptr->ai_protocol,
  148. ptr->ai_addr, ptr->ai_addrlen);
  149. if (fd != -1)
  150. {
  151. msg_Dbg (p_this, "got socket %d from rootwrap", fd);
  152. }
  153. else
  154. #endif
  155. {
  156. msg_Err (p_this, "socket bind error: %s",
  157. vlc_strerror_c(net_errno));
  158. continue;
  159. }
  160. }
  161. if (net_SockAddrIsMulticast (ptr->ai_addr, ptr->ai_addrlen))
  162. {
  163. if (net_Subscribe (p_this, fd, ptr->ai_addr, ptr->ai_addrlen))
  164. {
  165. net_Close (fd);
  166. continue;
  167. }
  168. }
  169. /* Listen */
  170. switch (ptr->ai_socktype)
  171. {
  172. case SOCK_STREAM:
  173. case SOCK_RDM:
  174. case SOCK_SEQPACKET:
  175. #ifdef SOCK_DCCP
  176. case SOCK_DCCP:
  177. #endif
  178. if (listen (fd, INT_MAX))
  179. {
  180. msg_Err (p_this, "socket listen error: %s",
  181. vlc_strerror_c(net_errno));
  182. net_Close (fd);
  183. continue;
  184. }
  185. }
  186. int *nsockv = (int *)realloc (sockv, (sockc + 2) * sizeof (int));
  187. if (nsockv != NULL)
  188. {
  189. nsockv[sockc++] = fd;
  190. sockv = nsockv;
  191. }
  192. else
  193. net_Close (fd);
  194. }
  195. freeaddrinfo (res);
  196. if (sockv != NULL)
  197. sockv[sockc] = -1;
  198. return sockv;
  199. }
  200. /**
  201. * Reads data from a socket, blocking until all requested data is received or
  202. * the end of the stream is reached.
  203. * This function is a cancellation point.
  204. * @return -1 on error, or the number of bytes of read.
  205. */
  206. ssize_t (net_Read)(vlc_object_t *restrict obj, int fd,
  207. void *restrict buf, size_t len)
  208. {
  209. size_t rd = 0;
  210. do
  211. {
  212. if (vlc_killed())
  213. {
  214. vlc_testcancel();
  215. errno = EINTR;
  216. return -1;
  217. }
  218. ssize_t val = vlc_recv_i11e(fd, buf, len, 0);
  219. if (val < 0)
  220. {
  221. if (errno == EINTR || errno == EAGAIN)
  222. continue;
  223. #ifdef _WIN32
  224. else if (WSAGetLastError() == WSAEMSGSIZE) /* datagram too big */
  225. {
  226. msg_Warn(obj, "read truncated to %zu bytes", len);
  227. val = len;
  228. }
  229. #endif
  230. else
  231. {
  232. msg_Err(obj, "read error: %s", vlc_strerror_c(errno));
  233. return rd ? (ssize_t)rd : -1;
  234. }
  235. }
  236. rd += val;
  237. if (val == 0)
  238. break;
  239. assert(len >= (size_t)val);
  240. len -= val;
  241. buf = ((char *)buf) + val;
  242. }
  243. while (len > 0);
  244. return rd;
  245. }
  246. /**
  247. * Writes data to a socket.
  248. * This blocks until all data is written or an error occurs.
  249. *
  250. * This function is a cancellation point.
  251. *
  252. * @return the total number of bytes written, or -1 if an error occurs
  253. * before any data is written.
  254. */
  255. ssize_t (net_Write)(vlc_object_t *obj, int fd, const void *buf, size_t len)
  256. {
  257. size_t written = 0;
  258. do
  259. {
  260. if (vlc_killed())
  261. {
  262. vlc_testcancel();
  263. errno = EINTR;
  264. return -1;
  265. }
  266. ssize_t val = vlc_send_i11e (fd, buf, len, MSG_NOSIGNAL);
  267. if (val == -1)
  268. {
  269. if (errno == EINTR || errno == EAGAIN)
  270. continue;
  271. msg_Err(obj, "write error: %s", vlc_strerror_c(errno));
  272. return written ? (ssize_t)written : -1;
  273. }
  274. if (val == 0)
  275. break;
  276. written += val;
  277. assert(len >= (size_t)val);
  278. len -= val;
  279. buf = ((const char *)buf) + val;
  280. }
  281. while (len > 0);
  282. return written;
  283. }
  284. #undef net_Gets
  285. /**
  286. * Reads a line from a file descriptor.
  287. * This function is not thread-safe; the same file descriptor I/O cannot be
  288. * read by another thread at the same time (although it can be written to).
  289. *
  290. * @note This only works with stream-oriented file descriptors, not with
  291. * datagram or packet-oriented ones.
  292. *
  293. * @return nul-terminated heap-allocated string, or NULL on I/O error.
  294. */
  295. char *net_Gets(vlc_object_t *obj, int fd)
  296. {
  297. char *buf = NULL;
  298. size_t size = 0, len = 0;
  299. for (;;)
  300. {
  301. if (len == size)
  302. {
  303. if (unlikely(size >= (1 << 16)))
  304. {
  305. errno = EMSGSIZE;
  306. goto error; /* put sane buffer size limit */
  307. }
  308. char *newbuf = realloc(buf, size + 1024);
  309. if (unlikely(newbuf == NULL))
  310. goto error;
  311. buf = newbuf;
  312. size += 1024;
  313. }
  314. assert(len < size);
  315. ssize_t val = vlc_recv_i11e(fd, buf + len, size - len, MSG_PEEK);
  316. if (val <= 0)
  317. goto error;
  318. char *end = memchr(buf + len, '\n', val);
  319. if (end != NULL)
  320. val = (end + 1) - (buf + len);
  321. if (recv(fd, buf + len, val, 0) != val)
  322. goto error;
  323. len += val;
  324. if (end != NULL)
  325. break;
  326. }
  327. assert(len > 0);
  328. buf[--len] = '\0';
  329. if (len > 0 && buf[--len] == '\r')
  330. buf[len] = '\0';
  331. return buf;
  332. error:
  333. msg_Err(obj, "read error: %s", vlc_strerror_c(errno));
  334. free(buf);
  335. return NULL;
  336. }
  337. #undef net_Printf
  338. ssize_t net_Printf( vlc_object_t *p_this, int fd, const char *psz_fmt, ... )
  339. {
  340. int i_ret;
  341. va_list args;
  342. va_start( args, psz_fmt );
  343. i_ret = net_vaPrintf( p_this, fd, psz_fmt, args );
  344. va_end( args );
  345. return i_ret;
  346. }
  347. #undef net_vaPrintf
  348. ssize_t net_vaPrintf( vlc_object_t *p_this, int fd,
  349. const char *psz_fmt, va_list args )
  350. {
  351. char *psz;
  352. int i_ret;
  353. int i_size = vasprintf( &psz, psz_fmt, args );
  354. if( i_size == -1 )
  355. return -1;
  356. i_ret = net_Write( p_this, fd, psz, i_size ) < i_size
  357. ? -1 : i_size;
  358. free( psz );
  359. return i_ret;
  360. }