Mercurial > mplayer.hg
annotate stream/tcp.c @ 29588:17d7ae586d03
Reduce code duplication for half/normal/double video size handling.
author | reimar |
---|---|
date | Wed, 02 Sep 2009 14:02:15 +0000 |
parents | d58878f243ea |
children | ce0122361a39 |
rev | line source |
---|---|
19542 | 1 /* |
2 * Network layer for MPlayer | |
3 * by Bertrand BAUDET <bertrand_baudet@yahoo.com> | |
4 * (C) 2001, MPlayer team. | |
5 */ | |
6 | |
7 #include <stdlib.h> | |
8 #include <string.h> | |
9 #include <unistd.h> | |
10 | |
11 #include <errno.h> | |
12 #include <ctype.h> | |
13 | |
14 #include <fcntl.h> | |
15 #include <sys/time.h> | |
16 #include <sys/types.h> | |
17 | |
18 #include "config.h" | |
19 | |
20 #include "mp_msg.h" | |
21 #include "help_mp.h" | |
27472
c0b233cd30ca
Revert moving closesocket definition and network headers to network.h.
diego
parents:
27464
diff
changeset
|
22 |
28402 | 23 #if !HAVE_WINSOCK2_H |
27472
c0b233cd30ca
Revert moving closesocket definition and network headers to network.h.
diego
parents:
27464
diff
changeset
|
24 #include <netdb.h> |
c0b233cd30ca
Revert moving closesocket definition and network headers to network.h.
diego
parents:
27464
diff
changeset
|
25 #include <netinet/in.h> |
c0b233cd30ca
Revert moving closesocket definition and network headers to network.h.
diego
parents:
27464
diff
changeset
|
26 #include <sys/socket.h> |
c0b233cd30ca
Revert moving closesocket definition and network headers to network.h.
diego
parents:
27464
diff
changeset
|
27 #include <arpa/inet.h> |
c0b233cd30ca
Revert moving closesocket definition and network headers to network.h.
diego
parents:
27464
diff
changeset
|
28 #else |
c0b233cd30ca
Revert moving closesocket definition and network headers to network.h.
diego
parents:
27464
diff
changeset
|
29 #include <winsock2.h> |
c0b233cd30ca
Revert moving closesocket definition and network headers to network.h.
diego
parents:
27464
diff
changeset
|
30 #include <ws2tcpip.h> |
c0b233cd30ca
Revert moving closesocket definition and network headers to network.h.
diego
parents:
27464
diff
changeset
|
31 #endif |
c0b233cd30ca
Revert moving closesocket definition and network headers to network.h.
diego
parents:
27464
diff
changeset
|
32 |
27473
ae5da477539e
Move '#define closesocket close' preprocessor directive to a common place
diego
parents:
27472
diff
changeset
|
33 #include "network.h" |
26751 | 34 #include "stream.h" |
19542 | 35 #include "tcp.h" |
29351 | 36 #include "libavutil/avstring.h" |
19542 | 37 |
38 /* IPv6 options */ | |
39 int network_prefer_ipv4 = 0; | |
40 | |
41 // Converts an address family constant to a string | |
42 | |
24841
44540930bf94
Make functions static if they aren't referenced externally.
zuxy
parents:
24559
diff
changeset
|
43 static const char *af2String(int af) { |
19542 | 44 switch (af) { |
45 case AF_INET: return "AF_INET"; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28404
diff
changeset
|
46 |
19542 | 47 #ifdef HAVE_AF_INET6 |
48 case AF_INET6: return "AF_INET6"; | |
49 #endif | |
50 default: return "Unknown address family!"; | |
51 } | |
52 } | |
53 | |
54 | |
55 | |
56 // Connect to a server using a TCP connection, with specified address family | |
57 // return -2 for fatal error, like unable to resolve name, connection timeout... | |
58 // return -1 is unable to connect to a particular port | |
59 | |
24841
44540930bf94
Make functions static if they aren't referenced externally.
zuxy
parents:
24559
diff
changeset
|
60 static int |
19542 | 61 connect2Server_with_af(char *host, int port, int af,int verb) { |
62 int socket_server_fd; | |
63 int err; | |
64 socklen_t err_len; | |
65 int ret,count = 0; | |
66 fd_set set; | |
67 struct timeval tv; | |
68 union { | |
69 struct sockaddr_in four; | |
70 #ifdef HAVE_AF_INET6 | |
71 struct sockaddr_in6 six; | |
72 #endif | |
73 } server_address; | |
74 size_t server_address_size; | |
75 void *our_s_addr; // Pointer to sin_addr or sin6_addr | |
76 struct hostent *hp=NULL; | |
77 char buf[255]; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28404
diff
changeset
|
78 |
28402 | 79 #if HAVE_WINSOCK2_H |
28162 | 80 unsigned long val; |
22379
6b245d6e56a9
winsocks expects an int in milliseconds instead of struct timeval to set
ivo
parents:
22142
diff
changeset
|
81 int to; |
6b245d6e56a9
winsocks expects an int in milliseconds instead of struct timeval to set
ivo
parents:
22142
diff
changeset
|
82 #else |
6b245d6e56a9
winsocks expects an int in milliseconds instead of struct timeval to set
ivo
parents:
22142
diff
changeset
|
83 struct timeval to; |
19542 | 84 #endif |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28404
diff
changeset
|
85 |
19542 | 86 socket_server_fd = socket(af, SOCK_STREAM, 0); |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28404
diff
changeset
|
87 |
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28404
diff
changeset
|
88 |
19542 | 89 if( socket_server_fd==-1 ) { |
90 // mp_msg(MSGT_NETWORK,MSGL_ERR,"Failed to create %s socket:\n", af2String(af)); | |
19543
e053647fbeec
Cosmetics: recommit patch changing return values to defines
reimar
parents:
19542
diff
changeset
|
91 return TCP_ERROR_FATAL; |
19542 | 92 } |
93 | |
22114 | 94 #if defined(SO_RCVTIMEO) && defined(SO_SNDTIMEO) |
28402 | 95 #if HAVE_WINSOCK2_H |
22379
6b245d6e56a9
winsocks expects an int in milliseconds instead of struct timeval to set
ivo
parents:
22142
diff
changeset
|
96 /* timeout in milliseconds */ |
6b245d6e56a9
winsocks expects an int in milliseconds instead of struct timeval to set
ivo
parents:
22142
diff
changeset
|
97 to = 10 * 1000; |
6b245d6e56a9
winsocks expects an int in milliseconds instead of struct timeval to set
ivo
parents:
22142
diff
changeset
|
98 #else |
6b245d6e56a9
winsocks expects an int in milliseconds instead of struct timeval to set
ivo
parents:
22142
diff
changeset
|
99 to.tv_sec = 10; |
6b245d6e56a9
winsocks expects an int in milliseconds instead of struct timeval to set
ivo
parents:
22142
diff
changeset
|
100 to.tv_usec = 0; |
6b245d6e56a9
winsocks expects an int in milliseconds instead of struct timeval to set
ivo
parents:
22142
diff
changeset
|
101 #endif |
6b245d6e56a9
winsocks expects an int in milliseconds instead of struct timeval to set
ivo
parents:
22142
diff
changeset
|
102 setsockopt(socket_server_fd, SOL_SOCKET, SO_RCVTIMEO, &to, sizeof(to)); |
6b245d6e56a9
winsocks expects an int in milliseconds instead of struct timeval to set
ivo
parents:
22142
diff
changeset
|
103 setsockopt(socket_server_fd, SOL_SOCKET, SO_SNDTIMEO, &to, sizeof(to)); |
22113
50c9dc00154d
Add timeout to tcp connections, avoid hanging forever.
rtogni
parents:
19543
diff
changeset
|
104 #endif |
50c9dc00154d
Add timeout to tcp connections, avoid hanging forever.
rtogni
parents:
19543
diff
changeset
|
105 |
19542 | 106 switch (af) { |
107 case AF_INET: our_s_addr = (void *) &server_address.four.sin_addr; break; | |
108 #ifdef HAVE_AF_INET6 | |
109 case AF_INET6: our_s_addr = (void *) &server_address.six.sin6_addr; break; | |
110 #endif | |
111 default: | |
112 mp_msg(MSGT_NETWORK,MSGL_ERR, MSGTR_MPDEMUX_NW_UnknownAF, af); | |
19543
e053647fbeec
Cosmetics: recommit patch changing return values to defines
reimar
parents:
19542
diff
changeset
|
113 return TCP_ERROR_FATAL; |
19542 | 114 } |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28404
diff
changeset
|
115 |
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28404
diff
changeset
|
116 |
19542 | 117 memset(&server_address, 0, sizeof(server_address)); |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28404
diff
changeset
|
118 |
28404
613f075b4ef0
Restructure network tests: Always check for both inet_aton and inet_pton.
diego
parents:
28402
diff
changeset
|
119 #if HAVE_INET_PTON |
613f075b4ef0
Restructure network tests: Always check for both inet_aton and inet_pton.
diego
parents:
28402
diff
changeset
|
120 if (inet_pton(af, host, our_s_addr)!=1) |
613f075b4ef0
Restructure network tests: Always check for both inet_aton and inet_pton.
diego
parents:
28402
diff
changeset
|
121 #elif HAVE_INET_ATON |
19542 | 122 if (inet_aton(host, our_s_addr)!=1) |
28404
613f075b4ef0
Restructure network tests: Always check for both inet_aton and inet_pton.
diego
parents:
28402
diff
changeset
|
123 #elif HAVE_WINSOCK2_H |
19542 | 124 if ( inet_addr(host)==INADDR_NONE ) |
125 #endif | |
126 { | |
127 if(verb) mp_msg(MSGT_NETWORK,MSGL_STATUS,MSGTR_MPDEMUX_NW_ResolvingHostForAF, host, af2String(af)); | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28404
diff
changeset
|
128 |
19542 | 129 #ifdef HAVE_GETHOSTBYNAME2 |
130 hp=(struct hostent*)gethostbyname2( host, af ); | |
131 #else | |
132 hp=(struct hostent*)gethostbyname( host ); | |
133 #endif | |
134 if( hp==NULL ) { | |
135 if(verb) mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_CantResolv, af2String(af), host); | |
19543
e053647fbeec
Cosmetics: recommit patch changing return values to defines
reimar
parents:
19542
diff
changeset
|
136 return TCP_ERROR_FATAL; |
19542 | 137 } |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28404
diff
changeset
|
138 |
19542 | 139 memcpy( our_s_addr, (void*)hp->h_addr_list[0], hp->h_length ); |
140 } | |
28402 | 141 #if HAVE_WINSOCK2_H |
19542 | 142 else { |
143 unsigned long addr = inet_addr(host); | |
144 memcpy( our_s_addr, (void*)&addr, sizeof(addr) ); | |
145 } | |
146 #endif | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28404
diff
changeset
|
147 |
19542 | 148 switch (af) { |
149 case AF_INET: | |
150 server_address.four.sin_family=af; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28404
diff
changeset
|
151 server_address.four.sin_port=htons(port); |
19542 | 152 server_address_size = sizeof(server_address.four); |
153 break; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28404
diff
changeset
|
154 #ifdef HAVE_AF_INET6 |
19542 | 155 case AF_INET6: |
156 server_address.six.sin6_family=af; | |
157 server_address.six.sin6_port=htons(port); | |
158 server_address_size = sizeof(server_address.six); | |
159 break; | |
160 #endif | |
161 default: | |
162 mp_msg(MSGT_NETWORK,MSGL_ERR, MSGTR_MPDEMUX_NW_UnknownAF, af); | |
19543
e053647fbeec
Cosmetics: recommit patch changing return values to defines
reimar
parents:
19542
diff
changeset
|
163 return TCP_ERROR_FATAL; |
19542 | 164 } |
165 | |
28400
9202b9245819
HAVE_ATON --> HAVE_INET_ATON to match FFmpeg and give it a 0/1 value.
diego
parents:
28162
diff
changeset
|
166 #if HAVE_INET_ATON || defined(HAVE_WINSOCK2_H) |
29351 | 167 av_strlcpy( buf, inet_ntoa( *((struct in_addr*)our_s_addr) ), 255); |
19542 | 168 #else |
169 inet_ntop(af, our_s_addr, buf, 255); | |
170 #endif | |
171 if(verb) mp_msg(MSGT_NETWORK,MSGL_STATUS,MSGTR_MPDEMUX_NW_ConnectingToServer, host, buf , port ); | |
172 | |
173 // Turn the socket as non blocking so we can timeout on the connection | |
28402 | 174 #if !HAVE_WINSOCK2_H |
19542 | 175 fcntl( socket_server_fd, F_SETFL, fcntl(socket_server_fd, F_GETFL) | O_NONBLOCK ); |
176 #else | |
177 val = 1; | |
178 ioctlsocket( socket_server_fd, FIONBIO, &val ); | |
179 #endif | |
180 if( connect( socket_server_fd, (struct sockaddr*)&server_address, server_address_size )==-1 ) { | |
28402 | 181 #if !HAVE_WINSOCK2_H |
19542 | 182 if( errno!=EINPROGRESS ) { |
183 #else | |
184 if( (WSAGetLastError() != WSAEINPROGRESS) && (WSAGetLastError() != WSAEWOULDBLOCK) ) { | |
185 #endif | |
186 if(verb) mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_CantConnect2Server, af2String(af)); | |
187 closesocket(socket_server_fd); | |
19543
e053647fbeec
Cosmetics: recommit patch changing return values to defines
reimar
parents:
19542
diff
changeset
|
188 return TCP_ERROR_PORT; |
19542 | 189 } |
190 } | |
191 tv.tv_sec = 0; | |
192 tv.tv_usec = 500000; | |
193 FD_ZERO( &set ); | |
194 FD_SET( socket_server_fd, &set ); | |
24558 | 195 // When the connection will be made, we will have a writeable fd |
19542 | 196 while((ret = select(socket_server_fd+1, NULL, &set, NULL, &tv)) == 0) { |
26326
5bfc1d8bece9
Remove the need for code using stream to export an mp_input_check_interrupt()
albeu
parents:
24841
diff
changeset
|
197 if(count > 30 || stream_check_interrupt(500)) { |
19542 | 198 if(count > 30) |
199 mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_ConnTimeout); | |
200 else | |
24558 | 201 mp_msg(MSGT_NETWORK,MSGL_V,"Connection interrupted by user\n"); |
19543
e053647fbeec
Cosmetics: recommit patch changing return values to defines
reimar
parents:
19542
diff
changeset
|
202 return TCP_ERROR_TIMEOUT; |
19542 | 203 } |
204 count++; | |
205 FD_ZERO( &set ); | |
206 FD_SET( socket_server_fd, &set ); | |
207 tv.tv_sec = 0; | |
208 tv.tv_usec = 500000; | |
209 } | |
24559
7b6a3948f5f2
(Re)move idiotic checks, ret can't be < 0 or > 0 if the loop condition
reimar
parents:
24558
diff
changeset
|
210 if (ret < 0) mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_SelectFailed); |
19542 | 211 |
212 // Turn back the socket as blocking | |
28402 | 213 #if !HAVE_WINSOCK2_H |
19542 | 214 fcntl( socket_server_fd, F_SETFL, fcntl(socket_server_fd, F_GETFL) & ~O_NONBLOCK ); |
215 #else | |
216 val = 0; | |
217 ioctlsocket( socket_server_fd, FIONBIO, &val ); | |
218 #endif | |
24558 | 219 // Check if there were any errors |
19542 | 220 err_len = sizeof(int); |
221 ret = getsockopt(socket_server_fd,SOL_SOCKET,SO_ERROR,&err,&err_len); | |
222 if(ret < 0) { | |
223 mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_GetSockOptFailed,strerror(errno)); | |
19543
e053647fbeec
Cosmetics: recommit patch changing return values to defines
reimar
parents:
19542
diff
changeset
|
224 return TCP_ERROR_FATAL; |
19542 | 225 } |
226 if(err > 0) { | |
227 mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_ConnectError,strerror(err)); | |
19543
e053647fbeec
Cosmetics: recommit patch changing return values to defines
reimar
parents:
19542
diff
changeset
|
228 return TCP_ERROR_PORT; |
19542 | 229 } |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28404
diff
changeset
|
230 |
19542 | 231 return socket_server_fd; |
232 } | |
233 | |
234 // Connect to a server using a TCP connection | |
235 // return -2 for fatal error, like unable to resolve name, connection timeout... | |
236 // return -1 is unable to connect to a particular port | |
237 | |
238 | |
239 int | |
240 connect2Server(char *host, int port, int verb) { | |
241 #ifdef HAVE_AF_INET6 | |
242 int r; | |
19543
e053647fbeec
Cosmetics: recommit patch changing return values to defines
reimar
parents:
19542
diff
changeset
|
243 int s = TCP_ERROR_FATAL; |
19542 | 244 |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28404
diff
changeset
|
245 r = connect2Server_with_af(host, port, network_prefer_ipv4 ? AF_INET:AF_INET6,verb); |
19543
e053647fbeec
Cosmetics: recommit patch changing return values to defines
reimar
parents:
19542
diff
changeset
|
246 if (r >= 0) return r; |
19542 | 247 |
248 s = connect2Server_with_af(host, port, network_prefer_ipv4 ? AF_INET6:AF_INET,verb); | |
19543
e053647fbeec
Cosmetics: recommit patch changing return values to defines
reimar
parents:
19542
diff
changeset
|
249 if (s == TCP_ERROR_FATAL) return r; |
19542 | 250 return s; |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28404
diff
changeset
|
251 #else |
19542 | 252 return connect2Server_with_af(host, port, AF_INET,verb); |
253 #endif | |
254 | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28404
diff
changeset
|
255 |
19542 | 256 } |