• Non ci sono risultati.

Appendice C - Implementazione dello schema di migrazione integrato

N/A
N/A
Protected

Academic year: 2021

Condividi "Appendice C - Implementazione dello schema di migrazione integrato"

Copied!
18
0
0

Testo completo

(1)

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;

(2)

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

(3)

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[]);

(4)

// 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;

(5)

}

// 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.

(6)

Ciascuna entry nel file dovrà avere il formato

[URL contenuto]

> [Indirizzo IP router] [nome logical-router]

Per esempio

10.0.30.2/starguitar.vob

>

2

10.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

(7)

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 1

enum 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)

{

(8)

};

// 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){

(9)

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; }

(10)

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

(11)

#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 */

(12)

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 );

(13)

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 );

(14)

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 ***** }

(15)

// 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; }

(16)

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;

}

(17)

{ 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 );

(18)

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';

Riferimenti

Documenti correlati