Archives par étiquette : netcat

Raspberry Pi Camera – 5 façons de faire du streaming

IMG_8806Le module Raspberry Pi Camera (et la version sans filtre IR, le module NoIR) sont de petits circuits (2,5cm x 2,5cm) dotés d’un capteur photo de 2592 x 1944 pixels capable d’enregistrer en 1080p à 30 images par secondes (ou 60 fps en 720p). Ce module se branche directement sur le port CSI du Pi prévu à cet effet.

La version NoIR permet de voir les infra-rouge, ce qui autorisera une vision nocturne si on le couple à un projecteur infra-rouge comme expliqué à fin de cet article : Système de vidéo-surveillance abordable avec des Raspberry Pi

Que ce soit pour un système de vidéo surveillance ou pour le pilotage d’un robot à distance, il faut pouvoir récupérer le flux vidéo et le diffuser à travers le réseau (streaming). Nous allons voir dans cet article 5 méthodes pour diffuser le flux vidéo d’un module Raspberry Pi Camera, plus ou moins efficacement.

Continuer la lecture

10 – Module 7 – VPN

J’utilise un petit serveur VPN PPTP pour que mes amis et moi puissions facilement échanger des fichiers ou jouer ensemble en réseau 🙂 C’est très facile à mettre en place aussi bien coté serveur en installant le paquet pptpd, que coté client car c’est nativement supporté par Windows.

Ce module me permet d’afficher la liste des personnes qui sont connectées à mon serveur VPN PPTP.

jarvis_screenshot_VPNJe ne détail pas dans cet article comment installer et configurer PPTPD. Voici un tutoriel qui vous aidera à mettre en place ce type de VPN : https://help.ubuntu.com/community/PPTPServer

Le serveur pptpd étant installé sur ma gateway, il faut procéder de la même manière que pour le module graphique de la bande passante pour transférer les données sur le Pi en utilisant netcat. La seule chose de nouveau ici est la commande last qui permet de récuppérer les informations de connexion des clients du VPN.

Transférer les données vers le Pi

Côté Pi (serveur netcat) :

#!/bin/bash

### BEGIN INIT INFO
# Provides:          nc_vpn_srv
# Required-Start:
# Required-Stop:
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: vpn for Jarvis
# Description:       Enable service provided by daemon.
### END INIT INFO

dst_port=12346
dst_dir=/home/jarvis/vpn
dst_file=vpn_oberon.log

nc_vpn()
{
  while [ "true" ]
  do
    nc -q 1 -u -l 12346 > $dst_dir/$dst_file < /dev/null
    sleep 5
  done
}

case "$1" in
        stop)
                echo " Stoping vpn for Jarvis..."
                killall vpn
                killall nc
                ;;
        start)
                echo " Starting vpn for Jarvis..."
                nc_vpn&
                exit 0
                ;;
        *)
                exit 1
                ;;
esac

exit 0

Côté gateway (client netcat) :

#! /bin/bash

### BEGIN INIT INFO
# Provides:          nc_vpn_clt
# Required-Start:
# Required-Stop:
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: vpn for Jarvis
# Description:       Enable service provided by daemon.
### END INIT INFO

src_port=8889
dst_port=12346
dst_host=10.0.0.1

nc_vpn()
{
        while [ "true" ]
        do
                last | grep ppp | grep "logged in" | nc -q 1 -p $src_port -u $dst_host $dst_port
                sleep 5
        done
}

case "$1" in
        stop)
                echo " Stoping vpn for Jarvis..."
                killall vpn
                killall nc
                ;;
        start)
                echo " Starting vpn for Jarvis..."
                nc_vpn&
                exit 0
                ;;
        *)
                exit 1
                ;;
esac

exit 0

Excécutez ces scripts au démarrage du système en les placants dans le répertoire /etc/init.d puis exécutant la commande suivante :

update-rc.d nom_du_script.sh defaults

index.php

Une simple <div> suffit car nous voulons simplement afficher une liste d’utilisateurs :

<div id="vpn"></div>

style.css

Un petit peu de mise en forme pour faire joli 🙂

/* vpn */

div#vpn
{
  left              : 550px;
  bottom            : 10px;
  position          : absolute;
  overflow          : hidden;
  background-color  : rgba(0, 0, 0, 1);
  color : #FFF;
}

td.vpn
{
  text-align        : left;
  font-size         : 30px;
  padding           : 5px;
}

img.vpn
{
  width : 20px;
  height : 20px;
}

javascript.js

Une simple requête AJAX permet de récupérer les données à afficher.

/* VPN */

var vpn_timeout;

function vpn ()
{
  $.ajax({
    async : false,
    type: "GET",
    url: "./ajax.php",
    data: "block=vpn",
    success: function(html){
      $("#vpn").html(html);
    }
  });

  vpn_timeout = setTimeout("vpn()", 5000);
}

