commit 5c269302ed02948fe97c37e6ce15d0ca5c17231a Author: yorick Barbanneau Date: Fri Oct 12 23:06:04 2018 +0200 First commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..364fdec --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +public/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..2e1e90c --- /dev/null +++ b/README.md @@ -0,0 +1,51 @@ +Notes de cours et TD machines +----------------------------- + +Dépôt git pour la construction d'un sitre statique avec +[Hugo](https://gohugo.io) reprenant l'ensemble de mes notres de cours et TM +machine mises au propre (J'ai beaucoup de retard...) + +Je rajouterai plus tard un `makefile` pour la construction de fichiers PDF avec +[pandoc](https://pandoc.org/) + +## Construction du site + +### Installer le thème + +Pour que la construction du site fonctionne, il faut installer le thème visuer +choisi (ici er). Il est présent sous la forme d'un `submodule` git au'il faut +initialiser (dans le répertoire racine du dépôt). + +```shell +git submodule init && git submodule update +``` + +### Version locale du site + +Pour construite le site, il faut au préalable installer hugo, sur Archlinux : + +```shell +# pacman -S hugo +``` + +Pour activer le serveur web intégré à Hugo, il suffit de lancer la commande +(dans le répertoire racine du dépôt) : + +```shell +$ hugo server -D --disableFastRender -v +``` + +Il est possible de rajouter l'option `--debug` afin d'afficher plus +d'information sur la sortie standard. Une fois ce mode activé, il suffit +d'ouvrir son navigateur er d'aller à l'adresse *http://localhost:1313*. + +## Site en ligne + +Le site n'est pas encore accessible en ligne, un jour peut-être... + +## Bugs + +C'est la première fois que j'utilise un générateur de site statique, le +focntionnement du site n'est donc pas optimal. Les pages **tags** et +**catégories** ne fonctionnent pas (pages blanches) pour une raison encore +mystérieuse. diff --git a/archetypes/default.md b/archetypes/default.md new file mode 100644 index 0000000..00e77bd --- /dev/null +++ b/archetypes/default.md @@ -0,0 +1,6 @@ +--- +title: "{{ replace .Name "-" " " | title }}" +date: {{ .Date }} +draft: true +--- + diff --git a/config.toml b/config.toml new file mode 100644 index 0000000..217ce30 --- /dev/null +++ b/config.toml @@ -0,0 +1,25 @@ +baseURL = "https://lpro.epha.se" +languageCode = "fr" +defaultContentLanguage = "fr" +title = "Licence pro ADSILLH - Cours et TD" +pygmentsCodeFences = true +pygmentsUseClasses = true +theme = "mainroad" +rssLimit = 10 +paginate = 10 + +[taxonomies] + category = "categories" + tag = "tags" + +[Params] + toc = true + post_navigation = true + postSections = ["reseau", "progsys", "installations", "bdd"] + +[Params.sidebar] + home = "right" # Configure layout for home page + list = "left" # Configure layout for list pages + single = false # Configure layout for single pages + # Enable widgets in given order + widgets = ["search", "categories", "taglist"] diff --git a/content/bdd/1-introduction/files/bibliotheque_creation.sql b/content/bdd/1-introduction/files/bibliotheque_creation.sql new file mode 100644 index 0000000..b52292f --- /dev/null +++ b/content/bdd/1-introduction/files/bibliotheque_creation.sql @@ -0,0 +1,43 @@ +CREATE SCHEMA Bibliotheque; +SET search_path TO Bibliotheque, public; +CREATE TYPE Bibliotheque.Sexe AS ENUM ('F', 'M'); +CREATE TYPE Bibliotheque.Etat AS ENUM ('Neuf', 'Bon', 'Use'); +CREATE TABLE Bibliotheque.Lecteur ( + num_lecteur serial NOT NULL, + nom text NOT NULL, + sexe Bibliotheque.Sexe NOT NULL, + -- age devient date de naissance + naissance date NOT NULL, + ville text NOT NULL, + -- clefs candidates + PRIMARY KEY (num_lecteur) +); +CREATE TABLE Bibliotheque.Livre ( + isbn integer NOT NULL, + titre text NOT NULL, + auteur text NOT NULL, + editeur text NOT NULL, + annee interval YEAR NOT NULL, + -- clefs candidates + PRIMARY KEY (isbn) +); +CREATE TABLE Bibliotheque.Exemplaire ( + num_exemplaire serial NOT NULL, + isbn integer NOT NULL, + date_achat date NOT NULL, + etat Bibliotheque.Etat NOT NULL, + -- clefs candidates + PRIMARY KEY (num_exemplaire), + -- Clefs étrangères + FOREIGN KEY (isbn) REFERENCES Bibliotheque.Livre(isbn) +); +CREATE TABLE Bibliotheque.Emprunt ( + num_exemplaire serial NOT NULL, + num_lecteur serial NOT NULL, + date_emprunt date NOT NULL, + -- clefs candidates + PRIMARY KEY (num_exemplaire, num_lecteur), + -- Clefs étrangères + FOREIGN KEY (num_exemplaire) REFERENCES Bibliotheque.Exemplaire(num_exemplaire), + FOREIGN KEY (num_lecteur) REFERENCES Bibliotheque.Lecteur(num_lecteur) +); diff --git a/content/bdd/1-introduction/files/cours1.pdf b/content/bdd/1-introduction/files/cours1.pdf new file mode 100644 index 0000000..6ddedce Binary files /dev/null and b/content/bdd/1-introduction/files/cours1.pdf differ diff --git a/content/bdd/1-introduction/files/schema_avions.sql b/content/bdd/1-introduction/files/schema_avions.sql new file mode 100644 index 0000000..3578f62 --- /dev/null +++ b/content/bdd/1-introduction/files/schema_avions.sql @@ -0,0 +1,41 @@ +-- schema de Base de données pour la gestion d'une compagnie aérienne. +CREATE SCHEMA aerocremi; +SET search_path TO aerocremi, public; + +CREATE TABLE aerocremi.avion( + -- Je pars du principe que le numéro de série est donné par le fabricant + -- de l'avion et qu'il ne contient que des chiffres. Il ne peut donc pas + -- être du type serial. + num_serie integer NOT NULL, + type text NOT NULL, + capacite integer NOT NULL, + PRIMARY KEY (num_serie) +); + +CREATE TABLE aerocremi.pilote( + matricule serial NOT NULL, + nom text NOT_NULL, + anciennete date, + PRIMARY KEY (matricule) +); + +CREATE TABLE aerocremi.vol( + num_vol text NOT NULL, + -- Je part du principe qu'il faut gérer les times zones sur les horaires + -- de vol (logique pour une compagnie aérienne) + -- https://www.postgresql.org/docs/current/static/datatype-datetime.html + heure_depart time with time zone NOT NULL, + heure_arrivee time with time zone NOT NULL, + PRIMARY_KEY (num_vol) +); + +CREATE TABLE aerocremi.planning( + num_planning serial NOT NULL, + num_vol text NOT NULL, + matricule integer NOT NULL, + date_vol date NOT NULL + PRIMARY KEY (num_planning), + FOREIGN KEY num_vol REFERENCES aerocremi.vol(num_vol), + FOREIGN KEY num_avion REFERENCES aerocremi.avion(num_serie), + FOREIGN KEY matricule REFERENCES aecrocremi.pilote(matricule) +); diff --git a/content/bdd/1-introduction/files/td1.pdf b/content/bdd/1-introduction/files/td1.pdf new file mode 100644 index 0000000..f1e28be Binary files /dev/null and b/content/bdd/1-introduction/files/td1.pdf differ diff --git a/content/bdd/1-introduction/index.md b/content/bdd/1-introduction/index.md new file mode 100644 index 0000000..2f0765a --- /dev/null +++ b/content/bdd/1-introduction/index.md @@ -0,0 +1,31 @@ +--- +title : "Base de données : Introduction" +date: 2018-09-10 +categories: ["Base de données", "Cours"] +--- + +Lors de ce cours, nous allons créer une application web de gestion d'un hôtel : +gestion des réservation et des factures. + +## Qu'est ce qu'une application web + +C'est une application de type client <> serveur disponible via un navigateur +web. Elle est conçue à partir d'un ensemble de sources (au sens code source) +hétérogène : HTML, CSS et javascript côté client; PHP, Python perl etc +côté serveur. + +On compte 3 types d'applications web : + + - **statique** (un site web basique) + - dynamique **côté serveur** + - dynamique *côté client et serveur** + +## Processus de création d'une base de données + + 1- données du "monde réel" + 2- réel perçu + 3- données et contraintes + 4- modèle relationnel + 5- implémentation dans un SGBDR *(Système de Gestion de Base de Données + Relationnelles) + diff --git a/content/bdd/2-definitions/indev.md b/content/bdd/2-definitions/indev.md new file mode 100644 index 0000000..6c65f41 --- /dev/null +++ b/content/bdd/2-definitions/indev.md @@ -0,0 +1,113 @@ +--- +title: "Base de données : définitions" +date: 2018-09-17 +modify: 2018-09-24 +categories: ["Base de données", "cours"] +--- + +## Le domaine + +Il représente l'ensemble des valeurs autorisées pour une information. Cette +notion est très proche [de domaine de définition](w_dom-def) en mathématiques. +On le décompose en deux grandes familles.: + + - **élémentaire** : les types de base comme les entiers, réels, chaines de + caractères mais aussi les intervales ou les listes de valeurs + - **structuré** : des types de valeurs plus structurée comme pas exemple la + notion de point définit pat une composant `X` et `Y`. + +[w_dom-def]:https://fr.wikipedia.org/wiki/Ensemble_de_d%C3%A9finition + +## Le produit cartésien + +Le produit cartésien des domaines $D_{1} D_{2}$ représente l'ensemble +des valeurs contenue dans $D_{1}$ et $D_{2}$, il est noté + +$$ + D_{1} \times D_{2} +$$ + +## La relation + +Elle représente un sousrensemble r du produit carthésien. Elle est caractérisée +par un nom. + +## Tuple ou n-tuple + +Il représente une ligne dans une relation + +## Attributs + +Nom donné à un colonne. Il est composé d'un indentifiant et d'un domaine + +## Schéma de relation + +Il ets définis par un ensemble d'attributs U et un ensenble de contraintes. on +le note courrament R(U), R(U) décrit l'intention de la relation. La relation +(tableau + valeurs) définit une extention. + +Une relation `r` est une instance finie d'un schema de relation notée `r:R(U)`, +exemple : + +``` +AlimentsPreferes(nom,type,origine,bio) +``` + +## La base de données + +Un schéma de base de données et un ensemble de schemas de relation liés par des +dépendances référencielles (un type de contraines). Une base de données est +alors un ensemble de relations (extensions) associées au schéma et verifiamts +ses contraines. + +## Le modèle relationnel + +Il est définis en 1970 par *E. F. Codd* (IBM Research Lab) et se veut +indépendant de la representation physique des données. Il a une assise +mathématique forte ([algèbre relationnelle](w_algebre-r), [formes +normales](w_form-norm)). + +[w_algebre-r]:https://fr.wikipedia.org/wiki/Alg%C3%A8bre_relationnelle +[w_form-norm]:https://fr.wikipedia.org/wiki/Forme_normale_(bases_de_donn%C3%A9es_relationnelles) + +### Objectifs généraux + + - Éliminer les comportements anormaux lors des mises à jour des données. + - Éliminer les données redondantes. + - Meilleures compréhension des relationssémantiques entres les données. + +### Buts + +Éliminer les anomalies de la relation universelle (tous les attributs sur toutes +les colonnes) pour faciliter la manipulation des relation. En un mot normaliser +les relations. + +### Méthode + +Décomposer la relation universelle en sous-relations qui ne souffre pas des +anomalies de la relation universelle. + + - conserve toutes les données + - conserve un minimum de contraintes + +### Les types de contraintes + + - sur les attributs : valeur nulle autorisées (ou non), valeur imposée ... + - sur les n-uplets (plusieurs valeurs) : l'exemple d'une bibliothèque, la date + de retour d'un livre doit être suppérieure à la date d'emprunt. + - sur les relations : clé, cardinalité + - sur la base de données : clé étrangères + - sur l'évolution temporelle de la base de données : exemple de l'état civil, + on passe, dans l'ordre de célibataire à marié puis divorcé. On ne peut pas + passer de célibataire à divorcé. + +# La notion de clé + +Une clé doit permettre de trouver un tuple dans une relation avec seulement une +partie des attributs, dit plus simplement, identifier sans équivoque un +enregistrement. + +Du point de vue mathématique, il ne doit pas avoir deux fois le même éléments +dans un ensemble : deux tuples d'une même relation ne peuvent être égaux. + +Soit un ensemble $U\{A_{1}, A_{2}, ..., A_{n}\}$ diff --git a/content/installations/1-LDAP/files/CoursLinux.pdf b/content/installations/1-LDAP/files/CoursLinux.pdf new file mode 100644 index 0000000..2256291 Binary files /dev/null and b/content/installations/1-LDAP/files/CoursLinux.pdf differ diff --git a/content/installations/1-LDAP/files/RZO LDAP.pdf b/content/installations/1-LDAP/files/RZO LDAP.pdf new file mode 100644 index 0000000..37282c3 Binary files /dev/null and b/content/installations/1-LDAP/files/RZO LDAP.pdf differ diff --git a/content/installations/1-LDAP/files/RZO Messagerie cours.pdf b/content/installations/1-LDAP/files/RZO Messagerie cours.pdf new file mode 100644 index 0000000..4b3f480 Binary files /dev/null and b/content/installations/1-LDAP/files/RZO Messagerie cours.pdf differ diff --git a/content/installations/1-LDAP/index.md b/content/installations/1-LDAP/index.md new file mode 100644 index 0000000..53961c6 --- /dev/null +++ b/content/installations/1-LDAP/index.md @@ -0,0 +1,263 @@ +--- +title: Les annuaires LDAP +date: 2018-09-06 +tags: ["annuaire", "LDAP", "LDIG"] +categories: ["Installations", "Cours"] +--- + +**LDAP** pour *Lightweight Directory Access Protocol* est à l'origine un +protocole utilisé pour la modification et la consultation de services +d'annuaire. Il a évolué pour devenir une norme pour les services d'annuaire +incluant un modèle de données, un modèle de nommage, un modèle fonctionnel, un +modèle de sécurité et un modèle de réplication. + +Dérivé du protocole x500, réputé "usine à gaz" complexe à mettre en place et +peu performant, LDAP se veux, comme son nom l'indique plus léger, il est +standardisé par l'IETF. La version actuelle est la LDAPv3 définie dans plusieurs +RFC en commençant par la RFC 4510 + +# Les modèles du LDAPv3 + +Ils sont au nombre de 4 : + + - **le modèle d'information** qui reprend entres autres le schéma, les OID, les + attributs, les classes d'objets + - **le modèle de désignation** qui s'attache au nommage des entrées, à la + hiérarchisation des données, au lien LDAP - DNS + - **le modèle de services** qui décrit les services offerts par le service + d'annuaire + - **le modèle de sécurité** qui défini l'authentification, la confidentialité, + l'intégrité et la gestion des habilitations. + +# Le modèle d'information + +Il décrit principalement le schéma de l'annuaire : les *attributs*, les +*syntaxes*, les *classes d'objets* et les *règles de recherches*. + +## les attributs + +Se sont les éléments de base du schéma décrit comme suit : + +``` +attributetype ( + # identifiant OID unique + NAME # nom de l'attribut + DESC # description de l'attribut + OBSOLETE # indique aue l'attribut est obsolète + SUP # classe parente de l'attribut + EQUALITY # nom de la règle de recherche + ORDERING # nom de la règle d'ordenancement + SUBSTR # nom de la règle de recherche dabs une sous-chaine + # de caractère + SYNTAX # syntaxe de l'attribut + SINGLE-VALUE # indique d'une seule valeur est attendue + COLLECTIVE # indique que le schéma est collectif + NO-USER-MODIFICATION # indique aue l'utilisateur ne peut modifier l'attribut + USAGE # usage de l'attribut. +) +``` + +Voici un exemple concret : + +``` +attributetype ( + 2.5.4.16 + NAME 'postalAddress' + DESC 'RFC2256: postal address' + EQUALITY caseIgnoreListMatch + SUBSTR caseIgnoreListSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 +) +``` + +## Les attributs + +On distingue les **attributs utilisateurs** qui caractérisent l'objet manipulé +par les utilisateurs des **attributs opérationnels** manipulés seulement par le +serveur afin de modifier les données. + +### Les OID - Object IDentifiers + +Ce sont des identifiants universels, représentés par une suite d'entiers séparés +par des points. Il sont organisés sous forme hiérarchique ainsi seul l'organisme +1.2.3 peur donner la signification de 1.2.3.4. + +Leur objectif est d'assurer l'interopérabilité entre différents logiciels et son +utilisés dans le LDAP, mais aussi le SNMP. + +Voir la [liste des OID](https://ldap.com/ldap-oid-reference-guide/)(en). Il est +possible d'utiliser [ce site](http://oid-info.com/get/)(en) pour faire une +recherche par OID. + +## Les syntaxes + +Elles permettent d'indiquer la règle à suivre pour enseigner l'attribut. Si, par +exemple, l'attribut suit une syntaxe dn et l'utilisateur saisit une chaîne de +caractère lambda, l'attribut ne pourra être renseigné. + +## Les classes d'objets + +Ils représentent une collection d'attributs . On peut y définir, par exemple, ce +qui est obligatoire ou facultatif. Voici une description du format : + +``` +ObjectClassDescription ( + # OID de la classe + NAME # nom de la classe + DESC # description de la classe + OBSOLETE # indique que la classe est obsolete + SUP # indique la classe parente + ABSTRACT # Les 3 éléments suivant sont au choix ( voir l'explication + STUCTURAL # ci-dessous + AUXILIARY + MUST () # Liste des attributs obligatoires + MAY () # liste des attributs facultatifs +) +``` + +Voici un exemple concret avec les classes `person` et `organisationnalPerson`: + +``` +( 2.5.6.6 + NAME 'person' + SUP top + STRUCTURAL + MUST ( sn $ cn ) + MAY ( userPassword $ telephoneNumber $ seeAlso $ + description ) +) +( 2.5.6.7 + NAME 'organizationalPerson' + SUP person + STRUCTURAL + MAY ( title $ x121Address $ registeredAddress $ + destinationIndicator $ preferredDeliveryMethod $ + telexNumber $ teletexTerminalIdentifier $ + telephoneNumber $ internationaliSDNNumber $ + facsimileTelephoneNumber $ street $ postOfficeBox $ + postalCode $ postalAddress $ + physicalDeliveryOfficeName $ ou $ st $ l ) + ) +``` + +### Les types de classes d`objets + +Il en existe trois : + + - **abstraites** : ce sont des classe de plus haut niveau non instanciable mais + pouvant être dérivées. la classe d'objets la plus haute étant `top` dont + toute classe dérive + - **structurelles** : sont des classes instanciables. + - **auxiliaires** : sont des classes permettant d'ajouter des attributs + facultatifs à des classes structurelles + +Voir diaporama du cours page 41. + +## Les règles de recherche + +Elles permettent aux serveur de comparer les valeurs des attributs avec celles +demandées dans les requêtes. + +L'exemple ci-dessous présente une règle de recherche sur un entier : + +``` +( +2.5.13.14 +NAME +'integerMatch' +1.3.6.1.4.1.1466.115.121.1.27 ) +``` + +# Le modèle de désignation + +Afin de pouvoir identifier tous les objets dans l'annuaire, il est important de +définir des règles de nommage communes a tous le service d'annuaire. deux +notions importante apparaissent : + + - le **RDN** pour *Relative Distinguished Name* est un nom unique seulement + dans le niveau considéré. + - le **DN** pour *Distinguished Name** est un nom unique identifiant un objets + dans l'arbre. Il est la somme de tous les RDN + +Pour un nommage cohérent, il est important de définir des règle commune de +nommage pour s'assurer de la cohérence des RND. Ceci permet de résoudre les +problèmes d'homonymie. + +Exemple : + +``` +RDN = CN=DURAND Yves +CN=DURAND Yves,L=Paris,L=Ile de France,C=fr +``` + +# L'organisation hiérarchique + +Un annuaire se présente sous la forme d'un arbre (DIT pour *Directory +information Tree*). + +Il peut refléter l'organisation hiérarchique de la +structure ou son implantation géographique, voir même mixer les deux. + +Il peut aussi représenter l'organisation de l'entreprise sous forme sémantique +en groupant les informations qui ont un même sens (personnes, groupes, +applications et.). Cette configuration facilite l'administration des droits +d'accès. Par exemple en affectant les droits d'écriture au DRH seulement sur +`ou=Personnes` + +# Le modèle de services + +LDAP est basé sur un modèle **Client <> Serveur**. Le client transmet une +requête décrivant une ou plusieurs actions à réaliser sur l'annuaire. Le serveur +est lui responsable de sa réalisation. Le serveur renvoi alors le résultat ou +une ou plusieurs références à d'autres serveurs susceptibles d'accéder à la +demande du client. + +Toutes les opération sont encapsulées dans une envelope commune : **le message +LDAP** *(LDAPMEssage)* + +Chaque requête possède son propre identifiant Il est possible de réutiliser cet +identifiant si : + + - la requête n'a pas été abandonnée + - elle n'ai pas eu de réponse à l'instant donné. + +Quelle que soit la requête, la réponse sera donné sous la forme d'un message +*LDAPResult* + +# Le modèle de sécurité + +L'accès à l'annuaire LDAP peut se faire : + + - en accès anonyme + - par authentification via un mot de passe + - par authentification par mot de passe via une liaison chiffrée TLS + - par authentification forte via certificats + - par authentification forte via certificats et liaison chiffrée TLS + +# Le format LDIF + +Le **LDIF** *LDAP Data Interchange Format* est un format de fichier de type +texte (ASCII) utilisé pour la représentation des données issues d'un annuaire +LDAP ou d'opération sur les données (mais pas les deux à la fois). + +Il est donc utilisé pour faciliter les opérations d'importation et/ou +d'exportation massive d'informations. Il contient une série d'enregistrements +séparés par des séparateur de lignes. Un enregistrement décrit un enregistrement +ou une modification. + +Exemple : + +```ldif +dn: dmdName=Devices,ou=iut_mont-de-marsan,dc=universite, dc=education,dc=gouv,dc=fr +dmdName: Devices +objectClass: dmd +objectClass: top +dn: dmdName=Applications,ou=iut_mont-de-marsan,dc=universite,dc=education,dc=gouv,dc=fr +dmdName: Applications +objectClass: dmd +objectClass: top +``` + +Voir le format +[LDIF](https://fr.wikipedia.org/wiki/LDAP_Data_Interchange_Format) sur +Wikipedia. diff --git a/content/installations/TDM_1-OpenLDAP/index.md b/content/installations/TDM_1-OpenLDAP/index.md new file mode 100644 index 0000000..f777d1a --- /dev/null +++ b/content/installations/TDM_1-OpenLDAP/index.md @@ -0,0 +1,198 @@ +--- +title: TDM1 OpenLDAP - notes d'installation +date: 2018-09-13 +lastmod: 2018-08-27 +category: Installations +tags: ['OpenLDAP', 'Apache Directory Studio', 'PAM'] +--- + +Le but de ce TD Machine est d'installer OpenLDAP sur une machine virtuelle, de +configurer un DIT en `dc=u-bordeaux,dc=fr`, de gérer les personnes, matériels et +fonctions et enfin de gérer l'authentification par le LDAP. + +# Installation d'openLDAP sur Debian + +Lors de l'installation, j'ai choisi de nommer la machine `openldap` et le +`domaine u-bordeaux.fr`, ainsi lors du paramétrage de mon service, il sera +accessible directement sur `openldap.u-bordeaux.fr` + +Sur une Debian 9 il suffit d'installer les paquets `slapd` et `ldap-utils` avec +la commande : + +```shell +apt install slapd ldap-utils +``` + +Il est possible de définir simplement le domaine et le mot de passe de +l'administrateur du serveur LDAP en reconfigurant le paquet avec la commande : + +```shell +dpkg-reconfigure -pHIGH slapd +``` + +Il est aussi possible de le faire directement par l'intégration de fichiers LDIF +dans l'annuaire. + +# Intégration des personnes, fonctions et matériels + +Nous allons créer 3 objets de type `dmd` *directory management domain* reprenant +les trois catégories demandées. Lors de la création de mon arbre, j'ai cependant +choisi cd créer des `ou` *organizational unit* mais c'est sémantiquement pas +juste (ce serait valable pour le service marketing ou le site de Pessac par +example). + +À partir du moment ou le serveur LDAP est lancé, fonctionnel et l'administrateur +créé, il est tout à fait possible de lancer cette étape depuis un logiciel comme +Apache Directory studio ou phpldapmyadmin. Mais le but ici était de le faire +depuis un fichier LDIF. + +```LDIF +dn: dmdName=users,dc=u-bordeaux,dc=fr +dmdName: users +objectClass: dMD + +dn: dmdName=roles,dc=u-bordeaux,dc=fr +dmdName: fonctions +objectClass: dMD + +dn: dmdName=machines,dc=u-bordeaux,dc=fr +dmdName: machines +objectClass: dMD +``` + +Il suffit d'intégrer ce fichier à l'annuaire avec la commande `ldapadd` : + +```shell +ldapadd -H ldap://openldap.u-bordeaux.fr -D "cn=admin,dc=u-bordeaux,dc=fr" \ + -W -f tree.ldif +``` + + - `-H ` : URI d'accès au serveur LDAP + - `-D ` : dn du compte autorisé pour l'ajout (ici l'admin) + - `-W` : demande le mot de passe + - `-f ` : fichier LDIF contenant les entrées à ajouter. + +## Effectuer une recherche dans l'annuaire + +La recherche dans l'annuaire est importante dans la mesure ou elle va nous +permettre de vérifier au fur et à mesure les données que l'on y ajoute. + +```shell +ldapsearch -x -W -D "cn=admin,dc=u-bordeaux,dc=fr" -b "dc=u-bordeaux,dc=fr" \ + "(objectClass=dMD)" +``` + - `-W` : demande le mot de passe + - `-D` : dn de l'admiistrateur du serveur + - `-b` : chemin ou effectuer la rechercheo + - `-x` : uriliser l'anthentification simple plutôt que SASL **déconseillé** + - `(*)` : recherche + +## Ajouter un mot de passe + +```shell +ldappasswd -H "ldap://ldapsrv.u-bordeaux.fr" -D "cn=admin,dc=u-bordeaux,dc=fr" \ + -W "uid=yorick.barbanneau,dmdName=users,dc=u-bordeaux,dc=fr" +``` + + - `-H` : host du serveur LDAP à contacter + +Les autres options sont similaires aux comances ci-dessus. + +# Apache Directory Studio + +C'est un logiciel permettant la gestion complète d'un annuaire LDAP. Écrit en +java, c'est une application open-source sous licence Apache 2. + +Pour l'installer, il faut disposer d'une interface graphique et d'un +environnement d'exécution Java. Pour le TD, j'ai donc installé le bureau `Lxde` et +`openjdk-8-jre`. + +```shell +apt install lxde openjdk-8-jre +``` + +j'ai ensuite téléchargé la dernière version d'Apache Directory Studio sur [le +site Apache](https://directory.apache.org/studio/download/download-linux.html). + +Une fois le logiciel téléchargé et décompressé, je l'ai lancé puis ajoute la +connexion au serveur LDAP dans *LDAP > nouvelle connexion*. + +J'ai créé un groupe enfant de `dmdName=fonction,dc=u-bordeaux,dc=fr` avec comme `cn` +users et un `gidNumber` de 2000 + +J'ai ensuite créé un utilisateur enfant de `dmdName=personnes,dc=u-bordeaux,dc=fr` +avec comme classe `OrganizationalPerson` et `PosixAccount`. J'ai fait choisi +un `uidMumber` suffisamment haut pour ne pas gêner ceux du système (2000) + +On pourrait le modéliser dans le fichier LDIF suivant (à Corriger): + +```LDIF +dn: uid=yorick.barbanneau,dmdName=users,dc=u-bordeaux,dc=fr +objectClass: top +objectClass: person +objectClass: organizationalPerson +objectClass: posixAccount +objectClass: shadowAccount +uid: yorick.barbanneau +sn: Barbanneau +cn: Yorick Barbanneau +userpassword: {SSHA}...... +uidnumber: 2000 +gidnumber: 2000 +homedirectory: /home/yorick.barbanneau +loginshell: /bin/bash +``` + +# Authentification sur la machine avec les comptes LDAP + +L'authentification machine depuis les données de l'annuaire nécessite +l'installation et la configuration de deux paquets Debian : + +```shell +apt install libpam-ldap libnss-ldap +``` + +L'installation entraine ici automatiquement le lancement de la configuration de +certains éléments via debconf. il reste cependant des choses à configurer. + +Tout d'abord le fichier `/etc/nsswitch.conf` : + +``` +passwd: files ldap +group: files ldap +shadow: files ldap +``` + +Ensuite il faut modifier le fichier `/etc/libnss-ldap.conf` et y modifier les champs +`base` et `uri` en fonction de notre serveur + +``` +uri ldap://openldap.u-bordeaux.fr +base dc=u-bordeaux,dc=fr +``` + +et redémarrer le service nscd : + +```shell +systemctl restart nscd +``` +Enfin, il reste à configurer PAM afin qu'il créé le dossier utilisateur s'il +n'existe pas. Dans le fichier `/etc/pam.d/common-account` rajouter la ligne : + +``` +session required pam_mkhomedir.so skel=/etc/skel umask=0022 +``` + +Pour vérifier que tout fonctionne, lancer `getent passwd`, les utilisateurs +venant du LDAP devraient apparaître dans la liste obtenue. + +# Voir aussi + + - [LDAP PAM sur la documentation Debian](https://wiki.debian.org/LDAP/PAM) + - [LDAP Authentication (Archlinux)](https://wiki.archlinux.org/index.php/LDAP_authentication) + - [SSSD](https://docs.pagure.org/SSSD.sssd/) + +## SSSD + +C'est une méthode d'authentification couplée à PAM qui semble intéressante : elle +supporte la connexion même en mode hors-ligne grâce à un cache. diff --git a/content/progsys/1-introduction/files/presentation.pdf b/content/progsys/1-introduction/files/presentation.pdf new file mode 100644 index 0000000..933e7c8 Binary files /dev/null and b/content/progsys/1-introduction/files/presentation.pdf differ diff --git a/content/progsys/1-introduction/index.md b/content/progsys/1-introduction/index.md new file mode 100644 index 0000000..65663c7 --- /dev/null +++ b/content/progsys/1-introduction/index.md @@ -0,0 +1,106 @@ +--- +title: "Programmation Système : Appels systèmes" +date: 2018-09-04 +tags: ["programmation", "système", "appels système"] +categories: ["Programmation système", "Cours"] +--- + +# Qu'est ce que c'est? + +C'est créer des programmes plutôt bas niveau qui s'interfacent avec le noyau +et/ou les librairies du système. Il faut donc une bonne connaissance du +fonctionnement du système et être en mesure d'identifier d'éventuels problèmes +de performance. + +# Le système d'exploitation + +C'est un ensemble de logiciels fournissant les services nécessaires à +l'exécution de programmes pour l'utilisateur final : + + - exécution de programmes + - accès aux matériels + - accès au(x) système(s) de fichier(s) + - accès mémoire + - accès réseau + +## POSIX et IEE + +La norme POSIX, standard IEEE, définie les interfaces utilisateurs et +logiciels, la ligne de commande standard et son interface de scripts, les +entrées / sorties de base. les attributs de fichiers (permissions) + +La norme SUS *Single Unie Specification* est une norme plus récente et moins +contraignante. elle est basée sur les travaux de l'IEEE et de l'Open Group. + +[SUS][https://fr.wikipedia.org/wiki/Single_UNIX_Specification] et +[POSIX][https://fr.wikipedia.org/wiki/POSIX] sur Wikipedia + +## LSB + +LSB ou *Linux Standard Base* définie l'agencement général du système GNU / Linux +: librairies standard, commandes POSIX étendues, hiérarchie du système de +fichiers, les runlevels etc. + +[LSB][https://fr.wikipedia.org/wiki/Linux_Standard_Base] sur Wikipedia. + +## Architecture des systèmes "modernes" + +Ils sont organisés en couches un peu à la façon du modèle OSI : + + 1. le matériel + 2. l'assemblage (assembleur) + 3. système (applications système) + 4. Application + N. Les applications / machines virtuelles (capables de traverser les couches + pour atteindre le matériel) + + Plus la couche est basse, plus la programmation est efficace du point de vue + des performances mais plus difficile est la portabilité (un code assembleurs et + moins portable qu'un script Python) + + Les systèmes modernes possèdent deux espaces d'exécutions : + + - l'espace utilisateur `user-space` ou `user-land` + - l'espace noyau `kernel-space` ou `kernel-land` + +# La libc + +La `libc` est la librairie standard des système GNU/ Linux, elle implémente +les fonctionnalités de base pour la plupart des programmes. C'est une API pour +accéder aux services du noyau : + + - entrées /sorties + - allocation fine de la mémoire + - gestion du temps + - encapsulation des appels noyau et en dehors du noyau (user-land) + +# Programme et processus + +Un programme est un fichier exécutable stocké sur un disque (mémoire morte). Un +processus et un programme mais en mémoire (et donc en cours d'exécution). Un +processus est défini par son identifiant (PID) et accède à un espace d'adressage +en mémoire vive (pour la pile, les données ...) + +# Descripteurs de fichiers + +Un descripteur de fichier pour *file descriptor* (abrégé *fd*) est un entier +positif affecté par le noyau pour référencer un fichier utilisé par un +processus. Il est bon de préciser que dans la philosophie Unix, tout est +fichier, le *fd* se retrouve donc pour les fichiers, sockets, tubes, +périphériques etc. + +# Les appels système + +Ils permettent de demander au noyau de réaliser une action précise et se font au +travers de la libc. Voici comment cela se passe : + + - Préparer les arguments en les positionnant dans des registres spécifiques + pour le noyau + - placer le numéro d'appel système dans un registre spécifique invoquer + - l'instruction `trap` qui bascule le processeur en mode noyau + +Le noyau invoque `system_call` après validation des arguments et retourne le +résultat à la libc : + + - en cas d'erreur la libc invoque `errno` avec en résultat le code erreur + - sinon le résultat diff --git a/content/progsys/2-fichiers/files/presentation.pdf b/content/progsys/2-fichiers/files/presentation.pdf new file mode 100644 index 0000000..09623b0 Binary files /dev/null and b/content/progsys/2-fichiers/files/presentation.pdf differ diff --git a/content/progsys/2-fichiers/index.md b/content/progsys/2-fichiers/index.md new file mode 100644 index 0000000..1a4e506 --- /dev/null +++ b/content/progsys/2-fichiers/index.md @@ -0,0 +1,251 @@ +--- +title: "Les fichiers" +date: 2018-09-11 +categories: ["Programmation système", "Cours"] +tags: ["fichiers", "descripteurs", "c"] +--- + +Dans la philosophie Unix, tout est fichiers, les entrees sorties sont donc +symbolisées par des manipulations de fichiers. Celles-ci se font par le biais de +**descripteurs de fichiers**, il représente le point d'entrée d'un fichier pout +un processus. + +Pour chaque programme en cours d'exécution, le noyau maintient une table des +fichiers ouverts. Cette table contient entres autres le descripteur de fihers +(un nombre entier non signé) et la **position du curseur** ( *file offset* ). + +Le curseur est la position où aura lieu la prochaine opération (lecture / +écriture). Cette position est exprimée en octets. + +Il existe cependant 3 types particuliers de descripteur de fichiers : + + - l'entrée standard (0 ou `STDIN_FILENO`) + - la sortie standard (1 ou `STDOUT_FILENO`) + - la sortie d'erreur (2 ou `STDERR_FILENO`) + +## Les appels système de base + +### open() + +```c +#include +#include +#include + +int open(const char *pathname, int flags); +int open(const char *pathname, int flags, mode_t mode); +``` + +Cet appel système ouvre le fichier dont le chemin est `pathname` et retourne un +descripteur de fichier. En vas de problème, la fonction `open()`retourne -1. + +#### flag + +`flag` est un masquage de bits permettant de spécifier le mode d'accès : + +flag | utilisation +---------|------------ +O RDONLY | Lecture seule +O WRONLY | Écriture seule +O RDWR | Lecture et écriture +O CREAT | Création du fichier s'il n'existe pas +O TRUNC | Troncature du fichier +... | ... +O APPEND | Écriture à la fin du fichier + +#### mode + +C'est aussi un masquage de bits définissant le node du fichier en vas de +création : + +| mode | octal | utilisation | +|---------|-------|-------------------------------------------------------- +| S_IRWXU | 00700 | Le propriétaire a le droit de lire, écrire, exécuter | +| S_IRUSR | 00400 | L’utilisateur a le droit de lire | +| S IWUSR | 00200 | L'utilisateur a le droit d'écrire | +| S IXUSR | 00100 | L'utilisateur a le droit d'exécuter | +| S_IRWXG | 00070 | Le groupe a le droit de lire, écrire, exécuter | +| S_IRGRP | 00040 | Le groupe a le droit de lire | +| S IWGRP | 00020 | Le groupe a le droit d'écrire | +| S IXGRP | 00010 | Le groupe a le droit d'exécuter | +| S_IRWXO | 00007 | Le propriétaire a le droit de lire, écrire, exécuter | +| S_IROTH | 00004 | L’utilisateur a le droit de lire | +| S IWOTH | 00002 | L'utilisateur a le droit d'écrire | +| S IXOTH | 00001 | L'utilisateur a le droit d'exécuter | + +#### Exemple en C + +```c +fd = open("test1.txt", O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); +``` +Ouvre un fichier `test.txt`, s'il n'existe pas il sera créé. Il est ouvert en +lecture - écritur seul le propriétaire a le droit de lire et d'écrire. + +#### Exemple en Python + +Il est possible de faire les même action en Python avec les modules `stat` et +`os`. + +```python +import os, stat +f = os.open("test1.txt", +os.O_RDWR | os.O_CREAT | os.O_TRUNC, +stat.S_IRUSR | stat.S_IWUSR) +f = open("test1.txt", 'w+', 0o600) # umask issue +``` + +Ce programme réalise les mêmes actions que ci-dessus mais en Python + +### read() + +Cet appel système lit des données d'un fichiers + +```c +#include + +ssize_t read(int fd, void *buf, size_t count); +``` + +Lit au plus `count` octets depuis le fichier référencé par le descripteur `fd` +et les stocke dans `*buff`. Renvoie 0 s'il n'y a plus d'octets à lire ou -1 si +la commande échoue + +### write() + +Écrits des données sur un fichier + +```c +#include +ssize_t write(int fd, const void *buf, size_t count); +``` + +Lit au plus `count` octets depuis la zone mémoire depuis `*buf` et les écrits +dans le fichier référencé par `fd`. Renvoie le nombre d'octets écrits ou -1 si +la commande échoue. Le nombre d'octets écrits peut être inférieur à `count` +(plus de place disponible par exemple). + +### close() + +Ferme un fichier, rend libère le descripteur associé et les ressources associées +allouées par le noyau. + +```c +#include +int close(int fd); +``` + +Renvoie 0 en cas de réussite et -1 s'il échoue. + +### Exemple de lecture-ecriture + +### en c + +```c +#include +#include +#define BUFMAX 32 + +int main (int argc, char **argv) { + char buffer[BUFMAX]; + int count; + count = read(STDIN_FILENO, buffer, BUFMAX); + if (count == -1) { + write(STDERR_FILENO, "Unable to read stdin\n", 21); + exit(EXIT_FAILURE); + } + write(STDOUT_FILENO, "Input data was: ", 16); + write(STDOUT_FILENO, buffer, count); + exit(EXIT_SUCCESS); +} +``` + +### en Python + +```Python +#!/usr/bin/python3 +import os, sys +def main(): + #buf = sys.stdin.read() # Ctrl-D for EOF + try: + buf = input() + except EOFError: + buf = '' + except Exception as e: + sys.stderr.write("Unable to read stdin: %s", e) + sys.exit(os.EX_DATAERR) + sys.stdout.write("Input data was: %s" % (buf)) + sys.exit(os.EX_OK) +main() +``` + +### lseek() + +```c +#include +off_t lseek(int fd, off_t offset, int whence); +``` + +Renvoie en octets depuis le début du fichier la nouvelle position du curseur. +Cet appel système modifie seulement la table de fichiers ouverts mais ne +provoque pas d'accès au système de fichiers. + +### whence + +position | utilisation +---------|------------ +SEEK_SET | le curseur est placé à `offset` octets depuis le début du fichier +SEEK_CUP | le curseur est déplacé de `offset` depuis sa position courante +SEEK_END | le curseur est déplacé de `offset` octets après la fin de fichier + +### fichiers à trou + +Si l'on positionne le curseur après la fin du fichier puis une opération +d'écriture, on créé alors un **trou**. Les données à l'intérieur du trou +contiennent 0 pour notre fichier, mais ne prenne pas d'espace disque. + +Ces **fichiers à trou** aussi appelés *sparse files* permettent d'utiliser le +système de fichier de manière plus efficace surtout lorsque le fichier est +majoritairement vide. Ils sont utilisés pour les bases de données, les images +disques, les fichiers journaux etc. + +### Unlink () + +Détruit un nom dans le système de fichiers. Si ce nom était le dernier lien vers +un fichier et que celui-ci n'est ouvert dans aucun processus, il est effacé et +l'espace qu'il occupait est marqué comme disponible. + +Si ce fichier et encore ouvert par un processus, il continu d'exister jusqu'à ce +que le dernier descripteur de fichier le référençant soit fermé. + +```c +#include +int unlink(const char *pathname); +``` + +## La librairie stdio + +La librairie sdtio.h fourni par la librairie standard permet de manipuler les +fichiers avec des fonction de plus haut niveau. + +Les fonction de cette librairie n'opèrent pas directement sur les descripteurs +de fichiers (notion spécifiques à Unix) mais sur des pointeur sur une structure +de type *FILE*. Elle contient entres autres : + + - le descripteur de fichier + - un champ *flag* indiquant l'état du flux + - une mémoire tampon + - la position courante dans le tampon + +Chaque appel système de gestion de fichiers a un équivalent dans `stdio`. + +```c +#include +FILE *fopen(const char *path, const char *mode); +FILE *fdopen(int fd, const char *mode); +int fclose(FILE *stream); +size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) +size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); +int fseek(FILE *stream, long offset, int whence); +int fflush(FILE *stream); +int fprintf(FILE *stream, const char *format, ...); +``` diff --git a/content/progsys/3-processus/index.md b/content/progsys/3-processus/index.md new file mode 100644 index 0000000..a3257d9 --- /dev/null +++ b/content/progsys/3-processus/index.md @@ -0,0 +1,262 @@ +--- +title: "Les processus" +date: 2018-09-18 +categories: ["Programmation système", "Cours"] +tags: ["processus", "programme", "c"] +--- + +Il ne faut pas confondre processus et programme, un processus étant une +instance chargée en mémoire et en cours d'exécution d'un programmme. Plusieurs +instance d'un programme peuvent s'exécuter en même temps. + +À chaque processus est assicié un identidiant (PID) et un espace de stockage en +mémoire pou y stocker la pile, les données, le code etc. (espace d'adressage). + +Un programme contient toutes les informations nécessaire à la création du +processus : + + - un format binaire ELF (historiquement a.out, Coff) + - le point d'entrée de la première instruction + - les données + - les information de débogage + - les information sur les librairies partagées + +Un processus est une entité abstraite connue du noyau aui lui alloue des +ressources pour son execution. Du point de vue du noyau un processus consiste en +: + + - En mode **user** + - une portion d'espace mémoire + - le code du programme + - les variables auquelles le programme a accès + - em mode **kernel** + - Une structure de données de l'état du processus + - la table des fichiers ouverts + - la table de la mémoire allouée + - le répertoire courant + - la priorité + - le gestionnaire d'évènements (signaux, fin de programmes ...) + - les limites du processus + +## le PID + +Il est créé par le noyau et aussi utilisé dans l'espace utilisateur (`kill`, +`ps`, `nice`) + +```c +#include + +pid_t getpid(void) +``` + +Renvoi le PID du processus appelant. Cette fonction est ouvent utilisée par des +routines qui créées des fichiers temporaires uniques. + +`pid_t` est un type abstrait pouvant être transtypé en `int`, sa valeur maximale +est définie dans `/proc/sys/kernel/pid_max` + +## Démarrage d'un programme en C + +Un programme en C commence toujours par la fonction `main()` : + +```c +int main (int argc, char **argv) { +} +``` + + - `argc` : entier, nombres d'arguments passés + - `**argv` : tableau de pointeurs, arguments passés + +L’invocateur du programme (ex: le shell) exécute l’appel système execvp et +utilise les arguments passés au programme comme paramètres. + +### exemple + +```shell +$ mycommand --color -l -s + +argv = ["mycommand", "--color", "-l", "-s"] +argc = 4 +``` + +on récupèrera les paramètres avec le code c suivant : + +```c +#include +#include + +int main(int argc, char **argv){ + for (int i=0; i +int atexit(void (*function)(void)); +``` + +La fonction `atexit()` enregistre la fonction donnée pour que celle-ci soit +automatiquement appelée lorsque le programme se termine normalement avec exit(3) +ou lors de la fin de la fonction main. Les fonctions ainsi enregistrées sont +invoquées dans l'ordre inverse de leur enregistrement ; aucun argument n'est +transmis `atexit()` renvoie 0 en cas de succès et une valeur non nulle en cas +d'échec + +## Mémoire allouée + +La mémoire allouée à chaque processus est divisée en segments : + + - **le segment texte**, en lecture seule contient les instructions en langage + machine (le binaire su programme au format *ELF*) + - **le segment des données initialisées** qui contient les variables globales + et statiques explicitement initialisées. Les valeurs de ces variables sont + lues depuis le fichiers exécutables lorsqu'il est chargé. + - **le segment des données non-initialisées** aui contient des variables + globales et statiques non explicitement initialisées (BSS) + - **la pile** appelées aussi *stack* est un segment dynamique aui s'étend et se + réduit. Il contient des blocs de pile appelés *stack frame* par fonction + appelée. Une *frame* contient les variables locales et la/les valeur(s) de + retour de la fonction. + - **le tas** aussi appelé *heap* est une zone où la mémoire peut être + dynamiquement allouée pour les variables à l'exécution du programme. + +L'espace mémoire d'un processus est virtuel car celui-ci n'adresse pas +directement la mémoire. Les processus sont isolées du noyau et le noyau +maintient un tableau de pages mémoires aui adresse les pages de la mémoire +physique. Un processus peut adressser plus de mémoire que le système en a de +disponible. + +Sous Unix, un processus est définis sous forme arborescente : chacun d'eux a un +processus parent (mis à pat le 1 - processus d'init) et chacun a aucun, un ou +plusieurs fils. + +## Création de processus + +```c +#include + +pid_t fork(void); +``` + +Après le `fork()`, le processus parent continue normalement son exécution. Le +processus fils commence son exécution juste après. On distingue le parent du +fils par la valeur de retour du `fork()` 0 pour le fils, le *PID* du fils pour +le père). Le fils est une copie du père cependant seule les zones modifiées sont +vraiment copiées. Le segment *text* est partagé entre les deux + +Après le `fork()`, la table des fichiers est partagées entre le parent et +l'enfant. Ainsi si l'offset est modifié dans un des processus, il le sera aussi +pour l'autre. Cela permet entres autres de faire collaborer les processus sur +les mêmes données. + +### exemple de `fork()` + +```c +#include +#include +#include +int main (int argc, char **argv) { + pid_t pid; + printf("Starting process with PID=%d\n", getpid()); + pid = fork(); + if (pid < 0) { + perror("Unable to fork"); + } + else if (pid == 0) { + printf("Starting child with PID=%d (my parent PID=%d)\n", getpid + } + else { + printf("Still in process with PID=%d\n", getpid()); + } + printf("Finishing process with PID=%d\n", getpid()); + exit(EXIT_SUCCESS); +} +``` + +## Terminaison de processus + +Quelle que soit la façon dont se termine un processus (père comme fils), le +noyau nettoie les ressources allouées. Il stocke cependant le status de +terminaison du fils jusqu'au moment ou le père en prend connaissance. + +Lorsque le père se termine, le processus fils devient enfant de 1 (*PID* 1) + +### Processus zombies + +Lorsqu'un processus enfant est terminé mais que le parent n'a toujours pas pris +connaissance de sa terminaison, il devient alors un processus zombie. Ce dernier +continue de consommer des ressources noyau (code de terminaison, entrée dans la +table des processus etc.) + +### Attendre la fin d'un processus enfant + +```c +#include +#include +pid_t waitpid(pid_t pid, int *status, int options); +pid_t wait(int *status); // waitpid(-1, &status, 0); +// en cas de réussite, l'identifiant du processus fils +// terminé (ou changé) est renvoyé ; en cas d'erreur, +// la valeur de retour est -1 +``` + +L'appel système `waitpid()` permet d'attendre la fin d'un processus. C'est un +appel bloquant (sauf avec certaines options). Il retourne une erreur s'il n'y a +pas de processus fils. Lorsque le processus fils se termine, la variable +`status` contient son code de retour. +## Création d'un nouveau processus + +Sous Unix, la création d'un nouveau processus et l'exécution d'un programme sont +deux choses distinctes. L'exécution d'un nouveau processus ne créé pas de +nouveau processus, il remplace juste le programme appelant en allant chercher +les données sur le système de fichiers. + +À l'exécution, tous les segments son réinitialisés comme si le programme avait +été exécuté normalement. + +L'exécution d'un programme se fait grâce à l'appel `execve()` + +```c +#include +extern char **environ; +int execl(const char *path, const char *arg, ..., (char *) NULL); +int execlp(const char *file, const char *arg, ..., (char *) NULL); +int execle(const char *path, const char *arg, ...,(char *) NULL, char *const envp[]); +int execv(const char *path, char *const argv[]); +int execvp(const char *file, char *const argv[]); +int execvpe(const char *file, char *const argv[], char *const envp[]); + +// Une sortie des fonctions exec() n'intervient que si une erreur s'est +// produite. La valeur de retour est -1, et errno contient le code +// d'erreur. +``` + +## Le format ELF + +ELF pour *Executable and Linkable Format* est utilisé pour l'exécution de code +compilé. Dévellopé par Unix System Labortatories, il est utilisé par Linux, BSD, +System V, IRIX, SPARC. + + diff --git a/content/progsys/TDM_1-appels_systemes/files/tdm1.pdf b/content/progsys/TDM_1-appels_systemes/files/tdm1.pdf new file mode 100644 index 0000000..fedb05f Binary files /dev/null and b/content/progsys/TDM_1-appels_systemes/files/tdm1.pdf differ diff --git a/content/progsys/TDM_1-appels_systemes/index.md b/content/progsys/TDM_1-appels_systemes/index.md new file mode 100644 index 0000000..f4458fd --- /dev/null +++ b/content/progsys/TDM_1-appels_systemes/index.md @@ -0,0 +1,39 @@ +--- +title: Programmation systeme TDM 1 +date: 2018-09-05 +categorie: ['Programmation système', 'TDM'] +tags : ['appels', 'systèmes', 'Python', 'C'] +--- +#Différence entre les strace C et Python + +Le strace python est plus volumineux, ce aui semble normal puisque le code est +interprété, et charge par conséquent l'ensemble de l'environnement d'execution +Python. *(36 lignes pour le C contre 613 pour le Python)*. + +Cependant il y a aussi beaucoup des similitudes, comme l'appel à la libc et les +commamdes envoyées au kernel (write). + +On peut donc en déduire que le temps d'exécution pour la version Python est plus +grande avec plus d'appels système. + +## temps d'execution comparé avec strace -tt + + - C : début 17:52:29.647826 fin 17:52:29.668778 + - Python : début 17:50:49.455004 fin 17:50:49.769447 + +La différence de temps d'execution apparaît clairement ici + +# Tracer un programme en cours d'exécution + +J'ai essayé de tracer htop lancé dans un autre terminal mais j'ai une erreur +(Opération non permise). En passant par root pour lancer mon strace, il +fonctionne. L'affichage du strace est continue logique puisque le programme +tournant en arrière plan, il continue de faire des appels systèmes (surveillance +des processus du sytèmes) + +Il est dont logique que je ne puisse pas stracer le processus 0, même apres +avoir modifier la variable sysctl yama. + +# Avec le sleep + +On constate un appel système de plus (nanosleep) avant le write. diff --git a/content/progsys/TDM_1-appels_systemes/src/hello_world.c b/content/progsys/TDM_1-appels_systemes/src/hello_world.c new file mode 100644 index 0000000..3c4b745 --- /dev/null +++ b/content/progsys/TDM_1-appels_systemes/src/hello_world.c @@ -0,0 +1,8 @@ +#include +#include + +int main (){ + printf("Hello World\n"); + sleep(5); + exit(0); +} diff --git a/content/progsys/TDM_1-appels_systemes/src/hello_world_sleep.c b/content/progsys/TDM_1-appels_systemes/src/hello_world_sleep.c new file mode 100644 index 0000000..3c4b745 --- /dev/null +++ b/content/progsys/TDM_1-appels_systemes/src/hello_world_sleep.c @@ -0,0 +1,8 @@ +#include +#include + +int main (){ + printf("Hello World\n"); + sleep(5); + exit(0); +} diff --git a/content/progsys/TDM_2-fichiers/files/tdm2.pdf b/content/progsys/TDM_2-fichiers/files/tdm2.pdf new file mode 100644 index 0000000..2280ef6 Binary files /dev/null and b/content/progsys/TDM_2-fichiers/files/tdm2.pdf differ diff --git a/content/progsys/TDM_2-fichiers/index.md b/content/progsys/TDM_2-fichiers/index.md new file mode 100644 index 0000000..fc5b69a --- /dev/null +++ b/content/progsys/TDM_2-fichiers/index.md @@ -0,0 +1,7 @@ +--- +title: "TDM : Les fichiers" +date: 2018-09-11 +categories : ['Programmation système', 'TDM'] +--- + +Pas encore de contenu diff --git a/content/progsys/TDM_2-fichiers/src/question1.c b/content/progsys/TDM_2-fichiers/src/question1.c new file mode 100644 index 0000000..9e88c47 --- /dev/null +++ b/content/progsys/TDM_2-fichiers/src/question1.c @@ -0,0 +1,26 @@ +#include +#include + +int main () { + char buffer[32]; + int ret, read_ret; + int next_read = 1; + do { + read_ret = read(STDIN_FILENO, buffer, 1); + switch ( read_ret ) { + case -1 : + write (STDERR_FILENO,"Error when reading\n", 19); + exit(EXIT_FAILURE); + case 0: + next_read = 0; + break; + default: + ret = write(STDOUT_FILENO, buffer, 1); + if ( ret == -1){ + write (STDERR_FILENO,"Error when writing\n", 19); + exit(EXIT_FAILURE); + } + } + } while ( next_read ); + exit(EXIT_SUCCESS); +} diff --git a/content/progsys/TDM_2-fichiers/src/question2.c b/content/progsys/TDM_2-fichiers/src/question2.c new file mode 100644 index 0000000..111199f --- /dev/null +++ b/content/progsys/TDM_2-fichiers/src/question2.c @@ -0,0 +1,27 @@ +#include +#include +#include +#include + +int main () { + int fd,i; + char alphabet[26] = "abcdefghijklmnopqrstuvwxyz"; + + //open file + fd = open("tp2-q2.txt",O_WRONLY | O_CREAT, S_IRWXU); + if ( fd == -1 ) { + write(STDERR_FILENO,"Error when opening file\n", 25); + exit(EXIT_FAILURE); + } + for (i=0;i<26;i++) { + if ( write(fd, &alphabet[i], 1) == -1 || write(fd,"\n",1) == -1){ + write (STDERR_FILENO,"Error when writing\n", 19); + exit(EXIT_FAILURE); + } + } + //Clode file + if ( close(fd) == -1){ + write(STDERR_FILENO, "Can't close file.\n", 18); + } + exit(EXIT_SUCCESS); +} diff --git a/content/progsys/TDM_2-fichiers/src/question3.c b/content/progsys/TDM_2-fichiers/src/question3.c new file mode 100644 index 0000000..55e5756 --- /dev/null +++ b/content/progsys/TDM_2-fichiers/src/question3.c @@ -0,0 +1,24 @@ +#include +#include +#include +#include +#define HOLE 10000 + +int main (int argc, char **argv) { + int fd = open("td2-q3.txt", O_WRONLY | O_CREAT, S_IRWXU); + if ( fd < 0) { + write(STDOUT_FILENO, "Error : can't open file\n", 24); + exit(EXIT_FAILURE); + } + for (int i=0;i<4;i++){ + if ( write(fd, "A", 1) == -1 || lseek(fd, HOLE, SEEK_CUR) == -1) { + write(STDOUT_FILENO, "Error : can't write to file.\n", 29); + exit(EXIT_FAILURE); + } + } + if ( close(fd) == -1) { + write(fd,"Error : can't close file.\n", 26); + exit(EXIT_FAILURE); + } + exit(EXIT_SUCCESS); +} diff --git a/content/progsys/TDM_2-fichiers/src/question4.c b/content/progsys/TDM_2-fichiers/src/question4.c new file mode 100644 index 0000000..0d9bfa5 --- /dev/null +++ b/content/progsys/TDM_2-fichiers/src/question4.c @@ -0,0 +1,24 @@ +#include +#include +#include +#include + +#define BUFFER 32 + +int main () { + char read_error[] = "Error when reading input.\n"; +#include + char buff[BUFFER]; + FILE *out, *in; + in = fdopen(STDIN_FILENO, "r"); + out = fdopen(STDOUT_FILENO,"w"); + int count; + while ((count = fread(&buff, BUFFER,1,in)) > 0) + { + fwrite(&buff, BUFFER,1,out); + } + if ( count == -1 ){ + fwrite(&read_error, strlen(read_error) + 1,1,fdopen(STDERR_FILENO,"w")); + } + exit(EXIT_SUCCESS); +} diff --git a/content/progsys/TDM_2-fichiers/src/question5.c b/content/progsys/TDM_2-fichiers/src/question5.c new file mode 100644 index 0000000..bface13 --- /dev/null +++ b/content/progsys/TDM_2-fichiers/src/question5.c @@ -0,0 +1,33 @@ +#include +#include +#include +#include +#include + +void output_error() { + fprintf(stderr,"Error : %s\n",strerror(errno)); + exit(EXIT_FAILURE); +} + +int main() { + char *file = "tp2_q5.txt"; + FILE *f = fopen(file,"w"); + char m[56] = "\0"; + char ret = '\n'; + if ( f == NULL ){ + output_error(); + } + for(char i='a' ;i<='z' ; i++){ + strncat(m,&i,1); + strncat(m,&ret,1); + } + fwrite(&m,strlen(m) + 1,1,f); + if ( ferror(f) ) { + output_error(); + } + fclose(f); + if ( ferror(f) ){ + output_error(); + } + exit(EXIT_SUCCESS); +} diff --git a/content/progsys/TDM_3-processus/files/tdm3.pdf b/content/progsys/TDM_3-processus/files/tdm3.pdf new file mode 100644 index 0000000..781a093 Binary files /dev/null and b/content/progsys/TDM_3-processus/files/tdm3.pdf differ diff --git a/content/progsys/TDM_3-processus/index.md b/content/progsys/TDM_3-processus/index.md new file mode 100644 index 0000000..4d25308 --- /dev/null +++ b/content/progsys/TDM_3-processus/index.md @@ -0,0 +1,59 @@ +--- +Title: "TDM : Les Processus" +Date: 2018-09-18 +Category: Programmation système +tags: ['TD Machine', 'programmation', 'C', 'processus'] +--- + +[Télécharger les questions](./files/tdm3.pdf) +## Question 1 + +Sans exécuter le programme, je pense qu'il y aura Il y a 4 processus de créé. + +``` +q1.bin─┬─q1.bin + │ + ├─q1.bin + └─q1.bin +``` + +Les processus se "clonent" et l'arbre des processus est plus complexe que prévu +: il y a 8 processus au total. + +```shell +$ ./q1.bin & +[1] 8895 +$ pstree 8895 +q1.bin─┬─q1.bin─┬─q1.bin───q1.bin + │ └─q1.bin + ├─q1.bin───q1.bin + └─q1.bin +``` + +## Question 2 + +Je suis parti au départ pour créer la commande avec une boucle for pour +parcourir `*argv` mais il est plus simple de construire la commande avec +` &argv[1]` qui retourne le tableau après l'élément 1. + +```C +int out = execvp(argv[1], &argv[1]); +``` +J'ai aussi fait en sorte que le programme père se termine sur un `EXIT_FAILURE` +si le fils se termine sur une erreur. + +```C +while ((pid = waitpid(pid, &status, 0)) > 0){ + (status == 0) ? exit(EXIT_SUCCESS) : exit(EXIT_FAILURE); +} +``` +Télécharger mon [code](./src/td3/q2.c). + +## Question 3 + +Ma proposition était un peu complexe et surtout ne correspondant pas vraiment à +la demande. J'ai donc modifié ma réponde (q3bis.c) + +Télécharger mon [code](./src/td3/q3.c). +Et la version remaniée [code](./src/td3/q3bis.c). + diff --git a/content/progsys/TDM_3-processus/src/q1.c b/content/progsys/TDM_3-processus/src/q1.c new file mode 100644 index 0000000..aa35f7a --- /dev/null +++ b/content/progsys/TDM_3-processus/src/q1.c @@ -0,0 +1,9 @@ +#include +#include +int main(int argc, char **argv) { + fork(); + fork(); + fork(); + sleep(10); + exit(EXIT_SUCCESS); +} diff --git a/content/progsys/TDM_3-processus/src/q2.c b/content/progsys/TDM_3-processus/src/q2.c new file mode 100644 index 0000000..b59e44f --- /dev/null +++ b/content/progsys/TDM_3-processus/src/q2.c @@ -0,0 +1,33 @@ +#include +#include +#include +#include +#include +#include + +int main (int argc, char **argv) { + pid_t pid; + int status; + pid = fork (); + if ( pid < 0 ){ + printf("Error: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + if ( pid == 0){ + printf(" Into child, command : %s\n",argv[1]); + // we are in children + int out = execvp(argv[1], &argv[1]); + if ( out == -1 ){ + printf("Error : %s\n",strerror(errno)); + exit(EXIT_FAILURE); + } + exit(EXIT_SUCCESS); + } + else { + // if child exit code is not 0 then exit father with EXIT_FAILURE + while ((pid = waitpid(pid, &status, 0)) > 0){ + (status == 0) ? exit(EXIT_SUCCESS) : exit(EXIT_FAILURE); + }; + } +} diff --git a/content/progsys/TDM_3-processus/src/q3.c b/content/progsys/TDM_3-processus/src/q3.c new file mode 100644 index 0000000..7ef8d07 --- /dev/null +++ b/content/progsys/TDM_3-processus/src/q3.c @@ -0,0 +1,37 @@ +#include +#include +#include +#include +#include +#include + +int main(int argc, char **argv){ + if (argc > 2) { + printf("Error : %s must have one argument\n", argv[0]); + exit(EXIT_FAILURE); + } + if (argv[1] == NULL) { + printf("Execute child process\n"); + exit(EXIT_SUCCESS); + } + else { + int x = atoi(argv[1]); + printf("Number of children to create : %d\n", x); + for (int i=0; i < x ; i++){ + int pid = fork(); + if (pid == -1) { + printf("Error : %s", strerror(errno)); + exit(EXIT_FAILURE); + } + if (pid == 0) { + // we are in our children + if ((execl(argv[0],"",NULL)) < 0 ) { + printf("Error : %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + } + + } + } + exit(EXIT_SUCCESS); +} diff --git a/content/progsys/TDM_3-processus/src/q3bis.c b/content/progsys/TDM_3-processus/src/q3bis.c new file mode 100644 index 0000000..5d608d4 --- /dev/null +++ b/content/progsys/TDM_3-processus/src/q3bis.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include +#include +#include + +int main(int argc, char **argv){ + if (argv[1] == NULL) { + printf("Error : %s must have one argument\n", argv[0]); + exit(EXIT_FAILURE); + } + printf("Execute programme number %s\n",argv[1]); + int r = atoi(argv[1]) - 1; + if (r > 0){ + int pid = fork(); + if (pid == -1) { + printf("Error : %s", strerror(errno)); + exit(EXIT_FAILURE); + } + if (pid == 0) { + // we are in our children + char args[12] = ""; + sprintf(args,"%i", r); + if ((execl(argv[0], argv[0], args, NULL)) < 0 ) { + printf("Error : %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + } + } + else { + printf("This is the end!\n"); + } + exit(EXIT_SUCCESS); +} diff --git a/content/progsys/TDM_4-les_signaux/files/tdm4.pdf b/content/progsys/TDM_4-les_signaux/files/tdm4.pdf new file mode 100644 index 0000000..5769fd7 Binary files /dev/null and b/content/progsys/TDM_4-les_signaux/files/tdm4.pdf differ diff --git a/content/progsys/TDM_4-les_signaux/src/q1.c b/content/progsys/TDM_4-les_signaux/src/q1.c new file mode 100644 index 0000000..7328736 --- /dev/null +++ b/content/progsys/TDM_4-les_signaux/src/q1.c @@ -0,0 +1,21 @@ +#include +#include +#include +#include + +int i; + +void signal_sigint(){ + printf("value : %d\n",i); + //exit(EXIT_SUCCESS); +} + +int main () { + if((signal(SIGINT,signal_sigint)) == SIG_ERR){ + perror("unable to catch signal"); + } + for (i=0; i<1000000; i++) { + sleep(0.01); + } +} + diff --git a/content/progsys/TDM_4-les_signaux/src/q2.c b/content/progsys/TDM_4-les_signaux/src/q2.c new file mode 100644 index 0000000..ce495be --- /dev/null +++ b/content/progsys/TDM_4-les_signaux/src/q2.c @@ -0,0 +1,45 @@ +#include +#include +#include +#include +#include + +#define PAUSE 60 +#define CHILDREN 2 +int pids[CHILDREN]; + +void signal_sigterm () { + for(int i=0; i 0) { + if ((kill(pids[i],15)) == -1){ + perror("Error in signal catch\n"); + } + printf("Sending SIGTERM to child %d\n", pids[i]); + } + else{ + printf("\tKilling me\n"); + exit(EXIT_SUCCESS); + } + } +} + +int main( int argc, char **argv){ + printf("Starting father with pid %d\n", getpid()); + int status; + for (int i=0;i +#include +#include + +//define +#define THREADS 2 +#define ITERATIONS 1000000 + +static long glob = 0; + +void *tmain( void *arg){ + long tmp; + for (int i=0; i < ITERATIONS; i++){ + tmp = glob; + tmp++; + glob = tmp; + + } + return NULL; +} + +int main(int argc, char **argv) { + pthread_t *t; + void *res; + // memory allocation for threads + if ( (t=calloc(THREADS, sizeof(pthread_t))) == NULL) { + perror("Unable ro allocate memory for pthread"); + } + for (int i=0; i < THREADS; i++){ + if (pthread_create(&t[i],NULL, tmain, &"") != 0){ + perror("unable to create thread\n"); + } + } + // Need to block parent thread until brother thread are finished + for (int j=0;j < THREADS; j++){ + // bloc main thread exec with pthread_join() + if (pthread_join(t[j], &res) != 0){ + perror ("Unable to join process"); + } + } + printf("glob is %ld, should be 2000000\n", glob); + free(t); + exit (EXIT_SUCCESS); +} diff --git a/content/progsys/TDM_5-threads/src/q1_mutex.c b/content/progsys/TDM_5-threads/src/q1_mutex.c new file mode 100644 index 0000000..744e93b --- /dev/null +++ b/content/progsys/TDM_5-threads/src/q1_mutex.c @@ -0,0 +1,52 @@ +#include +#include +#include + +//define +#define THREADS 2 +#define ITERATIONS 1000000 + +static long glob = 0; +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + +void *tmain( void *arg){ + long tmp; + for (int i=0; i < ITERATIONS; i++){ + if (pthread_mutex_lock(&mutex) != 0) { + perror("Mutex lock failed"); + exit(EXIT_FAILURE); + } + tmp = glob; + tmp++; + glob = tmp; + if (pthread_mutex_unlock(&mutex) != 0) { + perror("Mutex lock failed"); + exit(EXIT_FAILURE); + } + } + return NULL; +} + +int main(int argc, char **argv) { + pthread_t *t; + void *res; + // memory allocation for threads + if ( (t=calloc(THREADS, sizeof(pthread_t))) == NULL) { + perror("Unable ro allocate memory for pthread"); + } + for (int i=0; i < THREADS; i++){ + if (pthread_create(&t[i],NULL, tmain, &"") != 0){ + perror("unable to create thread\n"); + } + } + // Need to block parent thread until brother thread are finished + for (int j=0;j < THREADS; j++){ + // bloc main thread exec with pthread_join() + if (pthread_join(t[j], &res) != 0){ + perror ("Unable to join process"); + } + } + printf("glob is %ld, should be 2000000\n", glob); + free(t); + exit (EXIT_SUCCESS); +} diff --git a/content/progsys/TDM_5-threads/src/q2.c b/content/progsys/TDM_5-threads/src/q2.c new file mode 100644 index 0000000..4d9cce8 --- /dev/null +++ b/content/progsys/TDM_5-threads/src/q2.c @@ -0,0 +1,40 @@ +#include +#include +#include +#include + +//define +#define THREADS 5 +#define ITERATIONS 5 +#define SLEEP 2 + +void *tmain( void *arg){ + for (int i=0; i < ITERATIONS; i++){ + sleep(SLEEP); + printf("I'm alive : %i\n",(int) pthread_self()); + } + return NULL; +} + +int main(int argc, char **argv) { + pthread_t *t; + void *res; + // memory allocation for threads + if ( (t=calloc(THREADS, sizeof(pthread_t))) == NULL) { + perror("Unable ro allocate memory for pthread"); + } + for (int i=0; i < THREADS; i++){ + if (pthread_create(&t[i],NULL, tmain, &"") != 0){ + perror("unable to create thread\n"); + } + } + // Need to block parent thread until brother thread are finished + for (int j=0;j < THREADS; j++){ + // bloc main thread exec with pthread_join() + if (pthread_join(t[j], &res) != 0){ + perror ("Unable to join process"); + } + } + free(t); + exit (EXIT_SUCCESS); +} diff --git a/content/progsys/TDM_6-tubes/files/tdm6.pdf b/content/progsys/TDM_6-tubes/files/tdm6.pdf new file mode 100644 index 0000000..09a238a Binary files /dev/null and b/content/progsys/TDM_6-tubes/files/tdm6.pdf differ diff --git a/content/progsys/TDM_6-tubes/index.md b/content/progsys/TDM_6-tubes/index.md new file mode 100644 index 0000000..4c9e8ab --- /dev/null +++ b/content/progsys/TDM_6-tubes/index.md @@ -0,0 +1,6 @@ +--- +title: "TDM6 : les tubes" +date: 2018-10-09 +--- + + diff --git a/content/progsys/TDM_6-tubes/src/q1.c b/content/progsys/TDM_6-tubes/src/q1.c new file mode 100644 index 0000000..5a2ba74 --- /dev/null +++ b/content/progsys/TDM_6-tubes/src/q1.c @@ -0,0 +1,59 @@ +#include +#include +#include +#include +#include + +#define BUFFMAX 256 +#define OUTPATH "packages.list" + +int main (int argc, char **argv) { + pid_t pid; + int fds[2], status; + if (pipe(fds) == -1) { + perror ("Unable to create pipe"); + } + + pid = fork(); + if (pid == -1) { + perror("Unable to fork"); + } + + else if(pid > 0){ + // father + printf("Fork : Init father...\n"); + if (close(fds[1]) == -1) { + perror("Unable to close pipe from parent"); + } + // Waiting for children to terminate + char buff[BUFFMAX]; + FILE *fout = fopen(OUTPATH,"w"); + if ( fout == NULL ){ + perror(""); + } + int n; + while ((n=read(fds[0], &buff, BUFFMAX)) > 0){ + if ( fwrite(&buff, n, 1, fout) == -1 ){ + perror("Error when writing output"); + } + } + if ( fclose(fout) == -1){ + perror("Error ou outp[ut file close"); + } + wait(&status); + } + else { + // children + if (close(fds[0]) == -1) { + perror("Unable to close pipe from child"); + } + if ( dup2(fds[1], STDOUT_FILENO) != STDOUT_FILENO){ + perror("Unable to duplicate files descriptors"); + } + if ( close(fds[1]) == -1 ){ + perror ("error on pipe in close"); + } + execlp("pacman","pacman","-Qs", NULL); + } + exit(EXIT_SUCCESS); +} diff --git a/content/reseau/1-introduction-reseau/index.md b/content/reseau/1-introduction-reseau/index.md new file mode 100644 index 0000000..ad83297 --- /dev/null +++ b/content/reseau/1-introduction-reseau/index.md @@ -0,0 +1,64 @@ +--- +date: "2018-09-03" +categories: ["Réseau", "Cours"] +title: "Réseaux - Introduction" +tags: ["OSI", "latence", "débit"] +--- + +Le principe de ce cours est de permettre de savoir configurer et gérer un réseau +d'entreprise. + +# La pile OSI (vue rapide) + +elle se découpe en 7 couches a connaitre par cœur. + + 1. Physique : les bits *câble, ondes, fibre, ADSL ...* + 2. Liaison : on parle de **trames** *Ethernet, WiFi* + 3. Réseau : acheminement - **paquets** *IP, IPX* + 4. Transport : accusé de réception, port, **datagramme** *TCP, UDP, IPX* + 5. Session : qui? quoi? *CAS (SSO)* + 6. Présentation : encodage, langue *UTF-8, XML* + 7. Application : tout le reste. + +Voir schema sur l'encapsulation + +# Latence et débit + +Voir schema Page 3 + +**Débit** : Quantité d'information que l'on est capable d'envoyer / recevoir +dans un certain laps de temps. + +**Latence** : Temps entre le moment ou j'envoie mon premier bit est envoyé et où +il est reçu. La latence est indépendante du débit. La latence étant difficile à +mesurer, il est commun d'utiliser plutôt le temps d'un aller retour. + +Les deux notions ne sont pas liées même s'il est possible que l'une impacte +l'autre. On considère que l'expérience utilisateur n'est plus fluide à partir de +10ms de latence et n'est plus "interactive" à partir de 100ms. + +## Exercice + +Calculer le débit nécessaire pour envoyer une vidéo de 640x360 à 25hz et 24 +bits/pixels et un fichier audio 16 bits à 48 Khz + +### fichier vidéo + +Une image de notre fichier vidéo se compose donc de **230400** pixels et donc +pèse **5529**Kb *(5529600 bits)*. Pour 24 images il faut un débit de +**138240**Kb/s + +### fichier audio + +Une seconde de flux audio représentant 48000 valeurs de 16 bits le débit +nécessaire est donc de **768**Kb/s. Je suis parti du principe que le fichier +audio en question est mono. + +## Correction + +Prendre des approximations, ne pas s'embêter des détails. + +Pour comparaison + + - Fichier vidéo h264 400-100 Kb/s + - Fichier audio 128 Kb/s diff --git a/content/reseau/2-couches-liaison-reseau/index.md b/content/reseau/2-couches-liaison-reseau/index.md new file mode 100644 index 0000000..5c86694 --- /dev/null +++ b/content/reseau/2-couches-liaison-reseau/index.md @@ -0,0 +1,127 @@ +--- +title: "Le modèle OSI - la couche physique, la couche liaison et la couche réseau" +date: 2018-09-05 +categories: ["Réseau", "Cours"] +tags: ["physique", "cable", "fibre", "wifi"] +--- + +Les normes 801.## concerne en général la couche physique voire la couche liaison +voir la page [IEEE 802](https://fr.wikipedia.org/wiki/IEEE_802) sur Wikipedia. + +# Les câbles + +On parles souvent de câble RJ45 ou câble Ethernet, il est plus juste de parler +de câble à paires torsadées et fiches RJ45. Pourquoi les fils sont torsadés? +tout simplement pour minimiser les perturbations +[diaphoniques](https://fr.wikipedia.org/wiki/Diaphonie) induites par les fils +entre eux. Le tout est souvent enveloppé dans un blindage soit par +paire et/ou pour l'ensemble. + +Voir la page des [paires +torsadées](https://fr.wikipedia.org/wiki/Paire_torsad%C3%A9e) sur Wikipedia + +# La fibre optique + +Le principe est de faire passer de la lumière dans un fil en utilisant les +propriété réfractrice de la lumière. La fibre est en fait composée, en son cœur, +de deux couches avec des indice de réfraction différent afin de contenir la +lumière en la faisant rebondir. + +De par leurs longueur d'onde différentes, il est tout à fait possible d'utiliser +plusieurs couleurs de lumières afin d'envoyer plusieurs signaux en simultané. + +On parle de *fibre noire* lorsque la fibre est livrée telle quelle, c'est au +client de "l'allumer" et fournissant les boitiers d'alimentation (émetteur et +récepteurs). + +A contrario, la fibre allumée est fournie avec sa "lumière" c'est par contre le +prestataire (FAI par exemple) qui attribuera la couleur de la lumière. + +Voir [la fibre optique](https://fr.wikipedia.org/wiki/Fibre_optique) sur +Wikipedia + +# Le WiFi + +Le WiFi, utilisé pour l'ensemble des normes 802.11, couvre un ensemble de +protocoles de communication sans fils utilisant les ondes radioélectriques en +utilisant des bandes de fréquences autour de 2,4 Ghz (normes a,b,g,n) et +5 Ghz(n,ac) + +La norme découpe des canaux dans les bandes définie (14 utilisables dont 11 en +France pour celle 2,4 Ghz et 25 utilisable pour 5 Ghz) + +On trouve deux type d'antennes pour le WiFi : + + - **directionnelle** : le signal est envoyé dans une direction en particulier, + qui permet de diminuer l'atténuation et d'augmenter la portée. + - **omnidirectionnelle** : le signal est envoyé dans toute les directions, ce + qui diminue la portée. + +Voir la page du [WiFi](https://fr.wikipedia.org/wiki/Wi-Fi) sur Wikipédia. + +## Le théorème de Shannon + +Voir [la +page](https://fr.wikipedia.org/wiki/Th%C3%A9or%C3%A8me_d%27%C3%A9chantillonnage) +Wikipedia. + +# Les adresses + +Quel que soit le type de réseau, il y a forcément une notion d'adresse +sous-jacente. Pou Internet, réseau de réseaux, on dénombre trois type d'adresses + +## Adresse MAC + +Inscrite directement dans le matériel (carte réseau ethernet, wifi ...). Cette +adresse est utilisée localement (réseau interne) est codée sur 48bits en +hexadécimal : 24 étant spécifique au constructeur et 24 au matériel. Deux +périphériques peuvent avoir la même adresse MAC, mais le fabriquant se +débrouillera pour les envoyer à des coins opposés du monde pour ne pas qu'ils se +retrouve sur le même réseau local. + +## Adresse IP + +C'est une adresse virtuelle, dans le sens ou elle n'est pas inscrite en dur dans +le matériel comme l'adresse MAC. Elle est globale, routable et doit être unique. +Il en existe deux type IPv4 et IPv6 + +### IPv4 + +C'est le type d'adresse le plus ancien, une adresse IPv4 se compose de 4 valeurs +décimales séparées par des points (32 bits). Il est donc possible d'en attribuer +environ 4 milliards. C'est aujourd'hui une ressource rare épuisée dans certaines +partie du globe (États-Unis par exemple). + +### IPv6 + +C'est le type d'adresse le plus récent, il a été créé pour pallier à la pénurie +d'IPv4. Une adresse IPv6 est composée de 128 bits en hexadécimal regroupés en +paquet de 16 bits séparés par des deux-points (:). + +Elles sont plus facilement structurées, prenons l'exemple de la machine 4 de la +salle 101 du CREMI, son adresse est + +``` +2001:660:6101:800:252:4 +``` + + - `2001:660` correspond au réseau + [RENATER](https://fr.wikipedia.org/wiki/R%C3%A9seau_national_de_t%C3%A9l%C3%A9communications_pour_la_technologie,_l%27enseignement_et_la_recherche0 + - `:6101` c'est la région (Aquitaine - Bordeaux) + - `:800` c'est le bâtiment du CREMI + - `:252` c'est le numéro de salle + - `:4` c'est le poste. + +On voit ici que le découpage de l'adresse IPv6 la rend lisible. + +## Le masque de sous réseau + +Il permet de distinguer la partie utilisée pour le routage de celle utilisée +pour numéroter les interface d'une adresse IP. + +En IPv4, le masque de sous réseau distingue les bits d'une adresse IP +identifiant le sous-réseau et ceux identifiant l'hôte. + +En IPv6, le masque est appelé préfixe et est un multiple de 4 afin de découper +des morceaux entiers d'adresse pour les sous réseau, facilitant ainsi la vie de +tout le monde. diff --git a/content/reseau/3-protocoles/images/Tcp_close.svg b/content/reseau/3-protocoles/images/Tcp_close.svg new file mode 100644 index 0000000..ce70386 --- /dev/null +++ b/content/reseau/3-protocoles/images/Tcp_close.svg @@ -0,0 +1,729 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + Computer B + + Computer A + + ESTABLISHED + + ESTABLISHED + Fin seq=x + Ack ack=x+1 + + + + + + + + FIN_WAIT_1 + FIN_WAIT_2 + TIME_WAIT + CLOSED + CLOSE_WAIT + LAST_ACK + CLOSED + + + Fin seq=y + Ack ack=y+1 + + + Connection is half-closedComputer B can stillsend data to A + + diff --git a/content/reseau/3-protocoles/images/Tcp_connect.svg b/content/reseau/3-protocoles/images/Tcp_connect.svg new file mode 100644 index 0000000..1117793 --- /dev/null +++ b/content/reseau/3-protocoles/images/Tcp_connect.svg @@ -0,0 +1,589 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + Server + + Client + + CLOSED + + + SYN_SENT + + + + LISTEN + + + + SYN_RVCD + + + + ESTABLISHED + + + CLOSED + + + ESTABLISHED + + + socket() connect() + + + + socket() bind() listen() accept() + + + + + + Syn seq=x + Syn+Ack seq=y ack=x+1 + Ack seq=x+1 ack=y+1 + + diff --git a/content/reseau/3-protocoles/images/Tcp_flux.svg b/content/reseau/3-protocoles/images/Tcp_flux.svg new file mode 100644 index 0000000..88536da --- /dev/null +++ b/content/reseau/3-protocoles/images/Tcp_flux.svg @@ -0,0 +1,225 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/content/reseau/3-protocoles/images/Tcp_talk.svg b/content/reseau/3-protocoles/images/Tcp_talk.svg new file mode 100644 index 0000000..a7676a3 --- /dev/null +++ b/content/reseau/3-protocoles/images/Tcp_talk.svg @@ -0,0 +1,463 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + Computer B + + Computer A + + ESTABLISHED + + ESTABLISHED + + + Data seq=x ack=y + Ack seq=y ack=x+n + Send n bytes of data + Receive n bytes of data + Know that data are received + write() + read() + + diff --git a/content/reseau/3-protocoles/index.md b/content/reseau/3-protocoles/index.md new file mode 100644 index 0000000..35ebb6d --- /dev/null +++ b/content/reseau/3-protocoles/index.md @@ -0,0 +1,143 @@ +--- +title: "Les protocoles" +categories: ["Réseau", "Cours"] +date: 2018-09-12 +--- + +Les protocoles sont des conventions qui définissent des manières de communiquer. +En informatiquem on dénombre deux types de protocoles : binaires ou textuels. + +Théoriquement, aucun protocole ne peut être parfait. Ceci peur être illustré par +,le théorême des deux armees : + +> Soit des armées aui combattent, l'armée A, composée d'un seul soldat est +> assiégés par l'arméé B composée elle de deux soldats. +> +> Les deux soldats B sont de part-et d'autres du soldat de A qui possède un +> fusil. Pour assurer leurs victoire, les deux soldats B doivent attaquer de +> façon coodonnée. Utilisant des pigeons voyageurs, comment s'assurer de la bnne +> transmission des messages : le soldat A pourrait tuer le messager à tout +> moment (contenant le message ou la confirmation de bonne réception). + +# La commutation de circuits + +C'est le fonctionnement typique du réseau téléphonique jusque dans les années +60-70. les information échangées emprunte toujours le même chemin au sein du +réseau pour une session donnée. Son principal inconvénient est l'occupation de +la "route" même si aucune donnée ne transite (blanc). + +Voir [la commutation de circuits][w_comm-cirk] sur Wikipedia + +[w_comm-circ]:https://fr.wikipedia.org/wiki/Commutation_de_circuits + +# La commutation de paquet + +Apparue dans les années 70, il est ici question de découper l'information en +paquets contenant un entête pour l'acheminement, et de les faire transiter par +des routes aui peuvent être différentes. Il n'y a pas ici de réservation de +route, optimisant l'utilisation de la ressource. + +En France, l'ingénieur [Louis Pouzin][w_l-pouzin] a inventé le datagramme qui +servira de base pour le réseau par commutation de paquest, puis pour le +protocole UDP et inspirera Vint Cerf pour la création de TCP-IP + +Voir [la commutation de paquets][w_comm-pak] sur Wikipedia + +[w_l-pouzin]:https://fr.wikipedia.org/wiki/Louis_Pouzin +[w_comm-pak]:https://fr.wikipedia.org/wiki/Commutation_de_paquets + +# Les sommes de contrôles + +Les *checksum* ou sommes de controles permettent de s'assurer de l'intégrité +d'un message reçu par le réseau. Ce n'est cependant pas un code de correction +d'erreur, le but ici est bien la détection (pour éventuellement demander à +l'expéditeur de renvoyer le message). + +Dans notre quotidien, les sommes de contrôles sont utilisée pour les numéros +INSEE, les numéros de cartes bancaire etc. + +Il sont là avant tout pour détecter des erreur non intentionnelle (fiabilité) +mais n'ont pas vocation à prévenir les erreur intentionnelles (sécurité) + +Voir [les sommes de contrôles][w_checksum] + +[w_checksum]:https://fr.wikipedia.org/wiki/Somme_de_contr%C3%B4le + +# Le protocole TCP + +TCP pour *Transmission Control Protocol* est un protocole de transport fiable de +l'information sur des réseau infomatique. Il correspond à la couche +**transport** du modèle OSI. Il fonctionne en trois phases : + + - L'établissement d'une connection + - Le transfert des données + - La fin de connexion + +## Etablissement d'une connexion + +![Établissement d'une connexion TCP (source Wikipedia)](./images/Tcp_connect.svg) + +Le serveur ouvre une *socket* et attends la demande de connexion du client +(attente passive). Le client initie une connexion active en trois temps : + + - le client envoi un segment *SYN* au serveur. + - le serveur lui réponds par un segment *ACK + SYN* + - le client confirme par un segment *ACK* + +Durant ces échanges, les numéros de séquences du serveur et du client sont +synchronisés. Le client utilise son numéro de séquence `x` pour son premier +segment *SYN*. Le serveur utilise son numéro de séquence `y` dans le segment +*ACK+SYN* et le numero d'aquitement `x + 1`. Le client confirme par un *ACK* +avec comme numéro de séquence `x + 1` et comme numéro d'aquittement `y + 1`. + +## Tranfert de données + +![Transfert de données TCP (source Wikipedia)](images/Tcp_talk.svg) + + +Lors du transfert de données, les numéros de séquences sont utilisés afn de +réordonner les paquets. Les aquitements servent à s'assurer de la transmission +des messages et les sommes de contrôles leurs intégrités. + + - Le serveur envoi un paquet avec comme numéro de séquence `x` et est numero + d'aquittement `y` avec `z` octets + - le client réponds avec un sergment *ACK* avec comme numéro de séquence `x` + et comme numéro d'aquittenemt `y + z` + +Les numéros de soéquences sont des nombres entiers non-signés codés sur 32bits + +### temporisation + +TCP utilise un mécanisme de temporisation et de retransmission. Après l'emvoi +d'un segment, TCP attendra un certain temps la confirmation par un *ACK* +correspondant. + +## Terminaison d'une connexion + +![Fin connexion TCP (source Wikipedia)](images/Tcp_close.svg) + +La fin d'une connexion TCP se fait en quatre temps, chaque extremités de la +connexion envoyant un segment *FIN* et répondant à l'autre par un *ACK* + +## Gestion des flux + +Dans un espace réseau, comment les extremités (souvent le serveur) devinent la +vitesse de transmission des segments? En général prudemment : le serveur +commence à transferer les données lentement et augmente au fur et à mesure le +débit. Il inspecte alors les *ACK* et ajuste le débit en fonction des retours. + +![Gestion de flux d'une connexion TCP (source Wikipedia)](images/Tcp_flux.svg) + + 1. la connexion démarre doucement, le débit augmente au fur et à mesure que les + *ACK* reviennent en temps et en heure. + 2. les segments *ACK* n'arrivent pas à temps, le débit est diminué. + 3. à partir du moment ou les segments *ACK* arrivent bien, le débit est aumenté + à nouveau progressivement. + 4. on repasse à létape 2. + + Il existre plusieurs algorithmes pour la gestion du débit : Reno, Vegas, Bil, + Cubil. + +# Bibliographie + +[TCP sur Wikipedia](https://fr.wikipedia.org/wiki/Transmission_Control_Protocol) diff --git a/content/reseau/4-API_C/images/kernel_buffers.svg b/content/reseau/4-API_C/images/kernel_buffers.svg new file mode 100644 index 0000000..0971edb --- /dev/null +++ b/content/reseau/4-API_C/images/kernel_buffers.svg @@ -0,0 +1,904 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/content/reseau/4-API_C/index.md b/content/reseau/4-API_C/index.md new file mode 100644 index 0000000..11bc1f3 --- /dev/null +++ b/content/reseau/4-API_C/index.md @@ -0,0 +1,318 @@ +--- +title: "Programmation réseau avec l'API C" +date: 2018-09-26 +modify: 2018-10-03 +tags: ["programmation", "C"] +categories: ["Réseau", "Cours"] +--- +# API C pour un paquet UDP (exemple du DNS) + + 1. `socket()` : Appel système qui retourne un identifiant unique (entier non + signé) représentant une socket ouverte par le noyau, dans le style d'un + descripteur de fichier. + 2. `bind(53)` : Le processus annonce qu'il se positionne sur le port 53 en + écoute (serveur DNS) + 3. `rcvfrom()` : récupère les données (datagrammes) depuis le noyau, c'est un + appel bloquant. + 4. `sento()` : le processus fournit au noyau les données pour le transfert ( + l'écriture). C'est l'équivalent de `write()` utilisé poour les fichiers. + 5. `close()` : ferme la connexion. + +Ces étapes décrites ci-dessus sont valables pour la partie serveur, la partie +client est plus simple : `socket()` -> `sendto()` -> `rcvfrom()` -> `close()` + +# API pour un transfert TCP (avec connexion) + +# côté serveur + + 1. `socket()` + 2. `bind(80)` + 3. `listen()` : annonce l'ouverture du port et l'écoute + 4. `accept()` : attend des connexion avec un client (état disponible) + 5. `read()` : appel système lit les données provenant du réseau, en HTTP ce + serait la demande de la page `index.html` par exemple. + 6. `write()` : renvoi les données vers le réseau qui seront ensuite envoyées + par le noyau vers le client. + +## côté client + + 1. `connect()` : appel cloquant pour initier la connexion. + 2. `write()` : envoyer les donnés vers le client (la requete HTML par exemple) + 3. `read()` : lit les données (bloquant). Dès que les données sont prête, elles + sont envoyées à l'application. Si rien n'est lut, l'appel se terminera alors + seulement au moment du `close()` + +# Socket + +Pour démarrer une socket, plusieurs information son importante et changerons la +manière de procéder : + + - la famille d'adresse : IPv4, IPv6 + - le type de socket : échange simple de datagrammes (UDP) ou par une + connexion (TCP) + - le protocole : TCP, UDP, ICMP ... + - l'adresse locale (IP et port) + - l'adresse distante (IP et port) + +# API C + +Il faut bien avoir à l'esprit qu'en réseau, les données sont toujours au forman +big-endian. Pour avoir plus d'explications voir la page Wikipedia sur +[l'endianess](https://fr.wikipedia.org/wiki/Endianness). + +Il faut donc penser à utiliser des fonctions de conversion : + +```c +/* Conversion vers/depuis ordre réseau */ +uint16_t htons(uint16_t hostshort); #host to network short +uint16_t ntohs(uint16_t netshort); #network to host short +uint32_t htonl(uint32_t hostlong); #host to network long +uint32_t ntohl(uint32_t netlong); #network to host long + +/* Conversion ascii/binaire */ +int inet_aton(const char *ascii, struct in_addr *binaire); +char *inet_ntoa(struct in_addr binaire); + +/* De même, mais portables v4/v6 */ +int inet_pton(sa_family_t af, const char *ascii, void *binaire); +const char *inet_ntop(sa_family_t af, const void *binaire, char *ascii, socklen_t size); +``` + +## Structure pour IPv4 + +```c +struct in_addr { + /* ... */ + __be32 s_addr; +} +struct sockaddr_in { + sa_family_t sin_family; /* AF_INET6 */ + struct in6_addr sin_addr; + __be16 sin_port; +} +``` + +## Structure pour ipv6 + +```c +struct in6_addr { + /* ... */ + u8 s6_addr[16]; +} +struct sockaddr_in { + sa_family_t sin6_family; /* AF_INET6 */ + struct in6_addr sin6_addr; + __be16 sin6_port; +} +``` + +## API UDP + +```c +/* Créer une socket */ +int socket(int domain, int type, int protocol); +/* e.g. fd = socket(AF_INET, SOCK_DGRAM, 0); */ + +int bind( + int sockfd, # numéro de descripeur de socket + const struck sockaddr *addr # sock_addr peut être de type 4 ou 6 (cast) + socklen_t addrlen # taille de a structure sock_addr +) +/* Choisir l’adresse distante (IP et port), optionnel, pour utiliser +send/write/recv/read plutôt que sendto/recvfrom */ + +int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); + +/* Envoyer un datagramme UDP à un service d’une machine donnée */ +ssize_t sendto( + int sockfd, + const void *buf, + size_t len, + int flags, + const struct sockaddr *dest_addr, + socklen_t addrlen +); + +/* Recevoir un datagramme UDP depuis n’importe quelle machine */ +ssize_t recvfrom( + int sockfd, + void *buf, #tampon de données (ici à recevoir) + size_t len, + int flags, + struct sockaddr *src_addr, + socklen_t *addrlen +); + +/* Fermer la socket */ +int close(int fd); +``` + +## API C TCP + +```c +* voir man 7 tcp pour plus d’explications */ +/* Créer une socket */ +int socket(int domain, int type, int protocol); +/* e.g. fd = socket(AF_INET, SOCK_STREAM, 0); */ + +/*** Partie client ***/ +/* Se connecter à un service d’une machine donnée */ +int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); + +/*** Partie serveur ***/ +/* Attacher à un port local donné */ +int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); + +/* Passer en mode serveur */ +int listen(int sockfd, int backlog); + +/* Accepter une nouvelle connexion */ +int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); + +/* Fermer la socket */ +int close(int fd); + +/* Récupérer l’adresse locale */ +int getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen); + +/* Récupérer l’adresse distante */ +int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen); +``` + +# `write()`, `read()`, Tampons noyau + +![les buffers noyau](./images/kernel_buffers.svg) + +Pour chacune des connexions établies le noyau Linux créer des tampons : un pour +la lecture et un pour l'écriture. Pour la l'écriture, lorsqu'un processus +invoque un `write()`, les données sont d'abord écrites dans un tampon. S'il est +plein (sa taille est définie à l'avance), le noyau bloque l'appel `write()` et +lorsque de la place se libère, il le débloque. + +De l'autre côté, les données sont reçues dans le tampon `read()` et lorsqu'elles +sont transférées au processus, un segment *ACK* est envoyé à l'expéditeur. le +destinataire averti l'expéditeur de la place disponible dans son tampon `read()` +par le biais du champ `window size` (octet 16 à 18 d'un sergent TCP) dans un +segment *ACK*. Si le tampon contient, par exemple 2ko mais que le `read()` en +demande 10ko, les 2Ko sont automatiquement transférés au processus. + +Les tampons peuvent fausser complètement les outils de mesure de performance +réseau, en effet lors d'un appel `write()` les données sont transmise dans le +tampon très rapidement faussant alors la mesure du débit. + +## visualiser les buffers. + +Il est possible de visualiser les données en attentes dans les buffets avec la +commande `netstat` : + +```shell +[root@eph-archbook ephase]# netstat +Active Internet connections (w/o servers) +Proto Recv-Q Send-Q Local Address Foreign Address State +tcp 0 0 eph-archbook:47954 mail.gandi.net:imaps ESTABLISHED +tcp 0 0 eph-archbook:52264 imap.u-bordeaux.fr:imap ESTABLISHED +tcp 32 0 ?192.168.1.91:34456 vpn-0-24.aquilene:https CLOSE_WAIT +tcp 32 0 192.168.1.91:33424 vpn-0-24.aquilene:https CLOSE_WAIT +... +``` + +L'étal des tampons est indiqué par les champs `Recv-Q` et `Send-Q`. + +## option de socket TCP + +Les entêtes complète d'un datagramme TCP pèse au moins 54 octets (entêtes +Ethernet et IP comprises). Afin d'optimiser l'envoi de données, il est souvent +préférable de concaténer plusieurs appels `write()` ou d'utiliser `printf()` et +les mécanisme de tampons de la libc. Il est aussi possible de demander à TCP +d'attendre l'arrivée d'autres données avant d'envoyer un segment avec bien +évidemment la gestion d'un *timeout* pour ne pas attendre trop longtemps +(algorithme de [Nagle][l_nagle]). Ce n'est cependant pas adapté à tous les +protocoles : si ce système fonctionne bien pour HTTP, ce n'est pas le cas de SSH +ou la latence induite par ce mécanisme pose problèmes. + +```C +#include + +int setsockopt (int sockfd, int level, int optname, const void *optval, socklen_t optlen); +int getsockopt (int sockfd, int level, int optname, void *optval, socklen_t optlen); +``` + + - `int level` : niveau de la pile ou appliquer l'option, `SOL_TCP` signifiera + la partie TCP. + - `int optname` : l'option à activer, par exemple `TCP_NODELAY` afin de + désactiver l'algorithme de Nagle. Il est possible aussi de mettre un + bouchon au tampon `write()` avec `TCP_CORK`. Il faudra alors le désactiver + pout permettre au noyau d'envoyer les segments depuis les données du + *buffer* + +[l_nagle]:https://fr.wikipedia.org/wiki/Algorithme_de_Nagle +### l'option `SO_REUSEADDR` de `SOL_SOCKET` + +Par défaut, le système empêchera la connexion à une socket si un service y +était quelques minutes auparavant. Dans le cadre du test d'un programme ou pour +du debug, il est parfois nécessaire de désactiver ce comportement, et c'est +possible avec : + +```C +setsockopt ( fd, SOL_SOCKET, SO_REUSEADDR, "1"); +``` + +# La Qos (Qualité de Service) + +En réseau il est possible d'obtenir : + + - une bonne latence + - un bon débit + - de la fiabilité + +Il ne sera pas possible d'obtenir les trois. Il existe plusieurs solutions pour +prioriser les flux. Par exemple les petits paquets : leurs tailles indique +sûrement que l'on recherche une meilleure latence plutôt qu'un gros débit. + +Il est aussi possible de faire du DPI *Deep Packet Inspection* que ne serait pas +très approprié du point de vue de l'éthique et de la loi (neutralité du net...)< +En TCP il existe le champs ToS *Type of service" Mais celui-ci est inutilisé du +fait de son implémentation différentes chez les fabricants de matériels et +logiciels. + +Les équipements sur Internet ont tous un système de buffer, ce qui n'est pas +sans poser problèmes pour la *QoS* : s'il est facile de maitriser son routeur, +éventuellement le DSLAM si son fournisseur d'accès à Internet le permet, il est +est tout autres pour les équipements par lesquels transitent nos paquets.(voir +le [Bufferbloat][l_buffetbloat]) + +[l_bufferbloat]:https://en.wikipedia.org/wiki/Bufferbloat + +# API réseau et threads + +Il est tout à fait possible d'utiliser les *threads* et les *processus* pour +créer des buffers différents et ainsi paralléliser l'envoi / réception de +données et ainsi éviter de bloquer l'ensemble de son application avec un +`write()` ou un `read()`. Il est aussi possible d'utiliser l'API `SELECT` et +ainsi éviter de complexifier son code avec des threads / processus. + +```C +void FD_ZERO(fd_set *set); +void FD_CLR(int fd, fd_set *set); +void FD_SET(int fd, fd_set *set); +int FD_ISSET(int fd, fd_set *set); +int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); + +/* Attend des données lisibles sur fd1 ou fd2, traite en conséquence */ +int attend(int fd1, int fd2) { + fd_set set; + int max; + FD_ZERO(&set); + FD_SET(fd1, &set); + FD_SET(fd2, &set); + max = MAX(fd1, fd2); + if (select(max+1, &set, NULL, NULL, NULL) == -1) + return -1; + if (FD_ISSET(fd1, &set)) + traite(fd1); + if (FD_ISSET(fd2, &set)) + traite(fd2); + return 0; +} +int poll(struct pollfd *fds, nfds_t nfds, int timeout); +``` diff --git a/themes/mainroad b/themes/mainroad new file mode 160000 index 0000000..279cd6c --- /dev/null +++ b/themes/mainroad @@ -0,0 +1 @@ +Subproject commit 279cd6cbf36560db8b03bd54804e25ff8e3c26a1 diff --git a/themes/simpleit-hugo-theme b/themes/simpleit-hugo-theme new file mode 160000 index 0000000..062b4a1 --- /dev/null +++ b/themes/simpleit-hugo-theme @@ -0,0 +1 @@ +Subproject commit 062b4a11a7e4df3eaeb09877c49ef22c9300c4a4