File: | udp.c |
Location: | line 384, column 9 |
Description: | Function call argument is an uninitialized value |
1 | /***************************************************************************** | |||
2 | * udp.c: UDP input for DVBlast | |||
3 | ***************************************************************************** | |||
4 | * Copyright (C) 2009 VideoLAN | |||
5 | * | |||
6 | * Authors: Christophe Massiot <massiot@via.ecp.fr> | |||
7 | * | |||
8 | * This program is free software; you can redistribute it and/or modify | |||
9 | * it under the terms of the GNU General Public License as published by | |||
10 | * the Free Software Foundation; either version 2 of the License, or | |||
11 | * (at your option) any later version. | |||
12 | * | |||
13 | * This program is distributed in the hope that it will be useful, | |||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
16 | * GNU General Public License for more details. | |||
17 | * | |||
18 | * You should have received a copy of the GNU General Public License | |||
19 | * along with this program; if not, write to the Free Software | |||
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. | |||
21 | *****************************************************************************/ | |||
22 | ||||
23 | #include <stdlib.h> | |||
24 | #include <stdio.h> | |||
25 | #include <unistd.h> | |||
26 | #include <stdint.h> | |||
27 | #include <stdbool.h> | |||
28 | #include <string.h> | |||
29 | #include <sys/types.h> | |||
30 | #include <sys/stat.h> | |||
31 | #include <fcntl.h> | |||
32 | #include <sys/uio.h> | |||
33 | #include <sys/poll.h> | |||
34 | #include <sys/ioctl.h> | |||
35 | #include <sys/socket.h> | |||
36 | #include <netinet/in.h> | |||
37 | #include <net/if.h> | |||
38 | #include <arpa/inet.h> | |||
39 | #include <errno(*__errno_location ()).h> | |||
40 | ||||
41 | #include <bitstream/common.h> | |||
42 | #include <bitstream/ietf/rtp.h> | |||
43 | ||||
44 | #include "dvblast.h" | |||
45 | ||||
46 | /***************************************************************************** | |||
47 | * Local declarations | |||
48 | *****************************************************************************/ | |||
49 | #define UDP_LOCK_TIMEOUT5000000 5000000 /* 5 s */ | |||
50 | ||||
51 | static int i_handle; | |||
52 | static bool_Bool b_udp = false0; | |||
53 | static int i_block_cnt; | |||
54 | static uint8_t pi_ssrc[4] = { 0, 0, 0, 0 }; | |||
55 | static uint16_t i_seqnum = 0; | |||
56 | static mtime_t i_last_packet = 0; | |||
57 | ||||
58 | /***************************************************************************** | |||
59 | * udp_Open | |||
60 | *****************************************************************************/ | |||
61 | void udp_Open( void ) | |||
62 | { | |||
63 | int i_family; | |||
64 | struct addrinfo *p_connect_ai = NULL((void*)0), *p_bind_ai; | |||
65 | int i_if_index = 0; | |||
66 | in_addr_t i_if_addr = INADDR_ANY((in_addr_t) 0x00000000); | |||
67 | int i_mtu = 0; | |||
68 | char *psz_ifname = NULL((void*)0); | |||
69 | ||||
70 | char *psz_bind, *psz_string = strdup( psz_udp_src )(__extension__ (__builtin_constant_p (psz_udp_src) && ((size_t)(const void *)((psz_udp_src) + 1) - (size_t)(const void *)(psz_udp_src) == 1) ? (((const char *) (psz_udp_src))[0] == '\0' ? (char *) calloc ((size_t) 1, (size_t) 1) : ({ size_t __len = strlen (psz_udp_src) + 1; char *__retval = (char *) malloc (__len); if (__retval != ((void*)0)) __retval = (char *) memcpy (__retval, psz_udp_src, __len); __retval; })) : __strdup (psz_udp_src ))); | |||
71 | char *psz_save = psz_string; | |||
72 | int i = 1; | |||
73 | ||||
74 | /* Parse configuration. */ | |||
75 | ||||
76 | if ( (psz_bind = strchr( psz_string, '@' )(__extension__ (__builtin_constant_p ('@') && !__builtin_constant_p (psz_string) && ('@') == '\0' ? (char *) __rawmemchr (psz_string, '@') : __builtin_strchr (psz_string, '@')))) != NULL((void*)0) ) | |||
77 | { | |||
78 | *psz_bind++ = '\0'; | |||
79 | p_connect_ai = ParseNodeService( psz_string, NULL((void*)0), 0 ); | |||
80 | } | |||
81 | else | |||
82 | psz_bind = psz_string; | |||
83 | ||||
84 | p_bind_ai = ParseNodeService( psz_bind, &psz_string, DEFAULT_PORT3001 ); | |||
85 | if ( p_bind_ai == NULL((void*)0) ) | |||
86 | { | |||
87 | msg_Err( NULL((void*)0), "couldn't parse %s", psz_bind ); | |||
88 | exit(EXIT_FAILURE1); | |||
89 | } | |||
90 | i_family = p_bind_ai->ai_family; | |||
91 | ||||
92 | if ( p_connect_ai != NULL((void*)0) && p_connect_ai->ai_family != i_family ) | |||
93 | { | |||
94 | msg_Warn( NULL((void*)0), "invalid connect address" ); | |||
95 | freeaddrinfo( p_connect_ai ); | |||
96 | p_connect_ai = NULL((void*)0); | |||
97 | } | |||
98 | ||||
99 | while ( (psz_string = strchr( psz_string, '/' )(__extension__ (__builtin_constant_p ('/') && !__builtin_constant_p (psz_string) && ('/') == '\0' ? (char *) __rawmemchr (psz_string, '/') : __builtin_strchr (psz_string, '/')))) != NULL((void*)0) ) | |||
100 | { | |||
101 | *psz_string++ = '\0'; | |||
102 | ||||
103 | #define IS_OPTION( option ) (!strncasecmp( psz_string, option, strlen(option) )) | |||
104 | #define ARG_OPTION( option ) (psz_string + strlen(option)) | |||
105 | ||||
106 | if ( IS_OPTION("udp") ) | |||
107 | b_udp = true1; | |||
108 | else if ( IS_OPTION("mtu=") ) | |||
109 | i_mtu = strtol( ARG_OPTION("mtu="), NULL((void*)0), 0 ); | |||
110 | else if ( IS_OPTION("ifindex=") ) | |||
111 | i_if_index = strtol( ARG_OPTION("ifindex="), NULL((void*)0), 0 ); | |||
112 | else if ( IS_OPTION("ifaddr=") ) { | |||
113 | char *option = config_stropt( ARG_OPTION("ifaddr=") ); | |||
114 | i_if_addr = inet_addr( option ); | |||
115 | free( option ); | |||
116 | } | |||
117 | else if ( IS_OPTION("ifname=") ) | |||
118 | { | |||
119 | psz_ifname = config_stropt( ARG_OPTION("ifname=") ); | |||
120 | if (strlen(psz_ifname) >= IFNAMSIZ16) { | |||
121 | psz_ifname[IFNAMSIZ16-1] = '\0'; | |||
122 | } | |||
123 | } else | |||
124 | msg_Warn( NULL((void*)0), "unrecognized option %s", psz_string ); | |||
125 | ||||
126 | #undef IS_OPTION | |||
127 | #undef ARG_OPTION | |||
128 | } | |||
129 | ||||
130 | if ( !i_mtu ) | |||
131 | i_mtu = i_family == AF_INET610 ? DEFAULT_IPV6_MTU1280 : DEFAULT_IPV4_MTU1500; | |||
132 | i_block_cnt = (i_mtu - (b_udp ? 0 : RTP_HEADER_SIZE12)) / TS_SIZE188; | |||
133 | ||||
134 | ||||
135 | /* Do stuff. */ | |||
136 | ||||
137 | if ( (i_handle = socket( i_family, SOCK_DGRAMSOCK_DGRAM, IPPROTO_UDPIPPROTO_UDP )) < 0 ) | |||
138 | { | |||
139 | msg_Err( NULL((void*)0), "couldn't create socket (%s)", strerror(errno(*__errno_location ())) ); | |||
140 | exit(EXIT_FAILURE1); | |||
141 | } | |||
142 | ||||
143 | setsockopt( i_handle, SOL_SOCKET1, SO_REUSEADDR2, (void *) &i, sizeof( i ) ); | |||
144 | ||||
145 | /* Increase the receive buffer size to 1/2MB (8Mb/s during 1/2s) to avoid | |||
146 | * packet loss caused by scheduling problems */ | |||
147 | i = 0x80000; | |||
148 | ||||
149 | setsockopt( i_handle, SOL_SOCKET1, SO_RCVBUF8, (void *) &i, sizeof( i ) ); | |||
150 | ||||
151 | if ( bind( i_handle, p_bind_ai->ai_addr, p_bind_ai->ai_addrlen ) < 0 ) | |||
152 | { | |||
153 | msg_Err( NULL((void*)0), "couldn't bind (%s)", strerror(errno(*__errno_location ())) ); | |||
154 | close( i_handle ); | |||
155 | exit(EXIT_FAILURE1); | |||
156 | } | |||
157 | ||||
158 | if ( p_connect_ai != NULL((void*)0) ) | |||
159 | { | |||
160 | uint16_t i_port; | |||
161 | if ( i_family == AF_INET610 ) | |||
162 | i_port = ((struct sockaddr_in6 *)p_connect_ai->ai_addr)->sin6_port; | |||
163 | else | |||
164 | i_port = ((struct sockaddr_in *)p_connect_ai->ai_addr)->sin_port; | |||
165 | ||||
166 | if ( i_port != 0 && connect( i_handle, p_connect_ai->ai_addr, | |||
167 | p_connect_ai->ai_addrlen ) < 0 ) | |||
168 | msg_Warn( NULL((void*)0), "couldn't connect socket (%s)", strerror(errno(*__errno_location ())) ); | |||
169 | } | |||
170 | ||||
171 | /* Join the multicast group if the socket is a multicast address */ | |||
172 | if ( i_family == AF_INET610 ) | |||
173 | { | |||
174 | struct sockaddr_in6 *p_addr = | |||
175 | (struct sockaddr_in6 *)p_bind_ai->ai_addr; | |||
176 | if ( IN6_IS_ADDR_MULTICAST( &p_addr->sin6_addr )(((const uint8_t *) (&p_addr->sin6_addr))[0] == 0xff) ) | |||
177 | { | |||
178 | struct ipv6_mreq imr; | |||
179 | imr.ipv6mr_multiaddr = p_addr->sin6_addr; | |||
180 | imr.ipv6mr_interface = i_if_index; | |||
181 | if ( i_if_addr != INADDR_ANY((in_addr_t) 0x00000000) ) | |||
182 | msg_Warn( NULL((void*)0), "ignoring ifaddr option in IPv6" ); | |||
183 | ||||
184 | if ( setsockopt( i_handle, IPPROTO_IPV6IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP20, | |||
185 | (char *)&imr, sizeof(struct ipv6_mreq) ) < 0 ) | |||
186 | msg_Warn( NULL((void*)0), "couldn't join multicast group (%s)", | |||
187 | strerror(errno(*__errno_location ())) ); | |||
188 | } | |||
189 | } | |||
190 | else | |||
191 | { | |||
192 | struct sockaddr_in *p_addr = | |||
193 | (struct sockaddr_in *)p_bind_ai->ai_addr; | |||
194 | if ( IN_MULTICAST( ntohl(p_addr->sin_addr.s_addr))((((in_addr_t)((__extension__ ({ unsigned int __v, __x = (p_addr ->sin_addr.s_addr); if (__builtin_constant_p (__x)) __v = ( (((__x) & 0xff000000) >> 24) | (((__x) & 0x00ff0000 ) >> 8) | (((__x) & 0x0000ff00) << 8) | (((__x ) & 0x000000ff) << 24)); else __asm__ ("bswap %0" : "=r" (__v) : "0" (__x)); __v; })))) & 0xf0000000) == 0xe0000000 ) ) | |||
195 | { | |||
196 | if ( p_connect_ai != NULL((void*)0) ) | |||
197 | { | |||
198 | #ifndef IP_ADD_SOURCE_MEMBERSHIP39 | |||
199 | msg_Err( NULL((void*)0), "IP_ADD_SOURCE_MEMBERSHIP is unsupported." ); | |||
200 | #else | |||
201 | /* Source-specific multicast */ | |||
202 | struct sockaddr *p_src = p_connect_ai->ai_addr; | |||
203 | struct ip_mreq_source imr; | |||
204 | imr.imr_multiaddr = p_addr->sin_addr; | |||
205 | imr.imr_interface.s_addr = i_if_addr; | |||
206 | imr.imr_sourceaddr = ((struct sockaddr_in *)p_src)->sin_addr; | |||
207 | if ( i_if_index ) | |||
208 | msg_Warn( NULL((void*)0), "ignoring ifindex option in SSM" ); | |||
209 | ||||
210 | if ( setsockopt( i_handle, IPPROTO_IPIPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP39, | |||
211 | (char *)&imr, sizeof(struct ip_mreq_source) ) < 0 ) | |||
212 | msg_Warn( NULL((void*)0), "couldn't join multicast group (%s)", | |||
213 | strerror(errno(*__errno_location ())) ); | |||
214 | #endif | |||
215 | } | |||
216 | else if ( i_if_index ) | |||
217 | { | |||
218 | /* Linux-specific interface-bound multicast */ | |||
219 | struct ip_mreqn imr; | |||
220 | imr.imr_multiaddr = p_addr->sin_addr; | |||
221 | #if defined(__linux__1) | |||
222 | imr.imr_address.s_addr = i_if_addr; | |||
223 | imr.imr_ifindex = i_if_index; | |||
224 | #endif | |||
225 | ||||
226 | if ( setsockopt( i_handle, IPPROTO_IPIPPROTO_IP, IP_ADD_MEMBERSHIP35, | |||
227 | (char *)&imr, sizeof(struct ip_mreqn) ) < 0 ) | |||
228 | msg_Warn( NULL((void*)0), "couldn't join multicast group (%s)", | |||
229 | strerror(errno(*__errno_location ())) ); | |||
230 | } | |||
231 | else | |||
232 | { | |||
233 | /* Regular multicast */ | |||
234 | struct ip_mreq imr; | |||
235 | imr.imr_multiaddr = p_addr->sin_addr; | |||
236 | imr.imr_interface.s_addr = i_if_addr; | |||
237 | ||||
238 | if ( setsockopt( i_handle, IPPROTO_IPIPPROTO_IP, IP_ADD_MEMBERSHIP35, | |||
239 | (char *)&imr, sizeof(struct ip_mreq) ) == -1 ) | |||
240 | msg_Warn( NULL((void*)0), "couldn't join multicast group (%s)", | |||
241 | strerror(errno(*__errno_location ())) ); | |||
242 | } | |||
243 | #ifdef SO_BINDTODEVICE25 | |||
244 | if (psz_ifname) { | |||
245 | if ( setsockopt( i_handle, SOL_SOCKET1, SO_BINDTODEVICE25, | |||
246 | psz_ifname, strlen(psz_ifname)+1 ) < 0 ) { | |||
247 | msg_Err( NULL((void*)0), "couldn't bind to device %s (%s)", | |||
248 | psz_ifname, strerror(errno(*__errno_location ())) ); | |||
249 | } | |||
250 | free(psz_ifname); | |||
251 | psz_ifname = NULL((void*)0); | |||
252 | } | |||
253 | #endif | |||
254 | } | |||
255 | } | |||
256 | ||||
257 | freeaddrinfo( p_bind_ai ); | |||
258 | if ( p_connect_ai != NULL((void*)0) ) | |||
259 | freeaddrinfo( p_connect_ai ); | |||
260 | free( psz_save ); | |||
261 | ||||
262 | msg_Dbg( NULL((void*)0), "binding socket to %s", psz_udp_src ); | |||
263 | } | |||
264 | ||||
265 | /***************************************************************************** | |||
266 | * udp_Read | |||
267 | *****************************************************************************/ | |||
268 | block_t *udp_Read( mtime_t i_poll_timeout ) | |||
269 | { | |||
270 | struct pollfd pfd[2]; | |||
271 | int i_ret, i_nb_fd = 1; | |||
272 | ||||
273 | pfd[0].fd = i_handle; | |||
274 | pfd[0].events = POLLIN0x001; | |||
275 | if ( i_comm_fd != -1 ) | |||
| ||||
276 | { | |||
277 | pfd[1].fd = i_comm_fd; | |||
278 | pfd[1].events = POLLIN0x001; | |||
279 | i_nb_fd++; | |||
280 | } | |||
281 | ||||
282 | i_ret = poll( pfd, i_nb_fd, (i_poll_timeout + 999) / 1000 ); | |||
283 | ||||
284 | i_wallclock = mdate(); | |||
285 | ||||
286 | if ( i_ret < 0 ) | |||
287 | { | |||
288 | if( errno(*__errno_location ()) != EINTR4 ) | |||
289 | msg_Err( NULL((void*)0), "couldn't poll from socket (%s)", | |||
290 | strerror(errno(*__errno_location ())) ); | |||
291 | return NULL((void*)0); | |||
292 | } | |||
293 | ||||
294 | if ( pfd[0].revents ) | |||
295 | { | |||
296 | struct iovec p_iov[i_block_cnt + 1]; | |||
297 | block_t *p_ts, **pp_current = &p_ts; | |||
298 | int i_iov, i_block; | |||
299 | ssize_t i_len; | |||
300 | uint8_t p_rtp_hdr[RTP_HEADER_SIZE12]; | |||
301 | ||||
302 | if ( !i_last_packet ) | |||
303 | { | |||
304 | switch (i_print_type) { | |||
305 | case PRINT_XML: | |||
306 | printf("<STATUS type=\"lock\" status=\"1\"/>\n"); | |||
307 | break; | |||
308 | default: | |||
309 | printf("frontend has acquired lock\n" ); | |||
310 | } | |||
311 | } | |||
312 | i_last_packet = i_wallclock; | |||
313 | ||||
314 | if ( !b_udp ) | |||
315 | { | |||
316 | /* FIXME : this is wrong if RTP header > 12 bytes */ | |||
317 | p_iov[0].iov_base = p_rtp_hdr; | |||
318 | p_iov[0].iov_len = RTP_HEADER_SIZE12; | |||
319 | i_iov = 1; | |||
320 | } | |||
321 | else | |||
322 | i_iov = 0; | |||
323 | ||||
324 | for ( i_block = 0; i_block < i_block_cnt; i_block++ ) | |||
325 | { | |||
326 | *pp_current = block_New(); | |||
327 | p_iov[i_iov].iov_base = (*pp_current)->p_ts; | |||
328 | p_iov[i_iov].iov_len = TS_SIZE188; | |||
329 | pp_current = &(*pp_current)->p_next; | |||
330 | i_iov++; | |||
331 | } | |||
332 | pp_current = &p_ts; | |||
333 | ||||
334 | if ( (i_len = readv( i_handle, p_iov, i_iov )) < 0 ) | |||
335 | { | |||
336 | msg_Err( NULL((void*)0), "couldn't read from network (%s)", strerror(errno(*__errno_location ())) ); | |||
337 | goto err; | |||
338 | } | |||
339 | ||||
340 | if ( !b_udp ) | |||
341 | { | |||
342 | uint8_t pi_new_ssrc[4]; | |||
343 | ||||
344 | if ( !rtp_check_hdr(p_rtp_hdr) ) | |||
345 | msg_Warn( NULL((void*)0), "invalid RTP packet received" ); | |||
346 | if ( rtp_get_type(p_rtp_hdr) != RTP_TYPE_TS33 ) | |||
347 | msg_Warn( NULL((void*)0), "non-TS RTP packet received" ); | |||
348 | rtp_get_ssrc(p_rtp_hdr, pi_new_ssrc); | |||
349 | if ( !memcmp( pi_ssrc, pi_new_ssrc, 4 * sizeof(uint8_t) ) ) | |||
350 | { | |||
351 | if ( rtp_get_seqnum(p_rtp_hdr) != i_seqnum ) | |||
352 | msg_Warn( NULL((void*)0), "RTP discontinuity" ); | |||
353 | } | |||
354 | else | |||
355 | { | |||
356 | struct in_addr addr; | |||
357 | memcpy( &addr.s_addr, pi_new_ssrc, 4 * sizeof(uint8_t) ); | |||
358 | msg_Dbg( NULL((void*)0), "new RTP source: %s", inet_ntoa( addr ) ); | |||
359 | memcpy( pi_ssrc, pi_new_ssrc, 4 * sizeof(uint8_t) ); | |||
360 | switch (i_print_type) { | |||
361 | case PRINT_XML: | |||
362 | printf("<STATUS type=\"source\" source=\"%s\"/>\n", | |||
363 | inet_ntoa( addr )); | |||
364 | break; | |||
365 | default: | |||
366 | printf("new RTP source: %s\n", inet_ntoa( addr ) ); | |||
367 | } | |||
368 | } | |||
369 | i_seqnum = rtp_get_seqnum(p_rtp_hdr) + 1; | |||
370 | ||||
371 | i_len -= RTP_HEADER_SIZE12; | |||
372 | } | |||
373 | ||||
374 | i_len /= TS_SIZE188; | |||
375 | ||||
376 | while ( i_len && *pp_current ) | |||
377 | { | |||
378 | pp_current = &(*pp_current)->p_next; | |||
379 | i_len--; | |||
380 | } | |||
381 | ||||
382 | i_wallclock = mdate(); | |||
383 | err: | |||
384 | block_DeleteChain( *pp_current ); | |||
| ||||
385 | *pp_current = NULL((void*)0); | |||
386 | ||||
387 | return p_ts; | |||
388 | } | |||
389 | else if ( i_last_packet && i_last_packet + UDP_LOCK_TIMEOUT5000000 < i_wallclock ) | |||
390 | { | |||
391 | switch (i_print_type) { | |||
392 | case PRINT_XML: | |||
393 | printf("<STATUS type=\"lock\" status=\"0\"/>\n"); | |||
394 | break; | |||
395 | default: | |||
396 | printf("frontend has lost lock\n" ); | |||
397 | } | |||
398 | i_last_packet = 0; | |||
399 | } | |||
400 | ||||
401 | if ( i_comm_fd != -1 && pfd[1].revents ) | |||
402 | comm_Read(); | |||
403 | ||||
404 | return NULL((void*)0); | |||
405 | } | |||
406 | ||||
407 | /* From now on these are just stubs */ | |||
408 | ||||
409 | /***************************************************************************** | |||
410 | * udp_SetFilter | |||
411 | *****************************************************************************/ | |||
412 | int udp_SetFilter( uint16_t i_pid ) | |||
413 | { | |||
414 | return -1; | |||
415 | } | |||
416 | ||||
417 | /***************************************************************************** | |||
418 | * udp_UnsetFilter: normally never called | |||
419 | *****************************************************************************/ | |||
420 | void udp_UnsetFilter( int i_fd, uint16_t i_pid ) | |||
421 | { | |||
422 | } | |||
423 | ||||
424 | /***************************************************************************** | |||
425 | * udp_Reset: | |||
426 | *****************************************************************************/ | |||
427 | void udp_Reset( void ) | |||
428 | { | |||
429 | } | |||
430 |