ajax.php

Rien de particulier pour ce module :

  /////////////////////////////////////////////////
  //  VPN PPTPD
  /////////////////////////////////////////////////

  if($block == 'vpn'){
    echo vpn();
  }

inc.php

Deux fonctions sont nécessaires pour ce module :

  • vpn_parseData() : parse le fichier envoyé à travers netcat
  • vpn() : créé un tableau HTML avec les noms des utilisateurs connectés
  /////////////////////////////////////////////////
  //  VPN PPTPD
  /////////////////////////////////////////////////

  function vpn () {

    $datas = vpn_parseData ("/home/jarvis/vpn/vpn_oberon.log");

    $html  = '';

    if(sizeof($datas) > 0){
      $html .= '<table cellspacing="0px">';
      foreach($datas as $data){
        $html .= '<tr>';
        $html .= '<td valign="middle"><img class="vpn" src="pict/vpn.png"></td><td class="vpn">'.$data[0].'</td>';
        $html .= '</tr>';
      }
      $html .= '</table>';
    }

    return $html;
  }

  function vpn_parseData ($stat_file) {
    $datas = array();
    if(filemtime($stat_file) < time()-10){return $datas;}
    $stats = fopen($stat_file, 'r');
    while (($line = fgets($stats)) !== false) {
      $explode_line = str_word_count($line, 1, "0123456789.");
      $datas[]  = $explode_line;
    }
    fclose($stats);
    return $datas;
  }

Et voilà pour ce dernier module qui s’avère très simple 🙂

9 – Module 6 – Graphique de la bande passante

Pour diverses raisons, il peut intéressant de s’avoir si notre bande passante internet est saturée ou non. Ce module affiche un historique d’environ 5 minutes de l’utilisation de la bande passante descendante (download) et montante (upload). De cette manière, je peux voir en un seul coup d’oeil si quelque chose d’anormal se passe sur mon réseau.

jarvis_screenshot_ifstat

Introduction

Ce module est de loin le plus compliqué de tous. D’une part, il va falloir récupérer le débit instantané utilisé par l’interface réseau de la gateway qui est reliée à la Box internet. Puis, il va falloir transmettre ces données au Pi sur lequel fonctionne le dashscreen. Enfin, il faudra créer un graphique pour représenter ces informations…

En effet, j’ai choisi de ne pas utiliser de soft type mrtg qui sont spécialisés pour ce genre de chose. Je préfère installer le minimum de soft, et utiliser quelques commandes de base. Pour faire quelque chose de simple (comme afficher la bande passante sur la graphique), pas besoin de sortir l’artillerie lourde 🙂 Et puis …si on ne se compliquait pas la vie, ce serait beaucoup moins drôle, n’est ce pas ? 😉

Mesurer la bande passante

ifstat est un petit outil en ligne de commande qui affiche les statistiques d’utilisation d’une interface réseau. Dans un terminal, taper la commande suivante :

ifstat -n -i eth0

Et vous obtiendrait en continue, quelque chose dans le genre :

       eth0       
 KB/s in  KB/s out
    0.45      0.06
    0.71      0.39
    2.85      0.76
    0.57      0.06
    1.86      0.19
    0.45      0.06
    0.45      0.06
    0.45      0.06
    0.57      0.06
    0.59      0.13
    0.45      0.06
    0.45      0.06
    0.59      0.26
    0.57      0.06
    1.74      0.13
    ...

Chaque seconde on obtient le débit instantané (ou presque), en KBytes/s, c’est à dire en Ko/s 🙂 C’est exactement ce qu’il nous faut 🙂 Il convient maintenant d’envoyer ces informations en continue sur notre Pi.

Transmettre les données au Pi à travers le réseau

Le moyen le plus simple de transmettre une info d’un ordinateur à un autre c’est de les envoyer dans des paquets UDP… C’est tellement trivial qu’il ma fallu plusieurs jours avant d’en avoir l’idée !

La commande netcat est tout à fait appropriée pour ce type d’opération. Sur une machine A qui joue le rôle de serveur faites :

nc -u -l 12345
  • -u : pour utiliser l’UDP
  • -l : pour passer en mode écoute (serveur)
  • 12345 : un numéro de port découte

Puis sur une machine B qui joue le rôle de client, faites :

nc -p 8888 -u 10.0.0.1 12345
  • -p 8888 : un port source
  • -u : pour utiliser l’UDP
  • 10.0.0.1 : adresse IP de la machine A (serveur)
  • 12345 : port d’écoute de la machine A (serveur)

Et hop, tout ce que vous tapez au clavier sur B, s’affiche sur A 🙂

