Obligement - L'Amiga au maximum

Jeudi 28 mars 2024 - 17:59  

Translate

En De Nl Nl
Es Pt It Nl


Rubriques

Actualité (récente)
Actualité (archive)
Comparatifs
Dossiers
Entrevues
Matériel (tests)
Matériel (bidouilles)
Points de vue
En pratique
Programmation
Reportages
Quizz
Tests de jeux
Tests de logiciels
Tests de compilations
Trucs et astuces
Articles divers

Articles in english


Réseaux sociaux

Suivez-nous sur X




Liste des jeux Amiga

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z,
ALL


Trucs et astuces

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Glossaire

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Galeries

Menu des galeries

BD d'Amiga Spécial
Caricatures Dudai
Caricatures Jet d'ail
Diagrammes de Jay Miner
Images insolites
Fin de jeux (de A à E)
Fin de Jeux (de F à O)
Fin de jeux (de P à Z)
Galerie de Mike Dafunk
Logos d'Obligement
Pubs pour matériels
Systèmes d'exploitation
Trombinoscope Alchimie 7
Vidéos


Téléchargement

Documents
Jeux
Logiciels
Magazines
Divers


Liens

Associations
Jeux
Logiciels
Matériel
Magazines et médias
Pages personnelles
Réparateurs
Revendeurs
Scène démo
Sites de téléchargement
Divers


Partenaires

Annuaire Amiga

Amedia Computer

Relec


A Propos

A propos d'Obligement

A Propos


Contact

David Brunet

Courriel

 


Programmation : C - WGet (exemple de réception de données via la bsdsocket.library)
(Article écrit par Gilles Pelletier - août 2018)


Les interfaces de connexion ("sockets")

Les "sockets", ou Berkeley Sockets Interface, sont un ensemble normalisé de fonctions de communication développé par l'université de Berkeley à partir des années 1980.

Cette interface existe dans pratiquement tous les langages de programmation, du C au C# en passant par Java. Une interface de connexion représente une prise par laquelle une application peut envoyer et recevoir des données. Cette prise permet à l'application de se brancher sur un réseau et communiquer avec d'autres applications.

Les piles TCP/IP sur Amiga

Voici la liste des quelques piles TCP/IP connues sur Amiga :
Et aussi WinUAE. C'est vrai, ce n'est pas une pile TCP/IP, c'est un émulateur... mais en allant regarder dans les réglages, au niveau de Hardware/Expansion/Network, on trouve la fameuse bsdsocket.library.

WGet

...et on peut utiliser la pile TCP/IP de Windows, la fameuse ws_32.dll alias Windows Socket 2.0 32-Bit DLL, à travers la bsdsocket.library.

Petit programme

Pour illustrer le fonctionnement de ces interfaces de connexion, rien de tel qu'un petit programme. Il devrait compiler avec le SASC 6.0 et le netinclude d'AmigaOS 4.0.

