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
)
86 /*****************************************************************************
88 *****************************************************************************/
89 static block_t
*BlockUDP( access_t
*, bool * );
90 static int Control( access_t
*, int, va_list );
92 /*****************************************************************************
93 * Open: open the socket
94 *****************************************************************************/
95 static int Open( vlc_object_t
*p_this
)
97 access_t
*p_access
= (access_t
*)p_this
;
100 if( p_access
->b_preparsing
)
103 sys
= vlc_malloc( p_this
, sizeof( *sys
) );
104 if( unlikely( sys
== NULL
) )
107 p_access
->p_sys
= sys
;
109 /* Set up p_access */
110 ACCESS_SET_CALLBACKS( NULL
, BlockUDP
, Control
, NULL
);
112 char *psz_name
= strdup( p_access
->psz_location
);
114 const char *psz_server_addr
, *psz_bind_addr
= "";
115 int i_bind_port
= 1234, i_server_port
= 0;
117 if( unlikely(psz_name
== NULL
) )
120 /* Parse psz_name syntax :
121 * [serveraddr[:serverport]][@[bindaddr]:[bindport]] */
122 psz_parser
= strchr( psz_name
, '@' );
123 if( psz_parser
!= NULL
)
125 /* Found bind address and/or bind port */
126 *psz_parser
++ = '\0';
127 psz_bind_addr
= psz_parser
;
129 if( psz_bind_addr
[0] == '[' )
130 /* skips bracket'd IPv6 address */
131 psz_parser
= strchr( psz_parser
, ']' );
133 if( psz_parser
!= NULL
)
135 psz_parser
= strchr( psz_parser
, ':' );
136 if( psz_parser
!= NULL
)
138 *psz_parser
++ = '\0';
139 i_bind_port
= atoi( psz_parser
);
144 psz_server_addr
= psz_name
;
145 psz_parser
= ( psz_server_addr
[0] == '[' )
146 ? strchr( psz_name
, ']' ) /* skips bracket'd IPv6 address */
149 if( psz_parser
!= NULL
)
151 psz_parser
= strchr( psz_parser
, ':' );
152 if( psz_parser
!= NULL
)
154 *psz_parser
++ = '\0';
155 i_server_port
= atoi( psz_parser
);
159 msg_Dbg( p_access
, "opening server=%s:%d local=%s:%d",
160 psz_server_addr
, i_server_port
, psz_bind_addr
, i_bind_port
);
162 sys
->fd
= net_OpenDgram( p_access
, psz_bind_addr
, i_bind_port
,
163 psz_server_addr
, i_server_port
, IPPROTO_UDP
);
167 msg_Err( p_access
, "cannot open socket" );
173 sys
->timeout
= var_InheritInteger( p_access
, "udp-timeout");
174 if( sys
->timeout
> 0)
175 sys
->timeout
*= 1000;
180 /*****************************************************************************
181 * Close: free unused data structures
182 *****************************************************************************/
183 static void Close( vlc_object_t
*p_this
)
185 access_t
*p_access
= (access_t
*)p_this
;
186 access_sys_t
*sys
= p_access
->p_sys
;
188 net_Close( sys
->fd
);
191 /*****************************************************************************
193 *****************************************************************************/
194 static int Control( access_t
*p_access
, int i_query
, va_list args
)
201 case STREAM_CAN_SEEK
:
202 case STREAM_CAN_FASTSEEK
:
203 case STREAM_CAN_PAUSE
:
204 case STREAM_CAN_CONTROL_PACE
:
205 pb_bool
= va_arg( args
, bool * );
209 case STREAM_GET_PTS_DELAY
:
210 pi_64
= va_arg( args
, int64_t * );
211 *pi_64
= INT64_C(1000)
212 * var_InheritInteger(p_access
, "network-caching");
221 /*****************************************************************************
223 *****************************************************************************/
224 static block_t
*BlockUDP(access_t
*access
, bool *restrict eof
)
226 access_sys_t
*sys
= access
->p_sys
;
228 block_t
*pkt
= block_Alloc(sys
->mtu
);
229 if (unlikely(pkt
== NULL
))
230 { /* OOM - dequeue and discard one packet */
232 recv(sys
->fd
, &dummy
, 1, 0);
237 .iov_base
= pkt
->p_buffer
,
240 struct msghdr msg
= {
244 .msg_flags
= MSG_TRUNC
,
248 struct pollfd ufd
[1];
251 ufd
[0].events
= POLLIN
;
253 switch (vlc_poll_i11e(ufd
, 1, sys
->timeout
))
256 msg_Err(access
, "receive time-out");
263 ssize_t len
= recvmsg(sys
->fd
, &msg
, 0);
272 if (msg
.msg_flags
& MSG_TRUNC
)
274 msg_Err(access
, "%zd bytes packet truncated (MTU was %zu)",
276 pkt
->i_flags
|= BLOCK_FLAG_CORRUPTED
;