Albert Einstein disait « Tout devrait être rendu aussi simple que possible, mais pas plus ! ».

A méditer 😉

Pour transmettre les données renvoyées par la commande ifstat à travers netcat, nous utiliserons un pipe. Voici les deux scripts complets (client/serveur) pour réaliser cette opération :

  • Script serveur à exécuter sur le Pi nc_ifstat_srv.sh :
### BEGIN INIT INFO 
# Provides: nc_ifstat_srv 
# Required-Start: 
# Required-Stop: 
# Default-Start: 2 3 4 5 
# Default-Stop: 0 1 6 
# Short-Description: ifstat for Jarvis 
# Description: Enable service provided by daemon. 
### END INIT INFO

dst_port=12345
dst_dir=/home/jarvis/ifstat
dst_file=eth0.log

nc -u -l $dst_port >> $dst_dir/$dst_file&
  • Script client à exécuter sur votre gateway/routeur nc_ifstat_clt.sh  :
### BEGIN INIT INFO
# Provides:          nc_ifstat_clt
# Required-Start:
# Required-Stop:
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: ifstat for Jarvis
# Description:       Enable service provided by daemon.
### END INIT INFO

src_port=8888
dst_port=12345
dst_host=10.0.0.2
eth=eth0

nc_ifstat()
{
	while [ "true" ]
	do
  		ifstat -n -i $eth | nc -p $src_port -u $dst_host $dst_port
  		sleep 5
	done
}

case "$1" in
        stop)
		echo " Stoping ifstat for Jarvis..."
                killall ifstat
		killall nc
		;;
        start)
		echo " Starting ifstat for Jarvis..."
		nc_ifstat&
		exit 0	
                ;;
        *)
                exit 1
                ;;
esac

exit 0

Pour exécuter le script au démarrage de la machine, placer le dans le répertoire /etc/init.d puis lancer la commande :

update-rc.d nom_du_script.sh defaults

A ce stade, vous devriez avoir un fichier sur votre Pi dans lequel, chaque seconde, la bande passante instantanée y est ajoutée en fin de fichier 🙂 Il ne nous reste plus qu’à lire ce fichier avec un script PHP, et dessiner le graphique pour représenter les données qu’il contient 🙂

Création du graphique en PHP

Ici encore, j’aurais pu utiliser une lib graphique en PHP, en JavaScript ou en n’importe quoi d’autre. Mais au lieux de sous exploiter une usine à gaz difficilement personnalisable, j’ai préféré créer ma propre fonction graphique en PHP. Vous allez voir que c’est beaucoup plus simple que ce qu’on peut s’imaginer 🙂

Voici ma fonction imagickHisto() :

function imagickHisto ($max, $eth = '', $up_down = 'down') {

  $datas = parseData ("eth0.log", $up_down);

  $width            = 304; // largeur du graphique
  $height           = 100; // hauteur du graphique
  $padding          = 1;
  $ticks            = 5;
  $background_color = '#000'; // couleur du fond
  $axes_color       = '#555'; // couleur des axes

  if($up_down == 'down'){
    $data_color       = '#1D1'; // couleur du graphique pour le download
  }
  else{
    $data_color       = '#D11'; // couleur du graphique pour l'upload
  }

  $nb_values        = $width - 2*$padding - 2;
  $max_value        = $height - 2*$padding - 4;

  $nb_datas         = sizeof($datas);
  $trim             = $nb_values - $nb_datas;

  if($trim < 0){$trim = 0;}

  $image = new Imagick();
  $image ->newImage( $width, $height, new ImagickPixel($background_color) );
  $draw  = new ImagickDraw();
  $draw->setStrokeColor( new ImagickPixel($axes_color) );

  $xx1    = $padding;
  $xy1    = $height - $padding - 1;
  $xx2    = $width - $padding - 1;
  $xy2    = $xy1;
  $yx1    = $xx1;
  $yy1    = $xy1;
  $yx2    = $yx1;
  $yy2    = $padding;
  $half_y = $height/2;
  $half_x = $width/2;

  $draw->line  ( $xx1, $xy1, $xx2, $xy2 );
  $draw->line  ( $yx1, $yy1, $yx2, $yy2 );

  $draw->line  ( $yx1, $yy2, $yx1+$ticks, $yy2 );
  $draw->line  ( $yx1, $half_y, $yx1+$ticks, $half_y );

  $draw->setStrokeColor( new ImagickPixel($data_color) );

  $first_x = $xx1 + 1 + $trim;
  $last_x  = $xx2 - 1;
  $first_y = $xy1 - 1;
  $last_y  = $yy2 + 1;

  for($i=0;$i<$nb_values;$i++){
    if(isset($datas[$i])){
      $value   = $datas[$i]*$max_value/$max;
      $value_y = $first_y - $value;
      $value_x = $first_x + $i;
      $draw->line  ( $value_x, $first_y, $value_x, $value_y );
    }
  }

  $image->drawImage( $draw );

  $text_draw = new ImagickDraw();
  $text_draw->setFillColor($axes_color);
  $text_draw->setFontSize( 12 );
  $image->annotateImage($text_draw, $half_x-20, $padding+10, 0, "$eth - $up_down");

  $image->setImageFormat( "png" );
  header( "Content-Type: image/png" );
  echo $image;
  exit;
}