/*
 * wget.c
 * récupère le contenu d'une url dans un fichier
 * exemple: wget www.google.com 80 /index.htm
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <proto/exec.h>
#include <proto/bsdsocket.h>

struct Library *SocketBase ;

int main(int argc, char* argv[])
{
  struct sockaddr_in servaddr ;
  struct hostent *hp ;
  struct protoent *pe ;
  int sock_id ;
  char *message ;
  int msglen, msgcur, msgtodolen ;
  int err ;
  int port ;
  ULONG addr ;

  if (argc < 3)
  {
    printf("Usage: %s   ", argv[0]) ;
    exit(0) ;
  }

  port = atoi(argv[2]) ;
  if (port == 0) port = 80 ;

  message = malloc(2048) ;
  if (message == NULL)
  {
    printf("no mem\n") ;
    exit(0) ;
  }
  else
  {
    memset(message, 0, 2048) ;
  }

  SocketBase = OpenLibrary("bsdsocket.library", 0) ;
  if (SocketBase == NULL)
  {
    printf("no TCP/IP stack, no BSDsocket.library\n") ;
    exit(0) ;
  }
  else
  {
    printf("%s %ld.%ld\n", SocketBase->lib_Node.ln_Name, SocketBase->lib_Version, SocketBase->lib_Revision ) ;
  }

  pe = (struct protoent*)getprotobyname("tcp") ;
  if (pe == NULL)
  {
    printf("Cannot find protocol\n") ;
    exit(0) ;
  }
  else
  {
    printf("Got protocol \"%s\" %ld\n", pe->p_name, pe->p_proto) ;
  }

  /* Créé un socket */
  sock_id = socket(AF_INET, SOCK_STREAM, pe->p_proto) ;
  if( sock_id == -1 )
  {
    printf("Couldn't get a socket.\n") ;
    exit(EXIT_FAILURE) ;
  }
  else
  {
    printf("Got a socket.\n");
  }

  memset(&servaddr, 0, sizeof(servaddr)) ;

  /* adresse du serveur distant */
  hp = (struct hostent*) gethostbyname(argv[1]) ;
  if (hp == NULL)
  {
    printf("Couldn't get an address.\n") ;
    exit(EXIT_FAILURE) ;
  }
  else
  {
    /* là on aimerait bien écrire un truc comme **(UBYTE**)hp->h_addr, */
    /* mais le 68000 n'est pas d'accord pour lire une adresse          */
    /* potentiellement impaire, alors on y va prudemment en lisant     */
    /* octet par octet */
    UBYTE *p = (UBYTE *)hp->h_addr ;
    addr = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3] ;

    printf("Got an address.\n") ;
    printf("\"%s\" len=%ld %s\n", hp->h_name, hp->h_length, Inet_NtoA(addr)) ;
  }

  /* petit délire, rien que pour utiliser les fonctions de l'API bsdsocket... */
  servaddr.sin_addr.s_addr = inet_addr((APTR)Inet_NtoA(addr)) ;

  /* numéro de port et type */
  servaddr.sin_port   = htons(port) ;
  servaddr.sin_family = AF_INET ;

  /* connexion */
  err = connect(sock_id, (struct sockaddr *)&servaddr, sizeof(servaddr)) ;
  if (err != 0)
  {
    int i ;
    printf("Couldn't connect. %ld\n", err);
    printf("%02x", servaddr.sin_len) ;
    printf("%02x", servaddr.sin_family) ;
    for (i=0; i< 14; i++)
    {
      printf("%02x", ((struct sockaddr*)&servaddr)->sa_data[i]) ;
    }
    printf("\n") ;
  }
  else
  {
    printf("Got a connection!!!\n");
  }

  if (err == 0)
  {
    /* Ouvrir un fichier pour conserver ce que l'on reçoit */
    FILE *f= fopen("ram:bidule.bin", "wb") ;

    /* création d'une demande GET, avec tous les champs qu'il faut pour être poli avec le serveur */
    sprintf( message,
             "GET %s HTTP/1.0\r\n"
             "Host: %s\r\n"
             "From: nowhere\r\n"
             "User-Agent: %s\r\n\r\n",
             argv[3],   /* l'url */
             argv[1],   /* le serveur */
             argv[0]) ; /* le nom du programme */

    msglen     = 0 ;
    msgtodolen = strlen(message) ;
    msgcur     = 0 ;

    /* Envoyer la demande GET */
    do
    {
      msglen = send(sock_id, message+msgcur, msgtodolen, 0) ;
      if (msglen > 0)
      {
        msgcur     += msglen ;
        msgtodolen -= msglen ;
      }
    } while ((msglen > 0) && (msgtodolen > 0)) ;

    /* Lire la réponse */
    do
    {
      msglen = recv(sock_id, message, 2048, 0) ;

      if (msglen < 0)
      {
      }
      else if (msglen == 0)
      {
      }
      else
      {
        /* Ecrire un petit truc à l'écran (utile si la longueur de la réponse > 2Ko) */
        printf("response (%ld bytes):%s", msglen, message);

        if (f != NULL)
        {
          /* Ecriture dans le fichier ram:bidule.bin */
          fwrite(message, msglen, 1, f) ;
        }
      }
    } while (msglen > 0) ;

    if (f != NULL)
    {
      /* Fermeture du fichier ram:bidule.bin */
      fclose(f) ;
    }
  }

  CloseSocket(sock_id) ;

  free(message) ;

  CloseLibrary(SocketBase) ;

  return 0 ;
}

