Appendice C - Implementazione dello schema di
migrazione integrato
Si riportano il codice sorgente C++ che implementa il RB, nonché le modifiche apportate al
software VLC, che implementano lo schema di ripristino integrato alla rete, che è stato
illustrato e valutato nel Capitolo 4.
Implementazione del resource broker
Il RB è stato implementato come applicativo indipendente; nel corso delle prove è stato
eseguito sul client host. Inoltre il codice qui riportato è in grado di servire un solo client alla
volta.
File main.cc
Implementa la segnalazione e la comunicazione con i router e il VIDEOLAN client, così
come illustrata nel capitolo 4.
#include"server.h" #include"router.h" #include"socket.h"
// Definisco router di default a cui si connette client e RB #define rout_addr "10.0.20.1"
int main()
{
// Inizializza lista video server struct server lista[maxnumserver];
int numserver = init_cont(lista,"server.list"); printf("Sono stati registrati %d server",numserver);
// Inizializza l’interfaccia per il video client int sock_server = startserver(serverport); if (!sock_server){
printf("Inizializzazione fallita"); exit(1);
}
// Servizio successivo a client diversi while(1){
printf("In attessa di nuove connessioni\n"); char client_addr[15];
int client_sock = accettaconnessione(sock_server,client_addr); printf("Nuova connessione da %s\n",client_addr);
// Servizio ad un client
// Se il RB gira localmente al client host c’è bisogno di specificarne // l’indirizzo IP
client_addr = “10.0.20.2”;
// Identifica server che eroga il servizio [0..numserver-1] int servID=-1;
while(1){
// Attende eventuale richiesta del client per un tempo pari alla frequenza di polling
command cmd = wait_clnt_cmd(client_sock); switch(cmd){
case Error:
printf("Richiesta non valida"); continue;
case End:
printf("Connessione chiusa dal client");
tear_lsp(lista[servID].rout_sock,lista[servID].rout_name); goto end;
case None:
// Nessuna richiesta dal client:procede a verificare stato LSP se il servizio è in corso
if (servID != -1){
// Servizio in corso
// Richiede all’ingress router lo stato del LSP
lsp_status status =
status_lsp(lista[servID].rout_sock,lista[servID].rout_name); if (status == UP) continue;
printf("LSP abbattuto");
// Utilizzo la stessa routine per la migrazione e per iniziare il servizio case Request:
case Migrate:
if (servID != -1){
// Migrazione
// Abbatto LSP fallito per liberare tempestivamente le risorse tear_lsp(lista[servID].rout_sock,lista[servID].rout_name); printf("Apertura LSP da server di backup\n");
}
// Apertura del servizio else printf("Apertura LSP");
// Ordina instaurazione LSP su tutti i router tranne eventualmente quello fallito for (int i=0 ; i<numserver ; i++)
if (i != servID) set_lsp(lista[i].rout_sock, lista[i].rout_name ,rout_addr,
client_addr);
// Controlla ciclicamente esito richiesta su tutti i router finchè uno non viene instaurato
while(1){
for (int i=0 ; i<numserver ; i++) if (i != servID)
if (status_lsp(lista[i].rout_sock, lista[i].rout_name) == UP){
// LSP instaurato
servID = i; goto Path_Delivery;
}
// Se nessuno ha instaurato il LSP aspetta 1 sec prima di ricominciare il ciclo sleep(1);
// Fine ciclo while }
Path_Delivery:
// Invia URL del buckup al client
if (Invia(client_sock,lista[servID].cont_path) == FAIL){ printf("Impossibile inviare nuovo path al client"); goto end;
}
// Abbatte LSP inutili
for (int i=0 ; i<numserver ; i++)
if (i != servID) tear_lsp(lista[i].rout_sock, lista[i].rout_name);
continue;
// Fine Migrazione }
// Fuori dallo switch }
// Fuori dal while
// Chiusura connessione con client end:
close(client_sock);
//Ritorna all’inizio del primo while per servire prossimo client }
}
Modulo
router
Il modulo router implementa l’interfaccia con il piano di controllo di rete, vale a dire la
comunicazione con i router Juniper M10 che sono stati utilizzati nel testbed, allo scopo di
configurare e controllare i LSP a banda garantita. L’interazione avviene mediante interfaccia
telnet basata su linguaggio di script proprietario Junoscript
XML.
Poichè nel testbed si è fatto ricorso all’ausilio di router virtuali, il codice è in grado di
implementare la comunicazione con logical-router.
Router.h
#include <string>
// Porta del server Junos sui router Juniper #define JUNOSPORT 3221
// Frequenza di polling in msec #define POLLFREQ 1000
#define COMMIT "<rpc><commit-configuration/></rpc>" enum lsp_status {UP,DN};
int Connetti_rout(char* rout_addr);
void set_lsp(int rout_sock, char* rout_name, char* to, char* install); lsp_status status_lsp(int rout_sock, char* rout_name);
void tear_lsp(int rout_sock, char* rout_name);
Router.cc
#include"router.h" #include"socket.h"
// Funzioni che generano le stringe di configurazione da inviare ai router
static void str_set_lsp(char msg[],char* nome, char* rout_name, char* to, char* install);
static void str_tear_lsp(char msg[],char* nome, char* rout_name); static void str_lsp_status(char msg[],char nome[],char router[]);
// Funzione per aprire l'interfaccia Junoscript con un router int Connetti_rout(char* rout_addr){
int rout_sock= connetti(rout_addr,JUNOSPORT); if (!rout_sock ){
printf("Errore connessione router");
return 0;
}
/* Stringa per autenticazione */
char login[1024 ]="<rpc><request-login><username>login</username><challenge-response>password</challenge-response></request-login></rpc>";
/* Stringa per inizializzazione */
char init[1024]="<?xml version=\"1.0\" encoding=\"us-ascii\"?> \n <junoscript version=\"1.0\">";
Invia (rout_sock,init); Invia (rout_sock,login); sleep(1);
char msg[1024]; while(1){
Ricevi (rout_sock, msg); printf("%s",msg);
// Verifica successo del login
if(strstr(msg,"<status>success</status>")){
if (strstr(msg,"<!-- user login, class j-network-mgmt -->")) return rout_sock;
break;
}
// Verifica insuccesso del login
if(strstr(msg,"<status>fail</status>")) { close(rout_sock); return 0; } } }
// Funzione per configurare un LSP sull'ingress router
void set_lsp(int rout_sock, char* rout_name, char* to, char* install){
// Genero la stringa di configurazione char msg[1024];
str_set_lsp(msg,"stream",rout_name,to,install);
if(Invia(rout_sock,msg) == FAIL) printf("Errore invio comando"); }
// Funzione che ordina all'ingress router di procedere all'abbattimento del LSP void tear_lsp(int rout_sock, char* rout_name){
char msg[1024];
str_tear_lsp(msg,"stream",rout_name);
if(Invia(rout_sock,msg) == FAIL) printf("Errore invio comando"); }
// funzione che verifica lo stato (UP o DOWN) di un LSP lsp_status status_lsp(int rout_sock, char* rout_name){
// Invio richiesta char msg[1024];
str_lsp_status(msg,"stream",rout_name); if(Invia(rout_sock,msg) == FAIL){
printf("Errore invio richiesta"); return DN;
}
// Elaborazione della risposta da parte del roouter while(1){
// Attende risposta del router fino a 3 secondi esito status = RiceviNonBlock(rout_sock,msg,3000);
// Elaborazione della risposta if (status == FAIL){
printf("Errore ricezione risposta");
return DN;
}
if (status == NONE){
printf("Nessuna risposta");
return DN; } if(strstr(msg,"<lsp-state>Up</lsp-state>")) return UP; if(strstr(msg,"<lsp-state>Dn</lsp-state>")) return DN; } }
static void str_set_lsp(char msg[],char* nome, char* rout_name, char* to, char* install){
strcpy(msg,"<rpc><load-configuration><configuration><logical-routers>"); strcat(msg,rout_name);
strcat(msg,"<protocols><mpls><label-switched-path set=\"set\">"); strcat(msg,nome); strcat(msg,"<to>"); strcat(msg,to); strcat(msg,"</to><install>"); strcat(msg,install); strcat(msg ,"</install></label-switched-path></mpls></protocols></logical-routers></configuration></load-configuration></rpc>\n"); strcat(msg,COMMIT); };
static void str_tear_lsp(char msg[],char* nome, char* rout_name){
strcpy(msg,"<rpc><load-configuration><configuration><logical-routers>"); strcat(msg,rout_name);
strcat(msg,"<protocols><mpls><label-switched-path delete=\"delete\">"); strcat(msg,nome);
strcat(msg ,"</label-switched-path></mpls></protocols></logical-routers></configuration></load-configuration></rpc>\n");
strcat(msg,COMMIT); };
static void str_lsp_status(char msg[],char nome[], char router[]){ strcpy(msg,"<rpc><command> show mpls lsp name ");
strcat(msg,nome); strcat(msg," logical-router "); strcat(msg,router); strcat(msg,"</command></rpc>"); };
Modulo
server
Implementa le funzionalità relative alla memorizzazione e gestione dei video server, nonché
l’interfaccia con il client. In particolare implementa la funzione che legge dal file server.list
la lista di tutti i server che sono in grado di erogare lo streaming del video; a ciascun di essi
deve essere associato anche il nome (identificativo del logical-router) e l’indirizzo IP del
router al quale si connettono.
Ciascuna entry nel file dovrà avere il formato
[URL contenuto]
> [Indirizzo IP router] [nome logical-router]
Per esempio
10.0.30.2/starguitar.vob
>
210.0.30.1 edge1
Il modulo implementa anche la funzione che elabora le richieste del client al RB..
Server.h
// Funzionalità server Video client // #include <fstream> #define maxnumserver 5 using namespace std; struct server { char cont_path[50]; char rout_name[10]; int rout_sock; };
enum command {Request,Migrate,None,End,Error}; int init_cont(struct server lista[],char* file);
Server.cc
#include"server.h" #include"router.h" #include"socket.h"
// Legge da file l'URL di tutti i server per inizializzarne una lista int init_cont(struct server lista[],char* file){
fstream fp;
fp.open(file,ios::in);
int numserver = 0;
while (!fp.eof() && (numserver<maxnumserver)){ char rout_addr[15];
fp >> lista[numserver].cont_path >> rout_addr >> lista[numserver].rout_name;
printf("Content Path: %s \n",lista[numserver].cont_path); printf("Router address: %s \n",rout_addr);
printf("Router name: %s \n",lista[numserver].rout_name);
int sock = Connetti_rout(rout_addr);
if (sock){
lista[numserver].rout_sock = sock;
numserver++;
printf("Stabilita connessione con router \n"); } else printf("Fallita connessione con router \n");
}
fp.close();
return numserver; }
// Attende una richiesta dal client per un tempo pari alla frequenza di polling
command wait_clnt_cmd(int socket){
// Si attende msg da client char msg[1024];
esito lettura = RiceviNonBlock(socket,msg,POLLFREQ);
// Elabora l'esito switch(lettura){ case FAIL:
// Fine servizio
printf("Connessione chiusa dal client"); return End;
case NONE:
// Nessun messaggio return None;
case SUCCESS:
if(strstr(msg,"Request")) return Request; if(strstr(msg,"Migrate")) return Migrate; printf("Richiesta non valida");
return Error; }
}
Modulo
socket
E’ il modulo di più basso livello, che ge stisce la gestione dei socket di rete attraverso i quali il
RB interagisce con il client e con i router. Per entrambe le connessioni si è fatto ricorso a
socket TCP
Socket.h
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/wait.h> #include <signal.h> #include <netdb.h> #define BACKLOG 1enum esito{SUCCESS, FAIL, NONE}; int startserver(int port);
int accettaconnessione(int socket, char* from); int connetti(char* to, int port);
esito Invia (int sock,char* msg); esito Ricevi (int sock, char* msg);
esito RiceviNonBlock (int sock, char* msg, int wait);
socket.cc
#include"socket.h"
// Elimina processi zombie ancora in ascolto static void sigchld_handler(int s)
{
};
// Inizializza l'interfaccia con il client int startserver(int port){
int sockfd;
struct sockaddr_in my_addr; // Struttura che definisce mio indirizzo struct sigaction sa;
int yes=1;
if ((sockfd=socket(AF_INET,SOCK_STREAM,0)) == -1) { printf("Impossibile aprire socket server \n");
return 0;
}
// Elimina vecchi listener
if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) { printf("Impossibile eliminare vecchi listener \n");
}
// Definisce My_addr
my_addr.sin_family = AF_INET; my_addr.sin_port = htons(port); my_addr.sin_addr.s_addr = INADDR_ANY; memset(&(my_addr.sin_zero), '\0', 8);
// Elimina processi zombie
sa.sa_handler = sigchld_handler; sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
printf("Impossibile eliminare processi zombie \n");
}
// Fa il binding di sockfd su proprio indirizzo
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) ==
-1){
printf("Impossibile eseguire binding socket server \n");
return 0;
}
// Predispone il socket ad accettare una connessione dal cideo client if(listen(sockfd, BACKLOG) == -1){
printf("Impossibile eseguire listening su socket server \n"); return 0;
}
return sockfd; }
// Pone il RB in attesa di una connessione da parte di un client int accettaconnessione(int socket,char* from){
int new_fd;
struct sockaddr_in their_addr;
socklen_t sin_size=sizeof(struct sockaddr_in);
// Accetta connessione e definisce indirizzo del video client
if((new_fd = accept(socket,(struct sockaddr *)&their_addr,&sin_size)) == -1){ printf("Impossibile aprire socket server \n");
return 0;
}
strcpy(from,(char*)inet_ntoa(their_addr.sin_addr)); return new_fd;
}
// Apre socket TCP tra RB e un router int connetti(char* to, int port){
int sockfd;
struct hostent *he;
struct sockaddr_in their_addr;
//DNS
if((he=gethostbyname(to)) == NULL){
printf("Errore risoluzione indirizzo router"); return 0;
}
their_addr.sin_family = AF_INET; their_addr.sin_port = htons(port);
their_addr.sin_addr = *((struct in_addr *)he->h_addr); memset(&(their_addr.sin_zero), '\0', 8); // azzero il resto
if((sockfd=socket(AF_INET,SOCK_STREAM,0)) == -1){ printf("Errore apertura socket");
return 0;
}
// Connessione
if((connect(sockfd,(struct sockaddr *)&their_addr,sizeof(struct sockaddr))) == -1){
printf("Errore connessione al router");
return 0;
}
return sockfd; }
// Invia un messaggio nel socket di rete esito Invia (int sock,char* msg){
if (send(sock,msg, strlen(msg), 0) == -1) return FAIL; return SUCCESS;
}
// Attende che un messaggio si renda disponibile su un socket esito Ricevi (int sock, char* msg){
if (read(sock, msg, 1024) == 0) return FAIL; return SUCCESS;
};
// Attende che un messaggio si renda disponibile su un socket
// A differenza della funzione precedente aspetta un tempo massimo pari a wait (in msec)
esito RiceviNonBlock (int sock, char* msg, int wait){ struct timeval tv:
fd_set readfds;
// Imposto il tempo massimo di attesa tv.tv_usec = wait * 1000;
FD_ZERO(&readfds); FD_SET(sock,&readfds);
// Controlla se scade prima timeout o si rende disponibile un messaggio select(sock+1,&readfds,NULL,NULL,&tv);
if (FD_ISSET(sock,,&readfds){
// Socket pronto
if (read(sock, msg, 1024) == 0) return FAIL; return SUCCESS;
}
// E' scaduto time-out else return NONE; }
Modifiche apportate a VideoLAN client
Di seguito si riportano le modifiche apportate al software open-source VideoLAN client
(versione 0.7.2), e in particolare al modulo di accesso alla rete basato su HTTP. Le modifiche
implementano la comunicazione con il resource broker allo scopo di effettuare la migrazione
del server. In rosso si sono evidenziati commenti a quelle parti di codice che sono state
aggiunte o modificate.
/modules/access/http.c
/***************************************************************************** * http.c: HTTP input module ***************************************************************************** * Copyright (C) 2001-2004 VideoLAN * $Id: http.c 7522 2004-04-27 16:35:15Z sam $ ** Authors: Laurent Aimar <[email protected]> * Christophe Massiot <[email protected]> *
* This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. *****************************************************************************/ /***************************************************************************** * Preamble *****************************************************************************/ #include <stdlib.h> #include <vlc/vlc.h> #include <vlc/input.h> #include "vlc_playlist.h" #include "network.h" /***************************************************************************** * Module descriptor *****************************************************************************/ static int Open ( vlc_object_t * );
static void Close( vlc_object_t * );
// Definisce menu interfaccia grafica modules/access/http #define PROXY_TEXT N_("HTTP proxy")
#define PROXY_LONGTEXT N_( \
"You can specify an HTTP proxy to use. It must be of the form " \
"http://myproxy.mydomain:myport/. If none is specified, the HTTP_PROXY " \ "environment variable will be tried." )
// Inserisce nel menu campo per l’indirizzo del RB
#define RB_LONGTEXT N_( \
"You can specify the address of a RB to use to retrieve the desidered content with reserved bandwidth connection" )
// Inserisce nel menu campo per stabilire lunghezza temporale del buffer
#define CACHING_TEXT N_("Caching value in ms") #define CACHING_LONGTEXT N_( \
"Allows you to modify the default caching value for http streams. This " \ "value should be set in millisecond units." )
// Inserisce nel menu campo per stabilire time-out lettura socket
#define TIMEOUT_TEXT N_("Socket reading timeout value in ms") #define TIMEOUT_LONGTEXT N_( \
"Allows you to modify the default socket reading timeout value for http streams. This " \
"value should be set in millisecond units." )
#define USER_TEXT N_("HTTP user name")
#define USER_LONGTEXT N_("Allows you to modify the user name that will " \ "be used for the connection (Basic authentication only).")
#define PASS_TEXT N_("HTTP password")
#define PASS_LONGTEXT N_("Allows you to modify the password that will be " \ "used for the connection.")
#define AGENT_TEXT N_("HTTP user RB")
#define AGENT_LONGTEXT N_("Allows you to modify the user agent that will be " \ "used for the connection.")
vlc_module_begin();
set_description( _("HTTP input") ); set_capability( "access", 0 );
add_string( "http-proxy", NULL, NULL, PROXY_TEXT, PROXY_LONGTEXT, VLC_FALSE );
add_string( "http-user", NULL, NULL, USER_TEXT, USER_LONGTEXT, VLC_FALSE ); add_string( "http-pwd", NULL , NULL, PASS_TEXT, PASS_LONGTEXT, VLC_FALSE ); add_string( "http-user-agent", COPYRIGHT_MESSAGE , NULL, AGENT_TEXT,
AGENT_LONGTEXT, VLC_FALSE );
// Definisce valori di default per le voci del menu
add_string( "RB", "127.0.0.1:3490”, NULL, RB_TEXT, RB_LONGTEXT,VLC_FALSE ); add_integer( "socket-timeout", 1000, NULL,
TIMEOUT_TEXT, TIMEOUT_LONGTEXT, VLC_TRUE );
add_integer( "http-caching", 4 * DEFAULT_PTS_DELAY / 1000, NULL, CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE );
add_shortcut( "http" ); add_shortcut( "http4" ); add_shortcut( "http6" ); set_callbacks( Open, Close ); vlc_module_end(); /***************************************************************************** * Local prototypes *****************************************************************************/ struct access_sys_t { int fd; /* From uri */ vlc_url_t url; char *psz_user; char *psz_passwd; char *psz_user_agent; /* Proxy */
vlc_bool_t b_proxy;
vlc_url_t proxy;
// Allocazione variabili per la migrazione //
// struttuta che definisce indirizzo e porta del RB vlc_url_t rb;
// socket del RB
int rb_fd;
// time-out lettura socket //
mtime_t timeout; float startup; /* */ int i_code; char *psz_protocol; int i_version; char *psz_mime; char *psz_location; vlc_bool_t b_chunked; int64_t i_chunk; int64_t i_tell; int64_t i_size; };
static void Seek( input_thread_t *, off_t );
static ssize_t Read( input_thread_t *, byte_t *, size_t ); static void ParseURL( access_sys_t *, char *psz_url );
static int Connect( input_thread_t *, vlc_bool_t *, off_t *, off_t ); static char *b64_encode( unsigned char *src );
// Funzione che permette al client di connettersi al RB//
static int ConnectRB ( input_thread_t *p_input, char url[50]);
// Funzioni che eseguono la migrazione//
static vlc_bool_t Migrazioneclient ( input_thread_t * ); static vlc_bool_t MigrazioneRB ( input_thread_t * , char * );
// Funzione per elaborare l’URL
static void Elab_URL(char url[50]){
// Inizializza il modulo di accesso all’apertura del servizio
/***************************************************************************** * Open:
*****************************************************************************/ static int Open ( vlc_object_t *p_this )
{
input_thread_t *p_input = (input_thread_t*)p_this; access_sys_t *p_sys;
vlc_value_t val;
**** OMISSIS ****
// Legge dal menu timeout in lettura dal socket
var_Create( p_input, "socket-timeout", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT ); var_Get( p_input, "socket-timeout", &val );
var_Create( p_input, "RB", VLC_VAR_STRING | VLC_VAR_DOINHERIT ); var_Get( p_input, "RB", &val );
if( val.psz_string && *val.psz_string ) {
// Inizializza URL del RB
vlc_UrlParse( &p_sys->rb, val.psz_string, 0 );
if( p_sys->rb.psz_host == NULL) msg_Warn( p_input, "RB not valid" ); else
{
if( p_sys->rb.i_port <= 0 ) p_sys->rb.i_port = 3490;
msg_Dbg(p_input,"RB at %s Port %d ",p_sys->rb.psz_host,p_sys->rb.i_port);
// Definisce la posizione relativa dello streaming prima della quale il client non // può richiedere migrazione
p_sys->startup = 0.05; }
}
// Si connette al RB e riceve URL del contenuto multimediale
char url[50];
if (ConnectRB(p_input, url)){
msg_Warn(p_input,"Unable to connect controller"); goto error;
}
/* Parse URL */
ParseURL( p_sys, url );
if( p_sys->url.psz_host == NULL || *p_sys->url.psz_host == '\0' ) {
msg_Warn( p_input, "invalid host" ); goto error;
}
if( p_sys->url.i_port <= 0 ) {
p_sys->url.i_port = 80; }
***** OMISSIS *****
msg_Dbg( p_input, "http: server='%s' port=%d file='%s",
p_sys->url.psz_host, p_sys->url.i_port, p_sys->url.psz_path ); ***** OMISSIS *****
// Si connette al server per richiedere inizio dello streaming if( Connect( p_input, &p_input->stream.b_seekable,
&p_input->stream.p_selected_area->i_size, 0 ) ) {
***** OMISSIS ***** }
/* Imposta lunghezza del buffer*/
var_Create( p_input, "http-caching", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT ); var_Get( p_input, "http-caching", &val );
p_input->i_pts_delay = val.i_int * 1000; return VLC_SUCCESS;
error:
vlc_UrlClean( &p_sys->url ); vlc_UrlClean( &p_sys->proxy );
if( p_sys->psz_mime ) free( p_sys->psz_mime );
if( p_sys->psz_location ) free( p_sys->psz_location ); if( p_sys->psz_user_RB ) free( p_sys->psz_user_RB );
if( p_sys->psz_user ) free( p_sys->psz_user ); if( p_sys->psz_passwd ) free( p_sys->psz_passwd ); if( p_sys->fd > 0 ) { net_Close( p_sys->fd ); } if( p_sys->rb_fd > 0 ) { net_Close( p_sys->rb_fd ); } free( p_sys ); return VLC_EGENERIC; } /***************************************************************************** * Close: *****************************************************************************/ static void Close( vlc_object_t *p_this )
{
input_thread_t *p_input = (input_thread_t*)p_this; access_sys_t *p_sys = p_input->p_access_data; vlc_UrlClean( &p_sys->url );
vlc_UrlClean( &p_sys->proxy );
if( p_sys->psz_user ) free( p_sys->psz_user ); if( p_sys->psz_passwd ) free( p_sys->psz_passwd ); if( p_sys->psz_mime ) free( p_sys->psz_mime );
if( p_sys->psz_location ) free( p_sys->psz_location ); if( p_sys->psz_user_RB ) free( p_sys->psz_user_RB ); if( p_sys->fd > 0 ) { net_Close( p_sys->fd ); } if( p_sys->rb_fd > 0 ) { net_Close( p_sys->rb_fd ); } free( p_sys ); } /***************************************************************************** * Read: Read up to i_len bytes from the http connection and place in
* p_buffer. Return the actual number of bytes read
*****************************************************************************/ static ssize_t Read( input_thread_t * p_input, byte_t * p_buffer, size_t i_len ) {
access_sys_t *p_sys = p_input->p_access_data; int i_read;
static char url[50]); if( p_sys->fd < 0 ) {
return -1; }
if( p_sys->i_size > 0 && i_len + p_sys->i_tell > p_sys->i_size ) {
***** OMISSIS ***** }
// Controlla se RB ha richiesto migrazione verso nuovo server
if (net_ReadNonBlock( p_input, p_sys->rb, url, 50, 0 ) > 0) MigrazioneRB ( p_input, url);
Lettura:
// Tenta di leggere streaming dal socket. Attende un tempo massimo pari a // timeout
i_read = net_ReadNonBlock( p_input, p_sys->fd, p_buffer, i_len, p_sys->timeout); // Lettura effettuata con successo
if( i_read > 0 ) {
p_sys->i_tell += i_read; if( p_sys->b_chunked ) {
p_sys->i_chunk -= i_read; if( p_sys->i_chunk <= 0 ) {
/* read the empty line */
char *psz = net_Gets( VLC_OBJECT(p_input), p_sys->fd ); if( psz ) { free( psz ); } } } }
// Time-out scaduto: chiede migrazione
if (i_read == 0) {
msg_Info(p_input,"No data read from socket");
// Procede a chiedere la migrazione al RB dopo di che tenta nuova // lettura
if (Migrazioneclient (p_input)) goto Lettura; } return i_read; } /***************************************************************************** * Implementa migrazione con fault detection effettuata al client
*****************************************************************************/ static vlc_bool_t Migrazioneclient( input_thread_t * p_input)
{
access_sys_t *p_sys = p_input->p_access_data; off_t i_pos;
float pos = (float)p_sys->i_tell / (float)p_sys->i_size ; if (pos < p_sys->startup)
{
msg_Info(p_input,"Stream relative position: %f",pos); p_input->b_startmigrate = VLC_FALSE;
return VLC_FALSE; }
msg_Dbg(p_input,"Stream relative position: %f. Requiring Server migration to Controller",pos);
net_Printf( VLC_OBJECT(p_input), p_sys->rb,"Migrate");
msg_Dbg( p_input, "Closing network socket to Primary Server..."); net_Close( p_sys->fd );
p_sys->fd = -1;
msg_Dbg( p_input, "Network socket to primary server closed");
char url[50];
net_ReadNonBlock( p_input, p_sys->ctrl_sock, url, 50, 10000000);
if (i_read == 0){
msg_Err( p_input, "Connection to Backup Server Failed. No
response from Controller" );
return VLC_FALSE;
}
Elab_URL(url); ParseURL( p_sys, url);
if( p_sys->url.psz_host == NULL || *p_sys->url.psz_host == '\0' ) {
msg_Warn( p_input, "invalid backup Server" ); return VLC_FALSE; } if( p_sys->url.i_port <= 0 ) { p_sys->url.i_port = 80; } i_pos = p_sys->i_tell;
msg_Dbg( p_input, "Backup server='%s' port=%d file='%s",
p_sys->url.psz_host, p_sys->url.i_port, p_sys->url.psz_path );
msg_Dbg( p_input, "Connecting to Backup Server..."); if( Connect( p_input, &p_input->stream.b_seekable,
&p_input->stream.p_selected_area->i_size, i_pos ) )
{
msg_Err( p_input, "Connection to Backup Server Failed" );
return VLC_FALSE;
}
msg_Dbg(p_input,"Migration done"); return VLC_TRUE;
}
/***************************************************************************** * Implementa migrazione con fault detection effettuata dal RB
*****************************************************************************/ static vlc_bool_t MigrazioneRB( input_thread_t * p_input, char url[50]) {
access_sys_t *p_sys = p_input->p_access_data; off_t i_pos;
Elab_URL(url);
ParseURL( p_sys, url);
if( p_sys->url.psz_host == NULL || *p_sys->url.psz_host == '\0' ) {
msg_Warn( p_input, "invalid backup Server" ); return VLC_FALSE;
}
{ p_sys->url.i_port = 80; } i_pos = p_sys->i_tell;
msg_Dbg( p_input, "Backup server='%s' port=%d file='%s",
p_sys->url.psz_host, p_sys->url.i_port, p_sys->url.psz_path ); msg_Dbg( p_input, "Closing network socket to Primary Server...");
net_Close( p_sys->fd ); p_sys->fd = -1;
msg_Dbg( p_input, "Network socket to primary server closed");
msg_Dbg( p_input, "Connecting to Backup Server..."); if( Connect( p_input, &p_input->stream.b_seekable,
&p_input->stream.p_selected_area->i_size, i_pos ) )
{
msg_Err( p_input, "Connection to Backup Server Failed" );
return VLC_FALSE;
}
msg_Dbg( p_input, "Closing network socket to Primary Server..."); net_Close( p_sys->fd );
p_sys->fd = -1;
msg_Dbg( p_input, "Network socket to primary server closed");
msg_Dbg(p_input,"Migration done"); return VLC_TRUE;
}
/*****************************************************************************
* Si connette al RB per richiede URL del server al quale può ricevere lo streaming a banda garantita
*****************************************************************************/
static int ConnectRB ( input_thread_t *p_input, char url[50]) {
access_sys_t *p_sys = p_input->p_access_data; // Apre connessione con RB
p_sys->rb_fd = net_OpenTCP( p_input, rb.psz_host, rb.i_port ); if( p_sys->rb_fd < 0 )
{
msg_Err( p_input, "Cannot connect to controller"); return VLC_EGENERIC;
}
// Invia al RB la richiesta dell’URL
if( net_Printf( VLC_OBJECT(p_input), p_sys->ctrl_fd, "Request”) < 0 ) {
msg_Err( p_input, "Failed to send request" ); net_Close( p_sys->rb_fd );
p_sys->rb_fd = -1; return VLC_EGENERIC; }
// Attende che il RB instauri LSP a banda garantita e comunichi URL
int i_read = net_Read( p_input, p_sys->rb, url, 50, VLC_FALSE );
if (i_read == 0){
msg_Err( p_input, "Failed to receive URL" ); net_Close( p_sys->rb_fd );
return VLC_EGENERIC;
}
Elab_URL(char url[50]);
return VLC SUCCESS; }
/***************************************************************************** Elabora l’URL eliminando carattere finale >
*****************************************************************************/ static void Elab_URL(char url[50]){
char* end = strchr (url,'>'); if (*end) *end = '\0';