summaryrefslogtreecommitdiffstats
path: root/stream/tcp.c
diff options
context:
space:
mode:
authorben <ben@b3059339-0415-0410-9bf9-f77b7e298cf2>2006-08-05 10:30:06 +0000
committerben <ben@b3059339-0415-0410-9bf9-f77b7e298cf2>2006-08-05 10:30:06 +0000
commitd7b460956a351157b59a551a8c21cfc18bf11e69 (patch)
tree9733d7622666dccb56bc641dd3c9cf78825bc7c0 /stream/tcp.c
parentd3df3a773f3abd46c8f96a14c45c8d4a57ac71fb (diff)
downloadmpv-d7b460956a351157b59a551a8c21cfc18bf11e69.tar.bz2
mpv-d7b460956a351157b59a551a8c21cfc18bf11e69.tar.xz
isolated tcp socket code from network.c to a dedicated file
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@19341 b3059339-0415-0410-9bf9-f77b7e298cf2
Diffstat (limited to 'stream/tcp.c')
-rw-r--r--stream/tcp.c290
1 files changed, 290 insertions, 0 deletions
diff --git a/stream/tcp.c b/stream/tcp.c
new file mode 100644
index 0000000000..e34efbd412
--- /dev/null
+++ b/stream/tcp.c
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2001 Bertrand BAUDET, 2006 Benjamin Zores
+ * Network helpers for TCP connections
+ * (originally borrowed from network.c,
+ * by Bertrand BAUDET <bertrand_baudet@yahoo.com>).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#ifndef HAVE_WINSOCK2
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#define closesocket close
+#else
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#endif
+
+#include "mp_msg.h"
+#include "help_mp.h"
+#include "tcp.h"
+
+/* IPv6 options */
+int network_prefer_ipv4 = 0;
+
+/* Converts an address family constant to a string */
+static const char *
+af2String (int af)
+{
+ switch (af)
+ {
+ case AF_INET:
+ return "AF_INET";
+#ifdef HAVE_AF_INET6
+ case AF_INET6:
+ return "AF_INET6";
+#endif
+ default:
+ return "Unknown address family!";
+ }
+}
+
+static int
+connect2Server_with_af (char *host, int port, int af ,int verb)
+{
+ int socket_server_fd;
+ int err;
+ socklen_t err_len;
+ int ret, count = 0;
+ fd_set set;
+ struct timeval tv;
+
+ union {
+ struct sockaddr_in four;
+#ifdef HAVE_AF_INET6
+ struct sockaddr_in6 six;
+#endif
+ } server_address;
+
+ size_t server_address_size;
+ void *our_s_addr; /* Pointer to sin_addr or sin6_addr */
+ struct hostent *hp = NULL;
+ char buf[255];
+
+#ifdef HAVE_WINSOCK2
+ u_long val;
+#endif
+
+ socket_server_fd = socket (af, SOCK_STREAM, 0);
+ if (socket_server_fd == -1)
+ return TCP_ERROR_FATAL;
+
+ switch (af)
+ {
+ case AF_INET:
+ our_s_addr = (void *) &server_address.four.sin_addr;
+ break;
+#ifdef HAVE_AF_INET6
+ case AF_INET6:
+ our_s_addr = (void *) &server_address.six.sin6_addr;
+ break;
+#endif
+ default:
+ mp_msg (MSGT_NETWORK, MSGL_ERR, MSGTR_MPDEMUX_NW_UnknownAF, af);
+ return TCP_ERROR_FATAL;
+ }
+
+ memset (&server_address, 0, sizeof (server_address));
+
+#ifndef HAVE_WINSOCK2
+#ifdef USE_ATON
+ if (inet_aton (host, our_s_addr) !=1)
+#else
+ if (inet_pton (af, host, our_s_addr) !=1)
+#endif /* USE_ATON */
+#else
+ if (inet_addr (host) == INADDR_NONE)
+#endif /* HAVE_WINSOCK2 */
+ {
+ if (verb)
+ mp_msg (MSGT_NETWORK, MSGL_STATUS,
+ MSGTR_MPDEMUX_NW_ResolvingHostForAF, host, af2String (af));
+
+#ifdef HAVE_GETHOSTBYNAME2
+ hp = (struct hostent *) gethostbyname2 (host, af);
+#else
+ hp = (struct hostent *) gethostbyname (host);
+#endif /* HAVE_GETHOSTBYNAME2 */
+
+ if (!hp)
+ {
+ if (verb)
+ mp_msg (MSGT_NETWORK, MSGL_ERR,
+ MSGTR_MPDEMUX_NW_CantResolv, af2String (af), host);
+ return TCP_ERROR_FATAL;
+ }
+
+ memcpy (our_s_addr, (void *) hp->h_addr_list[0], hp->h_length);
+ }
+#ifdef HAVE_WINSOCK2
+ else
+ {
+ unsigned long addr = inet_addr (host);
+ memcpy (our_s_addr, (void *) &addr, sizeof (addr));
+ }
+#endif /* HAVE_WINSOCK2 */
+
+ switch (af)
+ {
+ case AF_INET:
+ server_address.four.sin_family = af;
+ server_address.four.sin_port = htons (port);
+ server_address_size = sizeof (server_address.four);
+ break;
+#ifdef HAVE_AF_INET6
+ case AF_INET6:
+ server_address.six.sin6_family = af;
+ server_address.six.sin6_port = htons (port);
+ server_address_size = sizeof (server_address.six);
+ break;
+#endif /* HAVE_AF_INET6 */
+ default:
+ mp_msg (MSGT_NETWORK, MSGL_ERR, MSGTR_MPDEMUX_NW_UnknownAF, af);
+ return TCP_ERROR_FATAL;
+ }
+
+#if defined(USE_ATON) || defined(HAVE_WINSOCK2)
+ strncpy (buf, inet_ntoa (*((struct in_addr *) our_s_addr)), 255);
+#else
+ inet_ntop (af, our_s_addr, buf, 255);
+#endif /* USE_ATON || HAVE_WINSOCK2 */
+
+ if (verb)
+ mp_msg (MSGT_NETWORK, MSGL_STATUS,
+ MSGTR_MPDEMUX_NW_ConnectingToServer, host, buf, port);
+
+ /* Turn the socket as non blocking so we can timeout on the connection */
+#ifndef HAVE_WINSOCK2
+ fcntl (socket_server_fd, F_SETFL,
+ fcntl (socket_server_fd, F_GETFL) | O_NONBLOCK);
+#else
+ val = 1;
+ ioctlsocket (socket_server_fd, FIONBIO, &val);
+#endif /* HAVE_WINSOCK2 */
+
+ if (connect (socket_server_fd, (struct sockaddr *) &server_address,
+ server_address_size) == -1)
+ {
+#ifndef HAVE_WINSOCK2
+ if (errno != EINPROGRESS)
+#else
+ if ((WSAGetLastError () != WSAEINPROGRESS)
+ && (WSAGetLastError () != WSAEWOULDBLOCK))
+#endif /* HAVE_WINSOCK2 */
+ {
+ if (verb)
+ mp_msg (MSGT_NETWORK, MSGL_ERR,
+ MSGTR_MPDEMUX_NW_CantConnect2Server, af2String (af));
+
+ closesocket (socket_server_fd);
+ return TCP_ERROR_PORT;
+ }
+ }
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 500000;
+
+ FD_ZERO (&set);
+ FD_SET (socket_server_fd, &set);
+
+ /* When the connection will be made, we will have a writable fd */
+ while ((ret = select (socket_server_fd + 1, NULL, &set, NULL, &tv)) == 0)
+ {
+ if (ret < 0)
+ mp_msg (MSGT_NETWORK, MSGL_ERR, MSGTR_MPDEMUX_NW_SelectFailed);
+ else if (ret > 0)
+ break;
+ else if (count > 30 || mp_input_check_interrupt (500))
+ {
+ if (count > 30)
+ mp_msg (MSGT_NETWORK, MSGL_ERR, MSGTR_MPDEMUX_NW_ConnTimeout);
+ else
+ mp_msg (MSGT_NETWORK, MSGL_V, "Connection interuppted by user\n");
+ return TCP_ERROR_TIMEOUT;
+ }
+
+ count++;
+ FD_ZERO (&set);
+ FD_SET (socket_server_fd, &set);
+ tv.tv_sec = 0;
+ tv.tv_usec = 500000;
+ }
+
+ /* Turn back the socket as blocking */
+#ifndef HAVE_WINSOCK2
+ fcntl (socket_server_fd, F_SETFL,
+ fcntl (socket_server_fd, F_GETFL) & ~O_NONBLOCK);
+#else
+ val = 0;
+ ioctlsocket (socket_server_fd, FIONBIO, &val);
+#endif /* HAVE_WINSOCK2 */
+
+ /* Check if there were any error */
+ err_len = sizeof (int);
+ ret = getsockopt (socket_server_fd, SOL_SOCKET, SO_ERROR, &err, &err_len);
+ if (ret < 0)
+ {
+ mp_msg (MSGT_NETWORK, MSGL_ERR,
+ MSGTR_MPDEMUX_NW_GetSockOptFailed, strerror (errno));
+ return TCP_ERROR_FATAL;
+ }
+
+ if (err > 0)
+ {
+ mp_msg (MSGT_NETWORK, MSGL_ERR,
+ MSGTR_MPDEMUX_NW_ConnectError, strerror (err));
+ return TCP_ERROR_PORT;
+ }
+
+ return socket_server_fd;
+}
+
+int
+connect2Server (char *host, int port, int verb)
+{
+#ifdef HAVE_AF_INET6
+ int r;
+ int s = TCP_ERROR_FATAL;
+
+ r = connect2Server_with_af (host, port,
+ network_prefer_ipv4 ? AF_INET:AF_INET6, verb);
+ if (r > TCP_ERROR_PORT)
+ return r;
+
+ s = connect2Server_with_af (host, port,
+ network_prefer_ipv4 ? AF_INET6:AF_INET, verb);
+ if (s == TCP_ERROR_FATAL)
+ return r;
+
+ return s;
+#else
+ return connect2Server_with_af (host, port, AF_INET,verb);
+#endif /* HAVE_AF_INET6 */
+}