Makefile

Le petit programme ne compile pas ? Dans la user-startup ou la startup-sequence, il devrait y avoir la définition des includes pour le SAS C à l'aide de la commande "assign".

assign INCLUDE: dev:sc/include

Ajouter :

assign NETINCLUDE: dev:sdks/sdk_53.30/netinclude

Ce fameux "netinclude" se trouve dans le répertoire "SDK_Install/base.lha/Include" du sdk_53.30.lha.

Après avoir recopié le fichier source wget.c dans un répertoire (nommé wget aussi, il faut savoir ranger ses programmes :)), éditer un fichier makefile comme suit :

target: wget

wget.o: wget.c
  sc INCLUDEDIR=NETINCLUDE: OBJNAME=wget.o wget.c

wget: wget.o
  slink LIB:c.o,wget.o TO wget LIB LIB:sc.lib NOICONS

De cette manière, le pré-compilateur ira chercher dans NETINCLUDE: puis dans INCLUDE: s'il ne trouve pas son include. Et puis on ne perturbe pas ses includes préférés, puisqu'ils sont dans des répertoires distincts.

La première ligne signifie que l'on veut construire le programme wget. La commande "sc" compile le code source wget.c avec les options qui vont bien. La commande "slink" lie le petit segment de démarrage c.o avec les fonctions C standard de sc.lib pour générer le programme wget.

Lancer ensuite la commande "scsetup". On devrait obtenir ceci :

WGet

Puis, on va fébrilement cliquer sur "Build"... pour que la machine infernale de compilation se lance.

WGet

Essais

Taper "wget www.google.com 80 /index.htm". Résultat : une belle erreur 404... alors que 10 ans en arrière, il rendait quelque chose de mieux.

De mieux en mieux : taper en une seule ligne "wget weather.service.msn.com 80 /data.aspx?outputview=search&weasearchstr=Grenoble&culture=fr-FR&src=wget" et il vous donnera sûrement la météo dans les environs de Grenoble...

URL or not URL ?

wget weather.service.msn.com 80 /data.aspx?outputview=search&weasearchstr=Grenoble&culture=fr-FR&src=wget est l'équivalent de la saisie de l'URL (Uniform Resource Locator) suivante dans la barre d'adresse d'un navigateur : http://weather.service.msn.com/data.aspx?outputview=search&weasearchstr=Grenoble&culture=fr-FR&src=wget Vous remarquerez que l'on est en HTTP, lien ici.

De toute façon, la machine weather.service.msn.com n'est pas sécurisée, toutes les données échangées entre le client et le serveur passent en clair. Pour faire quelque chose de plus sérieux en HTTPS, il y a un sacré boulot à entreprendre.

Conclusion

On est loin d'un navigateur, mais on est très proche d'une commande wget. J'espère vous avoir donné l'envie d'utiliser le SAS/C, même s'il date, il m'a rendu de bons services.

Voilà de quoi bien occuper ses soirées, sachant que le code donné en exemple fonctionne en mode 68000 et aussi sous Workbench 1.3. Il n'existe pas de pile TCP/IP pour 68000 et Workbench 1.3, seul WinUAE le rend possible... car tout le gros du travail se passe du côté Windows.


[Retour en haut] / [Retour aux articles]