-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathclient.c
178 lines (148 loc) · 4.71 KB
/
client.c
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <signal.h>
#include <errno.h>
#include <pthread.h>
#include "dht.h"
#define CLIENT_TIMEOUT 5
#define CLIENT_WAITTIME 1
// utile si jamais le serveur est hors ligne ou ne répond pas
void * client_timeout(void * arg) {
int sockfd = * (int *) arg;
sleep(CLIENT_TIMEOUT);
printf("Timeout. Le serveur est peut-être indisponible.\n");
close(sockfd);
exit(EXIT_SUCCESS);
}
// on attend si jamais d'autres paquets arrivent
void * client_waittime(void * arg) {
int sockfd = * (int *) arg;
sleep(CLIENT_WAITTIME);
close(sockfd);
exit(EXIT_SUCCESS);
}
int main(int argc, char **argv) {
int sockfd;
socklen_t addrlen;
struct sockaddr_in6 dest;
int is_get = 0, hash_len;
char * server_ip;
char * server_port;
char * hash;
char * put_ip;
char buf[BUFF_MAX_LENGTH];
char string_to_send[BUFF_MAX_LENGTH] = { 0 };
char * tmp;
// vérification du nombre d'arguments
if (argc != 5 && argc != 6) {
fprintf(stderr, "usage: %s IP PORT COMMANDE HASH [IP]\n", argv[0]);
exit(EXIT_FAILURE);
}
if (!strcmp(argv[3], "get")) is_get = 1;
if (is_get && argc != 5) {
fprintf(stderr, "usage: %s IP PORT get HASH\n", argv[0]);
exit(EXIT_FAILURE);
}
// si c'est autre chose que "get" ou "put"
if (!is_get && strcmp(argv[3], "put")) {
fprintf(stderr, "COMMANDE = get | put\n");
exit(EXIT_FAILURE);
}
server_ip = argv[1];
server_port = argv[2];
hash = argv[4];
hash_len = strlen(hash);
// si c'est un put, on veut qu'une IP soit renseignée
if (!is_get && argc != 6) {
fprintf(stderr, "usage: %s IP PORT put HASH IP\n", argv[0]);
exit(EXIT_FAILURE);
}
// si c'est un put, on veut une IP (on convertit donc les ndd en IP)
if (!is_get) {
put_ip = argv[5];
char ndd_to_ip[INET6_ADDRSTRLEN] = { 0 };
if (convert_ndd_to_ip(put_ip, ndd_to_ip)) put_ip = ndd_to_ip;
if (!is_valid_ip(put_ip)) {
print_error("L'IP fournie n'est pas valide.");
print_info_str("I", "L'IP fournie est : '%s'", put_ip);
exit(EXIT_FAILURE);
}
}
if (hash_len < 65 || hash_len > HASH_MAX_LENGTH) {
fprintf(stderr, "ERR: Le hash doit avoir une longueur comprise entre 65 et %d\n", BUFF_MAX_LENGTH - 2);
exit(EXIT_FAILURE);
}
// on crée le socket
if ((sockfd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
perror("socket");
exit(EXIT_FAILURE);
}
// conversion du nom de domaine en IP
char ipstr[INET6_ADDRSTRLEN];
if (convert_ndd_to_ip(server_ip, ipstr)) server_ip = ipstr;
// on initialise la structure pour la destination
dest.sin6_family = AF_INET6;
dest.sin6_port = htons(atoi(server_port));
addrlen = sizeof(struct sockaddr_in6);
// conversion de l'adresse IP en structure compréhensible pour C
if (inet_pton(AF_INET6, server_ip, &dest.sin6_addr) != 1) {
perror("inet_pton");
close(sockfd);
exit(EXIT_FAILURE);
}
// on génère la chaîne de caratcères à envoyer
if (is_get) {
strcpy(string_to_send, "G");
tmp = strcat(string_to_send, hash);
strcpy(string_to_send, tmp);
} else {
strcpy(string_to_send, "P");
tmp = strcat(string_to_send, hash);
strcpy(string_to_send, tmp);
tmp = strcat(string_to_send, "\t");
strcpy(string_to_send, tmp);
tmp = strcat(string_to_send, put_ip);
strcpy(string_to_send, tmp);
}
// on envoie la chaîne de caractères
if (sendto(sockfd, string_to_send, strlen(string_to_send), 0, (struct sockaddr *) &dest, addrlen) == -1) {
perror("sendto");
close(sockfd);
exit(EXIT_FAILURE);
}
if (is_get) {
pthread_t tid[2];
shutdown(sockfd, SHUT_WR); // on empêche le client d'écrire dans le socket
printf("IP disponibles pour le hash %s :\n", hash);
// un timeout, si jamais le serveur ne répondrait pas
if ((errno = pthread_create(&tid[0], NULL, client_timeout, &sockfd)) != 0) {
perror("pthread_create");
exit(EXIT_FAILURE);
}
while (1) {
memset(buf, 0, BUFF_MAX_LENGTH);
if (recvfrom(sockfd, buf, BUFF_MAX_LENGTH, 0, (struct sockaddr *) &dest, &addrlen) == -1) {
perror("recvfrom");
close(sockfd);
exit(EXIT_FAILURE);
}
if (*buf == 'S') { // si le serveur nous dit qu'on peut stopper le client
// on fait attendre un peu histoire d'être sûr de tout avoir reçu
if ((errno = pthread_create(&tid[1], NULL, client_waittime, &sockfd)) != 0) {
perror("pthread_create");
exit(EXIT_FAILURE);
}
}
else printf("%s\n", buf); // on affiche l'IP reçue
}
}
// on ferme le socket
close(sockfd);
return EXIT_SUCCESS;
}