56
65
struct sap_address_t
59
char psz_machine[NI_MAXNUMERICHOST];
68
struct sockaddr_storage orig;
60
70
int i_rfd; /* Read socket */
61
71
int i_wfd; /* Write socket */
63
73
/* Used for flow control */
82
/* A SAP session descriptor, enqueued in the SAP handler queue */
83
struct sap_session_t {
86
sap_address_t *p_address;
87
session_descriptor_t *p_sd;
89
/* Last and next send */
72
94
/*****************************************************************************
74
96
*****************************************************************************/
75
static void RunThread( vlc_object_t *p_this);
76
static int CalculateRate( sap_handler_t *p_sap, sap_address_t *p_address );
77
static char *SDPGenerate( sap_handler_t *p_sap,
78
const session_descriptor_t *p_session,
79
const sap_address_t *p_addr, vlc_bool_t b_ssm );
97
static void * RunThread( vlc_object_t *p_this);
98
static int ComputeRate( sap_address_t *p_address );
81
100
static int announce_SendSAPAnnounce( sap_handler_t *p_sap,
82
101
sap_session_t *p_session );
121
135
p_sap->b_control = config_GetInt( p_sap, "sap-flow-control");
123
137
if( vlc_thread_create( p_sap, "sap handler", RunThread,
124
VLC_THREAD_PRIORITY_LOW, VLC_FALSE ) )
138
VLC_THREAD_PRIORITY_LOW, false ) )
126
140
msg_Dbg( p_announce, "unable to spawn SAP handler thread");
141
vlc_object_release( p_sap );
145
vlc_object_set_destructor( p_sap, announce_SAPHandlerDestructor );
130
147
msg_Dbg( p_announce, "thread created, %i sessions", p_sap->i_sessions);
135
* Destroy the SAP handler
136
* \param p_this the SAP Handler to destroy
139
void announce_SAPHandlerDestroy( sap_handler_t *p_sap )
152
static void announce_SAPHandlerDestructor( vlc_object_t * p_this )
154
sap_handler_t *p_sap = (sap_handler_t *)p_this;
143
vlc_mutex_destroy( &p_sap->object_lock );
145
157
/* Free the remaining sessions */
146
158
for( i = 0 ; i< p_sap->i_sessions ; i++)
148
160
sap_session_t *p_session = p_sap->pp_sessions[i];
149
FREE( p_session->psz_sdp );
150
FREE( p_session->psz_data );
161
FREENULL( p_session->psz_data );
151
162
REMOVE_ELEM( p_sap->pp_sessions, p_sap->i_sessions , i );
163
FREENULL( p_session );
155
166
/* Free the remaining addresses */
156
167
for( i = 0 ; i< p_sap->i_addresses ; i++)
158
169
sap_address_t *p_address = p_sap->pp_addresses[i];
159
FREE( p_address->psz_address );
170
FREENULL( p_address->psz_address );
160
171
if( p_address->i_rfd > -1 )
162
173
net_Close( p_address->i_rfd );
190
200
/* If needed, get the rate info */
191
if( p_sap->b_control == VLC_TRUE )
201
if( p_sap->b_control == true )
193
203
for( i = 0 ; i< p_sap->i_addresses ; i++)
195
if( p_sap->pp_addresses[i]->b_enabled == VLC_TRUE )
205
if( p_sap->pp_addresses[i]->b_enabled == true )
197
CalculateRate( p_sap, p_sap->pp_addresses[i] );
207
ComputeRate( p_sap->pp_addresses[i] );
202
212
/* Find the session to announce */
203
vlc_mutex_lock( &p_sap->object_lock );
213
vlc_object_lock( p_sap );
204
214
if( p_sap->i_sessions > p_sap->i_current_session + 1)
206
216
p_sap->i_current_session++;
214
vlc_mutex_unlock( &p_sap->object_lock );
224
vlc_object_unlock( p_sap );
218
227
p_session = p_sap->pp_sessions[p_sap->i_current_session];
219
vlc_mutex_unlock( &p_sap->object_lock );
221
229
/* And announce it */
222
if( p_session->p_address->b_enabled == VLC_TRUE &&
223
p_session->p_address->b_ready == VLC_TRUE )
230
if( p_session->p_address->b_enabled == true &&
231
p_session->p_address->b_ready == true )
225
233
announce_SendSAPAnnounce( p_sap, p_session );
235
vlc_object_unlock( p_sap );
232
240
/* Add a SAP announce */
233
241
static int announce_SAPAnnounceAdd( sap_handler_t *p_sap,
234
242
session_descriptor_t *p_session )
236
int i_header_size, i;
237
char *psz_head, psz_addr[NI_MAXNUMERICHOST];
238
vlc_bool_t b_ipv6 = VLC_FALSE, b_ssm = VLC_FALSE;
245
char psz_addr[NI_MAXNUMERICHOST];
246
bool b_ipv6 = false, b_ssm = false;
239
247
sap_session_t *p_sap_session;
241
struct addrinfo hints, *res;
242
249
struct sockaddr_storage addr;
244
vlc_mutex_lock( &p_sap->object_lock );
246
if( p_session->psz_uri == NULL )
252
vlc_object_lock( p_sap );
253
addrlen = p_session->addrlen;
254
if ((addrlen == 0) || (addrlen > sizeof (addr)))
248
vlc_mutex_unlock( &p_sap->object_lock );
249
msg_Err( p_sap, "*FIXME* unexpected NULL URI for SAP announce" );
250
msg_Err( p_sap, "This should not happen. VLC needs fixing." );
256
vlc_object_unlock( p_sap );
257
msg_Err( p_sap, "No/invalid address specified for SAP announce" );
251
258
return VLC_EGENERIC;
254
261
/* Determine SAP multicast address automatically */
255
memset( &hints, 0, sizeof( hints ) );
256
hints.ai_socktype = SOCK_DGRAM;
257
hints.ai_flags = AI_NUMERICHOST;
259
i = vlc_getaddrinfo( (vlc_object_t *)p_sap, p_session->psz_uri, 0,
263
vlc_mutex_unlock( &p_sap->object_lock );
264
msg_Err( p_sap, "Invalid URI for SAP announce: %s: %s",
265
p_session->psz_uri, vlc_gai_strerror( i ) );
269
if( (unsigned)res->ai_addrlen > sizeof( addr ) )
271
vlc_mutex_unlock( &p_sap->object_lock );
272
vlc_freeaddrinfo( res );
273
msg_Err( p_sap, "Unsupported address family of size %d > %u",
274
res->ai_addrlen, (unsigned) sizeof( addr ) );
278
memcpy( &addr, res->ai_addr, res->ai_addrlen );
280
switch( addr.ss_family )
262
memcpy (&addr, &p_session->addr, addrlen);
264
switch( p_session->addr.ss_family )
282
266
#if defined (HAVE_INET_PTON) || defined (WIN32)
349
vlc_mutex_unlock( &p_sap->object_lock );
350
vlc_freeaddrinfo( res );
332
vlc_object_unlock( p_sap );
351
333
msg_Err( p_sap, "Address family %d not supported by SAP",
352
334
addr.ss_family );
353
335
return VLC_EGENERIC;
356
i = vlc_getnameinfo( (struct sockaddr *)&addr, res->ai_addrlen,
338
i = vlc_getnameinfo( (struct sockaddr *)&addr, addrlen,
357
339
psz_addr, sizeof( psz_addr ), NULL, NI_NUMERICHOST );
358
vlc_freeaddrinfo( res );
362
vlc_mutex_unlock( &p_sap->object_lock );
343
vlc_object_unlock( p_sap );
363
344
msg_Err( p_sap, "%s", vlc_gai_strerror( i ) );
364
345
return VLC_EGENERIC;
386
368
malloc( sizeof(sap_address_t) );
389
msg_Err( p_sap, "out of memory" );
371
vlc_object_unlock( p_sap );
390
372
return VLC_ENOMEM;
392
374
p_address->psz_address = strdup( psz_addr );
393
p_address->i_wfd = net_ConnectUDP( p_sap, psz_addr, SAP_PORT, 255 );
375
p_address->i_wfd = net_ConnectUDP( VLC_OBJECT(p_sap), psz_addr, SAP_PORT, 255 );
394
376
if( p_address->i_wfd != -1 )
398
net_StopRecv( p_address->i_wfd );
399
net_GetSockAddress( p_address->i_wfd, p_address->psz_machine,
402
/* removes scope if present */
403
ptr = strchr( p_address->psz_machine, '%' );
378
shutdown( p_address->i_wfd, SHUT_RD );
379
p_address->origlen = sizeof (p_address->orig);
380
getsockname (p_address->i_wfd, (struct sockaddr *)&p_address->orig,
381
&p_address->origlen);
408
if( p_sap->b_control == VLC_TRUE )
384
if( p_sap->b_control == true )
410
p_address->i_rfd = net_OpenUDP( p_sap, psz_addr, SAP_PORT, "", 0 );
386
p_address->i_rfd = net_ListenUDP1( (vlc_object_t*)p_sap, psz_addr, SAP_PORT );
411
387
if( p_address->i_rfd != -1 )
412
net_StopSend( p_address->i_rfd );
388
shutdown( p_address->i_rfd, SHUT_WR );
413
389
p_address->i_buff = 0;
414
p_address->b_enabled = VLC_TRUE;
415
p_address->b_ready = VLC_FALSE;
390
p_address->b_enabled = true;
391
p_address->b_ready = false;
416
392
p_address->i_limit = 10000; /* 10000 bps */
417
393
p_address->t1 = 0;
421
p_address->b_enabled = VLC_TRUE;
422
p_address->b_ready = VLC_TRUE;
397
p_address->b_enabled = true;
398
p_address->b_ready = true;
423
399
p_address->i_interval = config_GetInt( p_sap,"sap-interval");
424
400
p_address->i_rfd = -1;
438
414
p_sap_session->p_address = p_address;
417
memcpy (&p_session->orig, &p_sap_session->p_address->orig,
418
p_session->origlen = p_sap_session->p_address->origlen);
420
size_t headsize = 20;
421
switch (p_session->orig.ss_family)
432
msg_Err( p_sap, "Address family %d not supported by SAP",
434
vlc_object_unlock( p_sap );
438
/* If needed, build the SDP */
439
assert( p_session->psz_sdp != NULL );
441
p_sap_session->i_last = 0;
442
p_sap_session->i_length = headsize + strlen (p_session->psz_sdp);
443
p_sap_session->psz_data = malloc (p_sap_session->i_length + 1);
444
if (p_sap_session->psz_data == NULL)
446
free (p_session->psz_sdp);
447
vlc_object_unlock( p_sap );
442
451
/* Build the SAP Headers */
443
i_header_size = ( b_ipv6 ? 16 : 4 ) + 20;
444
psz_head = (char *) malloc( i_header_size * sizeof( char ) );
445
if( psz_head == NULL )
447
msg_Err( p_sap, "out of memory" );
452
uint8_t *psz_head = p_sap_session->psz_data;
451
454
/* SAPv1, not encrypted, not compressed */
452
psz_head[0] = b_ipv6 ? 0x30 : 0x20;
453
456
psz_head[1] = 0x00; /* No authentification length */
455
458
i_hash = mdate();
456
psz_head[2] = (i_hash & 0xFF00) >> 8; /* Msg id hash */
457
psz_head[3] = (i_hash & 0xFF); /* Msg id hash 2 */
459
psz_head[2] = i_hash >> 8; /* Msg id hash */
460
psz_head[3] = i_hash; /* Msg id hash 2 */
459
#if defined (HAVE_INET_PTON) || defined (WIN32)
463
switch (p_session->orig.ss_family)
462
inet_pton( AF_INET6, /* can't fail */
463
p_sap_session->p_address->psz_machine,
468
struct in6_addr *a6 =
469
&((struct sockaddr_in6 *)&p_session->orig)->sin6_addr;
470
memcpy (psz_head + headsize, a6, 16);
471
psz_head[0] |= 0x10; /* IPv6 flag */
469
inet_pton( AF_INET, /* can't fail */
470
p_sap_session->p_address->psz_machine,
474
memcpy( psz_head + (b_ipv6 ? 20 : 8), "application/sdp", 15 );
476
/* If needed, build the SDP */
477
if( p_session->psz_sdp == NULL )
479
p_session->psz_sdp = SDPGenerate( p_sap, p_session,
480
p_sap_session->p_address, b_ssm );
481
if( p_session->psz_sdp == NULL )
483
vlc_mutex_unlock( &p_sap->object_lock );
479
(((struct sockaddr_in *)&p_session->orig)->sin_addr.s_addr);
480
memcpy (psz_head + headsize, &ipv4, 4);
488
p_sap_session->psz_sdp = strdup( p_session->psz_sdp );
489
p_sap_session->i_last = 0;
491
psz_head[ i_header_size-1 ] = '\0';
492
p_sap_session->i_length = i_header_size + strlen( p_sap_session->psz_sdp);
494
p_sap_session->psz_data = (uint8_t *)malloc( sizeof(char)*
495
p_sap_session->i_length );
487
memcpy (psz_head + headsize, "application/sdp", 16);
497
490
/* Build the final message */
498
memcpy( p_sap_session->psz_data, psz_head, i_header_size );
499
memcpy( p_sap_session->psz_data+i_header_size, p_sap_session->psz_sdp,
500
strlen( p_sap_session->psz_sdp) );
491
strcpy( (char *)psz_head + headsize, p_session->psz_sdp);
504
493
/* Enqueue the announce */
505
494
INSERT_ELEM( p_sap->pp_sessions,
522
508
session_descriptor_t *p_session )
525
vlc_mutex_lock( &p_sap->object_lock );
511
vlc_object_lock( p_sap );
527
msg_Dbg( p_sap,"removing SAP announce %p",p_session->p_sap);
513
msg_Dbg( p_sap, "removing session %p from SAP", p_session);
529
515
/* Dequeue the announce */
530
516
for( i = 0; i< p_sap->i_sessions; i++)
532
if( p_session->p_sap == p_sap->pp_sessions[i] )
518
if( p_session == p_sap->pp_sessions[i]->p_sd )
520
free( p_session->psz_sdp );
521
sap_session_t *p_mysession = p_sap->pp_sessions[i];
534
522
REMOVE_ELEM( p_sap->pp_sessions,
535
523
p_sap->i_sessions,
538
FREE( p_session->p_sap->psz_sdp );
539
FREE( p_session->p_sap->psz_data );
540
free( p_session->p_sap );
526
free( p_mysession->psz_data );
584
571
p_session->i_next = p_session->i_last
585
572
+ p_session->p_address->i_interval*1000000;
591
574
return VLC_SUCCESS;
594
static char *SDPGenerate( sap_handler_t *p_sap,
595
const session_descriptor_t *p_session,
596
const sap_address_t *p_addr, vlc_bool_t b_ssm )
598
int64_t i_sdp_id = mdate();
599
int i_sdp_version = 1 + p_sap->i_sessions + (rand()&0xfff);
600
char *psz_group, *psz_name, psz_uribuf[NI_MAXNUMERICHOST], *psz_uri,
603
char *sfilter = NULL;
606
psz_group = p_session->psz_group;
607
psz_name = p_session->psz_name;
609
/* FIXME: really check that psz_uri is a real IP address
610
* FIXME: make a common function to obtain a canonical IP address */
611
ipv = ( strchr( p_session->psz_uri, ':' ) != NULL) ? '6' : '4';
612
if( *p_session->psz_uri == '[' )
616
strlcpy( psz_uribuf, p_session->psz_uri + 1, sizeof( psz_uribuf ) );
617
ptr = strchr( psz_uribuf, '%' );
620
ptr = strchr( psz_uribuf, ']' );
623
psz_uri = psz_uribuf;
626
psz_uri = p_session->psz_uri;
630
if (asprintf (&sfilter, "a=source-filter: incl IN IP%c * %s\r\n",
631
ipv, p_addr->psz_machine) == -1)
635
/* see the lists in modules/stream_out/rtp.c for compliance stuff */
636
res = asprintf (&psz_sdp,
638
"o=- "I64Fd" %d IN IP%c %s\r\n"
642
"a=tool:"PACKAGE_STRING"\r\n"
644
"a=type:broadcast\r\n"
647
"m=video %d %s %d\r\n",
648
i_sdp_id, i_sdp_version,
649
ipv, p_addr->psz_machine,
650
psz_name, ipv, psz_uri,
651
(ipv == 4) ? "/255" : "",
652
(sfilter != NULL) ? sfilter : "",
653
psz_group ? "a=x-plgroup:" : "",
654
psz_group ? psz_group : "", psz_group ? "\r\n" : "",
656
p_session->b_rtp ? "RTP/AVP" : "udp",
657
p_session->i_payload);
664
msg_Dbg( p_sap, "Generated SDP (%i bytes):\n%s", strlen(psz_sdp),
669
static int CalculateRate( sap_handler_t *p_sap, sap_address_t *p_address )
577
static int ComputeRate( sap_address_t *p_address )
672
579
uint8_t buffer[SAP_MAX_BUFFER];