1 /*****************************************************************************
2 * udp.c: raw UDP input module
3 *****************************************************************************
4 * Copyright (C) 2001-2005 VLC authors and VideoLAN
5 * Copyright (C) 2007 Remi Denis-Courmont
8 * Authors: Christophe Massiot <massiot@via.ecp.fr>
9 * Tristan Leteurtre <tooney@via.ecp.fr>
10 * Laurent Aimar <fenrir@via.ecp.fr>
11 * Jean-Paul Saman <jpsaman #_at_# m2x dot nl>
14 * Reviewed: 23 October 2003, Jean-Paul Saman <jpsaman _at_ videolan _dot_ org>
16 * This program is free software; you can redistribute it and/or modify it
17 * under the terms of the GNU Lesser General Public License as published by
18 * the Free Software Foundation; either version 2.1 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU Lesser General Public License for more details.
26 * You should have received a copy of the GNU Lesser General Public License
27 * along with this program; if not, write to the Free Software Foundation,
28 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
29 *****************************************************************************/
31 /*****************************************************************************
33 *****************************************************************************/
40 #include <vlc_common.h>
41 #include <vlc_plugin.h>
42 #include <vlc_access.h>
43 #include <vlc_network.h>
44 #include <vlc_block.h>
45 #include <vlc_interrupt.h>
53 /*****************************************************************************
55 *****************************************************************************/
56 static int Open( vlc_object_t
* );
57 static void Close( vlc_object_t
* );
59 #define BUFFER_TEXT N_("Receive buffer")
60 #define BUFFER_LONGTEXT N_("UDP receive buffer size (bytes)" )
61 #define TIMEOUT_TEXT N_("UDP Source timeout (sec)")
64 set_shortname( N_("UDP" ) )
65 set_description( N_("UDP input") )
66 set_category( CAT_INPUT
)
67 set_subcategory( SUBCAT_INPUT_ACCESS
)
69 add_obsolete_integer( "server-port" ) /* since 2.0.0 */
70 add_obsolete_integer( "udp-buffer" ) /* since 3.0.0 */
71 add_integer( "udp-timeout", -1, TIMEOUT_TEXT
, NULL
, true )
73 set_capability( "access", 0 )
74 add_shortcut( "udp", "udpstream", "udp4", "udp6" )
76 set_callbacks( Open
, Close
)
84 block_t
*overflow_block
;
87 /*****************************************************************************
89 *****************************************************************************/
90 static block_t
*BlockUDP( stream_t
*, bool * );
91 static int Control( stream_t
*, int, va_list );
93 /*****************************************************************************
94 * Open: open the socket
95 *****************************************************************************/
96 static int Open( vlc_object_t
*p_this
)
98 stream_t
*p_access
= (stream_t
*)p_this
;
101 if( p_access
->b_preparsing
)
104 sys
= vlc_obj_malloc( p_this
, sizeof( *sys
) );
105 if( unlikely( sys
== NULL
) )
110 /* Overflow can be max theoretical datagram content less anticipated MTU,
111 * IPv6 headers are larger than IPv4, ignore IPv6 jumbograms
113 sys
->overflow_block
= block_Alloc(65507 - sys
->mtu
);
114 if( unlikely( sys
->overflow_block
== NULL
) )
117 p_access
->p_sys
= sys
;
119 /* Set up p_access */
120 ACCESS_SET_CALLBACKS( NULL
, BlockUDP
, Control
, NULL
);
122 char *psz_name
= strdup( p_access
->psz_location
);
124 const char *psz_server_addr
, *psz_bind_addr
= "";
125 int i_bind_port
= 1234, i_server_port
= 0;
127 if( unlikely(psz_name
== NULL
) )
130 /* Parse psz_name syntax :
131 * [serveraddr[:serverport]][@[bindaddr]:[bindport]] */
132 psz_parser
= strchr( psz_name
, '@' );
133 if( psz_parser
!= NULL
)
135 /* Found bind address and/or bind port */
136 *psz_parser
++ = '\0';
137 psz_bind_addr
= psz_parser
;
139 if( psz_bind_addr
[0] == '[' )
140 /* skips bracket'd IPv6 address */
141 psz_parser
= strchr( psz_parser
, ']' );
143 if( psz_parser
!= NULL
)
145 psz_parser
= strchr( psz_parser
, ':' );
146 if( psz_parser
!= NULL
)
148 *psz_parser
++ = '\0';
149 i_bind_port
= atoi( psz_parser
);
154 psz_server_addr
= psz_name
;
155 psz_parser
= ( psz_server_addr
[0] == '[' )
156 ? strchr( psz_name
, ']' ) /* skips bracket'd IPv6 address */
159 if( psz_parser
!= NULL
)
161 psz_parser
= strchr( psz_parser
, ':' );
162 if( psz_parser
!= NULL
)
164 *psz_parser
++ = '\0';
165 i_server_port
= atoi( psz_parser
);
169 msg_Dbg( p_access
, "opening server=%s:%d local=%s:%d",
170 psz_server_addr
, i_server_port
, psz_bind_addr
, i_bind_port
);
172 sys
->fd
= net_OpenDgram( p_access
, psz_bind_addr
, i_bind_port
,
173 psz_server_addr
, i_server_port
, IPPROTO_UDP
);
177 msg_Err( p_access
, "cannot open socket" );
181 sys
->timeout
= var_InheritInteger( p_access
, "udp-timeout");
182 if( sys
->timeout
> 0)
183 sys
->timeout
*= 1000;
188 /*****************************************************************************
189 * Close: free unused data structures
190 *****************************************************************************/
191 static void Close( vlc_object_t
*p_this
)
193 stream_t
*p_access
= (stream_t
*)p_this
;
194 access_sys_t
*sys
= p_access
->p_sys
;
195 if( sys
->overflow_block
)
196 block_Release( sys
->overflow_block
);
198 net_Close( sys
->fd
);
201 /*****************************************************************************
203 *****************************************************************************/
204 static int Control( stream_t
*p_access
, int i_query
, va_list args
)
210 case STREAM_CAN_SEEK
:
211 case STREAM_CAN_FASTSEEK
:
212 case STREAM_CAN_PAUSE
:
213 case STREAM_CAN_CONTROL_PACE
:
214 pb_bool
= va_arg( args
, bool * );
218 case STREAM_GET_PTS_DELAY
:
219 *va_arg( args
, vlc_tick_t
* ) =
220 VLC_TICK_FROM_MS(var_InheritInteger(p_access
, "network-caching"));
229 /*****************************************************************************
231 *****************************************************************************/
232 static block_t
*BlockUDP(stream_t
*access
, bool *restrict eof
)
234 access_sys_t
*sys
= access
->p_sys
;
236 block_t
*pkt
= block_Alloc(sys
->mtu
);
237 if (unlikely(pkt
== NULL
))
238 { /* OOM - dequeue and discard one packet */
240 recv(sys
->fd
, &dummy
, 1, 0);
245 struct iovec iov
[] = {{
246 .iov_base
= pkt
->p_buffer
,
249 .iov_base
= sys
->overflow_block
->p_buffer
,
250 .iov_len
= sys
->overflow_block
->i_buffer
,
252 struct msghdr msg
= {
257 struct pollfd ufd
[1];
260 ufd
[0].events
= POLLIN
;
262 switch (vlc_poll_i11e(ufd
, 1, sys
->timeout
))
265 msg_Err(access
, "receive time-out");
272 ssize_t len
= recvmsg(sys
->fd
, &msg
, 0);
281 /* Received more than mtu amount,
282 * we should gather blocks and increase mtu
283 * and allocate new overflow block. See Open()
285 if (unlikely(len
> sys
->mtu
))
287 msg_Warn(access
, "%zd bytes packet received (MTU was %zu), adjusting mtu",
289 block_t
*gather_block
= sys
->overflow_block
;
291 sys
->overflow_block
= block_Alloc(65507 - len
);
293 gather_block
->i_buffer
= len
- sys
->mtu
;
294 pkt
->p_next
= gather_block
;
295 pkt
= block_ChainGather( pkt
);