-
Notifications
You must be signed in to change notification settings - Fork 0
/
cliente.c
256 lines (222 loc) · 8.68 KB
/
cliente.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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
/**
* Este archivo contiene la implementación del programa cliente, que operaría
* las puertas del estacionamiento. El formato de mensaje y las constantes de
* configuración estan en otros header.
*
* @author Alfredo Fanghella, 12-10967
* @author Georvic Tur, 12-11402
* @see mensajes.h
* @see configuracion.h
*/
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <time.h>
#include "configuracion.h"
#include "mensajes.h"
/**
* Rutina principal del proceso cliente.
*
* @param argc Número de argumentos
* @param argv Debe contener puerto, acción, ID del carro y nombre de dominio o IP
*/
int main(int argc, char **argv){
char uso_correcto[] ="sem_cli -d <dirección IP o nombre de dominio>\n\t\
-p <puerto>\n\t\
-c <acción>\n\t\
-i <identificador de vehículo>\n";
if (argc != 9){
fprintf(stderr,"Número incorrecto de argumentos.\nUso correcto:\n");
fprintf(stderr, uso_correcto);
exit(EXIT_FAILURE);
}
//Argumentos del cliente
char *direccion = NULL; //Nombre de dominio o IP
char *puerto = NULL; //Número de Puerto
unsigned long identificador;
mensaje_c msj; // mensaje que se enviará al servidor
mensaje_s structRespuesta;
int opcn; //Se parsean los argumentos del cliente
//optarg es una variable global con un apuntador al argumento actual
// Variables para el chequeo de la entrada
char * err;
long numPuerto;
bool flag_i, flag_d, flag_p, flag_c;
flag_i = flag_d = flag_p = flag_c = false;
while ((opcn = getopt(argc,argv, "d:p:c:i:")) != -1){
switch(opcn){
case 'd':
direccion = optarg;
flag_d = true;
break;
case 'p':
numPuerto = strtol(optarg, &err, 10);
if ((*err != '\0') || (numPuerto < 1) || (numPuerto > MAX_PUERTO)) {
fprintf(stderr, "El puerto no es válido\n");
exit(EXIT_FAILURE);
}
puerto = optarg;
flag_p = true;
break;
case 'c':
if ((strlen(optarg) != 1) || ((*optarg != 'e') && (*optarg != 's'))){
fprintf(stderr,"Tipo de acción equivocada. Debe ser 'e' para entrada o 's' para salida\n");
exit(EXIT_FAILURE);
}
msj.accion = *optarg;
flag_c = true;
break;
case 'i':
if (optarg[0] == '-'){
fprintf(stderr,"El identificador debe ser un número positivo.\n");
exit(EXIT_FAILURE);
}
errno = 0;
identificador = strtoul(optarg, &err, 10);
if (*err!= '\0') {
fprintf(stderr,"El número de identificación no es válido.\n");
exit(EXIT_FAILURE);
} else if ((errno == ERANGE) || (identificador > UINT32_MAX)){
fprintf(stderr,"El número de identificación es demasiado grande.\n");
exit(EXIT_FAILURE);
}
msj.ident = htonl(identificador);
flag_i = true;
break;
default:
fprintf(stderr,"Formato de argumentos incorrecto.\nUso correcto:\n");
fprintf(stderr, uso_correcto);
exit(EXIT_FAILURE);
}
}
if (!(flag_d && flag_c && flag_i && flag_p)) {
fprintf(stderr,"Formato de argumentos incorrecto.\nUso correcto:\n");
fprintf(stderr, uso_correcto);
}
//El tipo de socket a usar (UDP)
struct addrinfo infoDir;
memset(&infoDir, 0, sizeof(infoDir));
infoDir.ai_family = AF_UNSPEC;
infoDir.ai_socktype = SOCK_DGRAM;
infoDir.ai_protocol = IPPROTO_UDP;
//Configuracion del socket
struct addrinfo *dirServ;
int codigoErr;
if ((codigoErr=getaddrinfo(direccion, puerto, &infoDir, &dirServ)) != 0){
fprintf(stderr," Problema al obtener información sobre el servidor.\n");
gai_strerror(codigoErr);
exit(EXIT_FAILURE);
}
//Creación del socket
int socketCltSrvdr = socket(dirServ->ai_family, dirServ->ai_socktype, dirServ->ai_protocol);
if (socketCltSrvdr == -1){
fprintf(stderr," Problema al crear el socket.\n");
exit(EXIT_FAILURE);
}
//Estructura para establecer el timeout de la espera por la respuesta
//del servidor.
struct timeval tiempoEsperaMax;
tiempoEsperaMax.tv_sec = TIEMPO_MAX_SEG;
tiempoEsperaMax.tv_usec = TIEMPO_MAX_USEG;
//Se configura el socket para esperar un tiempo máximo al recibir
if (setsockopt(socketCltSrvdr,
SOL_SOCKET,
SO_RCVTIMEO,
&tiempoEsperaMax,
sizeof(tiempoEsperaMax)))
{
fprintf(stderr," Problema al establecer tiempo máximo de espera\n");
exit(EXIT_FAILURE);
}
ssize_t numBytesEnviados=-1;
struct sockaddr_storage dirOrigenServ;
socklen_t tamanoSocket = sizeof(dirOrigenServ);
ssize_t numBytesRecibidos = 0;
int i=0;
//No se necesita
//msj.ack=0;
int identificadorRcbd=-1;
//Se repite hasta que se envíe y reciba la info o se agoten los intentos.
while((i < NUM_INTENTOS) &&
((numBytesEnviados==-1) || (numBytesRecibidos < 0) ||
(identificadorRcbd != identificador)))
{
//La identidad del cliente también ha de estar en el mensaje de respuesta del server
numBytesEnviados = sendto(
socketCltSrvdr,
&msj,
sizeof msj - sizeof msj.pad,
0,
dirServ->ai_addr,
dirServ->ai_addrlen);
numBytesRecibidos = recvfrom(
socketCltSrvdr, &structRespuesta,
sizeof structRespuesta - sizeof structRespuesta.pad, 0,
(struct sockaddr *) &dirOrigenServ,
&tamanoSocket);
i++;
identificadorRcbd = ntohl(structRespuesta.ident);
}
if (!socketCltSrvdr){
fprintf(stderr,"Problema al enviar información.\n");
}
if (numBytesRecibidos == -1){
fprintf(stderr,"No se recibió ningún mensaje.\n");
}
if (identificadorRcbd != identificador){
fprintf(stderr, "No se recibió un mensaje correspondiente al cliente.\n");
exit(EXIT_FAILURE);
}
if (i==NUM_INTENTOS){
fprintf(stderr,"Tiempo de respuesta agotado.\n");
exit(EXIT_FAILURE);
}
char permiso = structRespuesta.accion;
int dia = (int) (structRespuesta.dia);
int mes = (int) (structRespuesta.mes);
int anyo = ((int) (structRespuesta.anyo))-100+2000;
int hora = (int) (structRespuesta.hora);
int minuto = (int) (structRespuesta.minuto);
int precio = (int) ntohl(structRespuesta.precio);
if ((msj.accion == 'e') && (permiso == 's')){
printf("Puede Pasar\n");
printf("-----------Ticket---------\n");
printf("ID: %d\n", identificadorRcbd);
printf("Hora: %d:%d\n", hora, minuto);
printf("Fecha: %d/%d/%d\n", dia,mes,anyo);
printf("---------------------------\n");
} else if ((msj.accion == 'e') && (permiso == 'n')){
printf("En este momento no hay puestos\n");
} else if ((msj.accion == 's') && (permiso == 's')){
printf("---------------------------------\n");
printf("ID: %d\n", identificadorRcbd);
printf("Debe cancelar: Bs. %d\n", precio);
printf("---------------------------------\n");
} else if ((msj.accion == 's') && (permiso == 'n')){ // En caso de que se
printf("<<<<<<<<Factura Reenviada>>>>>>>>\n"); //use la retransmisión
printf("---------------------------------\n");
printf("ID: %d\n", identificadorRcbd);
printf("Debe cancelar: Bs. %d\n", precio);
printf("---------------------------------\n");
} else if ((msj.accion == 'e') && (permiso == 'f')){
printf("<<<<<<<Ticket Reenviado>>>>>>>\n");
printf("Puede Pasar\n");
printf("-----------Ticket----------\n");
printf("ID: %d\n", identificadorRcbd);
printf("Hora: %d:%d\n", hora, minuto);
printf("Fecha: %d/%d/%d\n", dia,mes,anyo);
printf("---------------------------\n");
} else if ((msj.accion == 's') && (permiso == 'v')){
printf("<<<<Este ticket no es válido>>>>\n<<<<El vehículo no se encuentra>>>>\n");
}
freeaddrinfo(dirServ);
close(socketCltSrvdr);
return 0;
}