Veuillez accepter mes excuses pour le manque cruel de commentaire dont fait l’objet cette fonction. Pour résumer, la fonction prend trois paramètres :

  • $max : la valeur max (en Ko) pour borner le graphique. Par exemple, mon débit réel maximum atteint 1800 Ko/s. Je choisie donc $max = 2000.
  • $eth : nom de l’interface (exemple eth0)
  • $up_down : « up » ou « down » pour spécifier la couleur du graphique ainsi que les données à afficher issue de ifstat

La fonction lit un tableau de donnée renvoyé par la fonction parseData(), puis dessine sur le graphique une barre de 1px de large par donnée. Avec une largeur de 300px, on peut donc afficher 5 minutes d’historique de données 🙂

Voici la fonction parseData() dont le rôle est de lire le fichier contenant les données issues de la commande ifstat :

  function parseData ($stat_file, $up_down) {
    $datas = array();
    if(filemtime($stat_file) < time()-10){return $datas;}
    $stats = fopen($stat_file, 'r');
    while (($line = fgets($stats)) !== false) {
      $explode_line = str_word_count($line, 1, "0123456789.");
      if($up_down == 'down') {
        $datas[]  = $explode_line[0];
      }
      else{
        $datas[]  = $explode_line[1];
      }
    }
    fclose($stats);
    $datas = array_slice($datas, -300);
    return $datas;
  }

Cette fonction prend deux paramètres :

  • $stat_file : fichier à parser
  • $up_down : « up » ou « down » pour distinguer les données d’upload et de download

Pour la suite, nous reprennons la même démarche que pour les autres modules 🙂

index.php

Il faut une div par graphique ; nous en ajoutons donc deux au fichier index.php, une pour l’upload et une pour le download.

 <div id="ifstat_eth0_up"><img id="img_eth0_up" src="pict/blank.png"></div>
 <div id="ifstat_eth0_down"><img id="img_eth0_down" src="pict/blank.png"></div>

Comme pour le module Xplanet, il convient d’initier la source des balises images <img> avec une image vide blank.png.

style.css

Il suffit ici de positionner nos deux <div> :

/* ifstat */

div#ifstat_oberon_up
{
  right             : 20px;
  bottom            : 20px;
  position          : absolute;
  overflow          : hidden;
  background-color  : rgba(0, 0, 0, 1);
}

div#ifstat_oberon_down
{
  right             : 340px;
  bottom            : 20px;
  position          : absolute;
  overflow          : hidden;
  background-color  : rgba(0, 0, 0, 1);
}

javascript.js

Une simple requête AJAX permet de récupérer les graphiques à afficher.

/* ifstat */

var ifstat_timeout;

function ifstat () {

  var now             = new Date().getTime();

  var url_down = "ajax.php?block=ifstat&eth=wan&up_down=down&max=2000&hour="+now;
  var img_eth0_down = $("<img />").attr("src", url_eth0_down);
  $("#img_eth0_down").attr("src", url_eth0_down);

  var url_up   = "ajax.php?block=ifstat&eth=wan&up_down=up&max=150&hour="+now;
  var img_eth0_up = $("<img />").attr("src", url_eth0_up);
  $("#img_eth0_up").attr("src", url_eth0_up);

  ifstat_timeout = setTimeout("ifstat()", 5000);
}

Même principe que pour le module Xplanet, il convient de précharger les images avant de les afficher. Je fixe le délais de rafraichissement à 5 secondes, ce qui est suffisant.

ajax.php

Le code à ajouter dans ce fichier reste élémentaire comme pour les autres modules. Il ne faut toutefois pas oublier de prendre en compte les paramètres de la fonction imagickHisto() :

  /////////////////////////////////////////////////
  //  IFSTAT
  /////////////////////////////////////////////////

  if($block == 'ifstat'){
    imagickHisto ($_REQUEST['max'], $_REQUEST['eth'], $_REQUEST['up_down']);
  }


inc.php

Dans ce fichier, il suffit de copier-coller les fonctions imagickHisto() et parseData() qui ont été décrites plus haut dans cet article.

Voilà le rendu final en gros plan, lorsque la bande passante est très sollicitée :

ifstat