Bonjour

Voilà, je suis un frais codeur en langage C qui fait ses premières armes. J'ai décidé pour commencer de me lancer dans le codage d'un bot irc. J'aimerais ici présenter mon code et vous demander ce que vous en pensez. Je ne vous demande pas de faire du débuggage bien sur, mais plutôt à ce que vous m'aidiez à comprendre s'il y a de grosses boulettes et erreurs de programmation, dans l'optique de faire un code propre. Donc toutes les remarques sont bienvenues, mais il y a un certains nombre de points sur lesquels je m'interroge particulièrement.

1) J'utilise les posix threads. Le but de l'opération est que le bot soit en situation d'idle, et qu'il puisse autant réagir à des messages arrivant sur la socket, qu'être disponible pour l'envoi de messages. Du coup ça se concrétise avec deux threads, dont l'un appelle une fonction de lecture sur la socket (read_func) et l'autre appelle une fonction d'écriture sur stdin.
Existe-t-il des moyens plus simples de réaliser cette situation? J'ai vu récemment que je pourrais éventuellement utiliser select() qui permet d'endormir le bot en scrutant une série de descripteurs de fichier. Quelle est la meilleure solution ?

2) Vous remarquerez que j'utilise des variables globales. Au début je voulais m'en passer totalement, mais c'était galère, les buffer d'écriture et lecture étant utilisés partout dans le code. Est-ce vraiment un problème d'utiliser des variables globales? Serait-il mieux de les éviter ou pas, et pourquoi ?

Je poste ici juste le fichier principal, qui contient l'essentiel de la structure du programme et suffit pour comprendre son fonctionnement. Le bot au complet, si quelqu'un veut voir le reste, est disponible sur http://keikoz.free.fr/scripts/kbot-0.06.tar.gz .

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <netdb.h>
#include "commands.h"
#include "irc.h"
#include "kbot.h"
#include "files.h"
 
/* Initialisation des fonctions */
void *write_funct(void *arg);
void *read_funct(void *arg);
 
/* Variables globales. Est-ce mal ? Les buffers sont utilisés tout au long
 * de la connexion ... */
int Cli_Sock;
char wBuffer[MAX_BUFFER];
char rBuffer[MAX_BUFFER];
pthread_t read_thread, write_thread;
 
 
int main(int argc, char *argv[])
{
  int Serv_Port;
  struct sockaddr_in Serv_Addr;
  struct hostent *Server;
 
 
  /* On vérifie que la commande est utilisée correctement */
  if (argc != 3) {
    fprintf(stderr,"Usage: kbot hostname port\n");
    exit(1);
  }
  else {
    Serv_Port = atoi(argv[2]);
    if (Serv_Port < 1 || Serv_Port > 65355) {
      fprintf(stderr, "Invalid port\n");
      exit(1);
    }
  }
 
 
  /* Appel du fichier de configuration */
  conf_file_open();
 
 
  /* On créé l'adresse serveur avec les paramètres de connexion */
  Server = gethostbyname(argv[1]);
  Serv_Addr.sin_family = AF_INET;
  Serv_Addr.sin_port = htons(Serv_Port);
  memcpy(&Serv_Addr.sin_addr.s_addr, Server->h_addr, Server->h_length);
 
 
  /* On établi le socket (pourquoi AF_INET et pas PF_INET ?) */
  Cli_Sock = socket(AF_INET, SOCK_STREAM, 0);
  if (Cli_Sock < 0) {
    fprintf(stderr,"Erreur lors de la création du socket\n");
    exit(1);
  }
 
 
  /* On établit la connection sur le socket */
  if(connect(Cli_Sock, (struct sockaddr*) &Serv_Addr, sizeof(Serv_Addr))!= 0) {
    fprintf(stderr,"Erreur lors de la connection\n");
    exit(1);
  }
 
 
  /* Threads (écriture, lecture) */
  pthread_create(&write_thread, NULL, write_funct, NULL);
  pthread_create(&read_thread, NULL, read_funct, NULL);
 
 
  /* On rejoint les thread lors de leur fin d'exécution) */
  pthread_join(write_thread, NULL);
  pthread_join(read_thread, NULL);
 
  return 0;
}
 
 
/* fonctions d'écriture/lecture dans le socket */
void *write_funct (void *arg)
{
  /* Modules */
  auth();
 
  /* Boucle: Processus d'écriture */
  while (1) {
    memset(wBuffer, 0, MAX_BUFFER);
    fgets(wBuffer, MAX_BUFFER-1, stdin);
 
    commands();
 
    if (write(Cli_Sock, wBuffer, strlen(wBuffer)) < 0)
      fprintf(stderr,"Error writing to socket\n");
  }
  return(0);
}
 
void *read_funct (void *arg)
{
  while (1) {
    int n;
 
    memset(rBuffer,0, MAX_BUFFER);
    n = recv(Cli_Sock, rBuffer, MAX_BUFFER, 0);
 
    /* Situation d'écriture normale. Revoir cette partie pour intégrer le traitement des commandes irc (qui se terminent par un \r\n) */
    if (n > 0) {
 
      /* Ecriture sur stdout */
      printf(">%s", rBuffer);
 
      /* Modules */
      on_ping();
 
    }
 
    /* Cas erreur */
    else if (n < 0) 
      fprintf(stderr,"Error reading from socket\n");
 
    /* Fermeture du socket distant */
    else if (n == 0) {
      if (close(Cli_Sock) != 0)
	fprintf(stderr, "Could not close the socket\n");
      printf("Fin de la connection\n");
      pthread_exit(&read_thread);
    }
 
  }
  return(0);
}