-
Notifications
You must be signed in to change notification settings - Fork 1
/
client_stub.c
683 lines (526 loc) · 21.7 KB
/
client_stub.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
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
//
// client_stub.c
// SD15-Product
//
// Created by Bruno Mata on 10/11/14.
// Copyright (c) 2014 Grupo SD015. All rights reserved.
//
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include "general_utils.h"
#include "client_stub.h"
#include "network_cliente.h"
#include "network_utils.h"
#include "client_stub.h"
#include "message.h"
#include "list-private.h"
/*
* Verifica se o opcode é do tipo Getter
*/
int opcode_is_getter (int opcode ) {
return opcode == OC_IN || opcode == OC_IN_ALL || opcode == OC_COPY || opcode == OC_COPY_ALL;
}
/*
* Assume que a msg_response é uma mensagem de sucesso para com a msg_request.
*/
int client_decision_to_take (struct message_t * msg_request, struct message_t * msg_response ) {
if ( opcode_is_getter(msg_request->opcode) && msg_response->content.result > 0 ) {
return CLIENT_RECEIVE_TUPLES;
}
return CLIENT_PROCEED;
}
/*
* Função que dada dois argumentos (keep_tuples, on_or_all) define o opcode
* retorna -1 em caso de erro
*/
int assign_opcode(int keep_tuples, int one_or_all){
int opcode = OC_DOESNT_EXIST;
if (keep_tuples == DONT_KEEP_AT_ORIGIN && one_or_all == 1){
opcode = OC_IN;
}
else if (keep_tuples == DONT_KEEP_AT_ORIGIN && one_or_all == 0){
opcode = OC_IN_ALL;
}
else if (keep_tuples == KEEP_AT_ORIGIN && one_or_all == 1){
opcode = OC_COPY;
}
else if (keep_tuples == KEEP_AT_ORIGIN && one_or_all == 0){
opcode = OC_COPY_ALL;
}
return opcode;
}
/*
* Função que dado um endereço cria uma rtable inativa (sem ligação a um servidor)
*/
struct rtable_t * rtable_create_from_address(char* server_address_and_port){
struct rtable_t *new_rtable = (struct rtable_t*) malloc(sizeof(struct rtable_t));
if ( new_rtable == NULL)
return NULL;
new_rtable->status = RTABLE_UNAVAILABLE;
new_rtable->server_address_and_port = strdup(server_address_and_port);
return new_rtable;
}
/*
* Função que dada uma estrutura server_t cria uma rtable
* retorna NULL em caso de erro
*/
struct rtable_t* rtable_create_from_server ( struct server_t *server_to_connect, char *server_address_and_port){
struct rtable_t *new_rtable = (struct rtable_t*) malloc(sizeof(struct rtable_t));
if ( new_rtable == NULL)
return NULL;
char* ip_from_server = strdup(server_to_connect->ip_address);
int port_number_from_server = server_to_connect->port;
int socketfd_from_server = server_to_connect->socketfd;
//continuar aqui
new_rtable->server_to_connect.ip_address = ip_from_server;
free(ip_from_server);
new_rtable->server_to_connect.port = port_number_from_server;
new_rtable->server_to_connect.socketfd = socketfd_from_server;
new_rtable->server_address_and_port = strdup(server_address_and_port);
new_rtable->status = RTABLE_AVAILABLE;
return new_rtable;
}
/*
* Função que dada uma estrutura rtable cria uma server_t
* retorna NULL em caso de erro
*/
struct server_t* rtable_get_server ( struct rtable_t *remote_table) {
return remote_table == NULL ? NULL : &(remote_table->server_to_connect);
}
/* Função para estabelecer uma associação com uma tabela num servidor.
* address_port é uma string no formato <hostname>:<port>.
* retorna NULL em caso de erro .
*/
struct rtable_t *rtable_bind(const char *address_port) {
if ( address_port == NULL )
return NULL;
char* address_port_copy = strdup (address_port);
struct server_t *server_to_conect = network_connect(address_port_copy);
//verificação da ligação ao servidor
if (server_to_conect == NULL){
free(address_port_copy);
return NULL;
}
//a criar uma estrutura rtable
struct rtable_t *remote_table_to_connect = rtable_create_from_server(server_to_conect, address_port_copy);
free(address_port_copy);
free(server_to_conect);
return remote_table_to_connect;
}
/* Fecha a ligação com o servidor, liberta toda a memória local.
* Retorna 0 se tudo correr bem e -1 em caso de erro.
*/
int rtable_unbind(struct rtable_t *rtable){
int task = FAILED;
//cria server_t com base em rtable
struct server_t *connected_server = rtable_get_server(rtable);
//verifica se server_t foi bem criado
if (connected_server == NULL) {
perror ("CLIENT_STUB > RTABLE_UNBIND > Unable to disconnect from server!");
return FAILED;
}
puts("--- disconnecting from server...");
//faz um network_close ao servidor
task = network_close(connected_server);
if(task == FAILED){
return FAILED;
}
puts("--- disconnected from server...");
return SUCCEEDED;
}
/* Função para adicionar um tuplo na tabela.
* Devolve 0 (ok) ou -1 (problemas).
*/
int rtable_out(struct rtable_t *rtable, struct tuple_t *tuple){
struct tuple_t *tuple_to_send = tuple;
//cria server_t com base em rtable
struct server_t *connected_server = rtable_get_server(rtable);
//cria mensagem com OC_OUT, CT_TUPLE e tuple
struct message_t *message_to_send = message_create_with(OC_OUT, CT_TUPLE, tuple_to_send);
if (message_to_send == NULL){
puts("CLIENT-STUB > RTABLE_OUT > Failed to create message to send...");
free(connected_server);
return FAILED;
}
//envia mensagem para o servidor e recebe mensagem do servidor com o resultado da operação
struct message_t *received_msg = network_send_receive(connected_server, message_to_send);
//faz verificação da mensagem recebida
if (received_msg == NULL) {
puts ("CLIENT-STUB > RTABLE_OUT > Failed to send/receive message");
return FAILED;
}
//verifica se a mensagem recebida foi de sucesso
if (response_with_success(message_to_send, received_msg) == NO){
puts("CLIENT-STUB > RTABLE_OUT > RECEIVED MESSAGE WITH ERROR OPCODE or OPCODE UNEXPECTED.");
free(message_to_send);
free(received_msg);
return FAILED;
}
return SUCCEEDED;
}
/* Função para obter tuplos da tabela.
* Em caso de erro, devolve NULL.
*/
struct tuple_t **rtable_get( struct rtable_t *rtable, struct tuple_t *template, int keep_tuples, int one_or_all ) {
int opcode = assign_opcode(keep_tuples, one_or_all);
int content_type = assign_ctype(opcode, NO );
//cria server_t com base em rtable
struct server_t *connected_server = rtable_get_server(rtable);
//cria mensagem a enviar ao servidor
struct message_t *message_to_send = message_create_with(opcode, content_type, template);
//envia mensagem para o servidor e recebe mensagem do servidor com o resultado da operação
struct message_t *received_msg = network_send_receive(connected_server, message_to_send);
//faz verificação da mensagem recebida
if (received_msg == NULL) {
if ( message_to_send)
free_message(message_to_send);
if (received_msg )
free_message(received_msg);
return NULL;
}
//onde os tuplos a receber serão guardados
struct tuple_t **received_tuples = NULL;
//verifica se a mensagem recebida foi de sucesso
if (response_with_success(message_to_send, received_msg)) {
//checks what has to do now...
if ( client_decision_to_take(message_to_send, received_msg) == CLIENT_RECEIVE_TUPLES ) {
int number_of_tuples = received_msg->content.result;
printf("--- has %d tuples to get from the server.\n", number_of_tuples);
received_tuples = (struct tuple_t**) malloc(sizeof(struct tuple_t*)*number_of_tuples);
int i;
for (i = 0; i < number_of_tuples; i++){
received_msg = receive_message(connected_server->socketfd);
received_tuples[i] = tuple_from_message(received_msg);
}
}
}
else { puts("---- NOT response_with_success !!"); }
//devolve os tuplos recebidos (ou nulo se nao recebeu nenhum tuplo)
return received_tuples;
}
/* Devolve número de elementos da tabela.
*/
int rtable_size(struct rtable_t *rtable){
int value = 0; //elem to send
int rtable_size = FAILED;
//cria server_t com base em rtable
struct server_t *connected_server = rtable_get_server(rtable);
//envia mensagem com OC_SIZE, CT_RESULT e element
struct message_t *message_to_send = message_create_with(OC_SIZE , CT_RESULT,&value);
if(message_to_send == NULL){
free(connected_server);
return FAILED;
}
puts("Sending message to server...");
//envia mensagem para o servidor e recebe mensagem do servidor com o resultado da operação
struct message_t *received_msg = network_send_receive(connected_server, message_to_send);
//faz verificação da mensagem recebida
if (received_msg == NULL) {
return FAILED;
}
//verifica se a mensagem recebida foi de sucesso
if (response_with_success(message_to_send, received_msg) == NO){
free(message_to_send);
free(received_msg);
free(connected_server);
return FAILED;
}
//coloca o tamanho da tabela na variavel rtable_size
rtable_size = received_msg->content.result;
free (message_to_send);
free (received_msg);
return rtable_size;
}
/*
* Função para enviar mensagem OC_REPORT, CT_SFAILURE, para replica a informar que switch não está definido.
* Recebe mensagem OC_REPORT, CT_Running com informação do endereço do novo switch
* Devolve 0 (ok) ou -1 (problemas).
* (Projeto 5)
*/
char * rtable_report(struct rtable_connection *rtable_connection){
//1. cria mensagem de report com endereço do switch que falhou
struct message_t * report_to_send = message_create_with(OC_REPORT, CT_SFAILURE, "give me a switch");
if (report_to_send == NULL){
puts("CLIENT-STUB > RTABLE_REPORT > Failed to create report to send...");
return NULL;
}
// puts("CLIENT-STUB > RTABLE_OUT > Sending message to server...");
puts("--- sending report to server...");
//2. envia mensagem para o servidor e recebe mensagem do servidor com o resultado da operação
struct server_t *connected_server = &(rtable_connection->rtable_replica->server_to_connect);
struct message_t *received_report = network_send_receive(connected_server, report_to_send);
printf(">>> received report with new switch address_port: %s\n", received_report->content.token);
//3. faz verificação da mensagem recebida
if (received_report == NULL) {
puts ("CLIENT-STUB > RTABLE_REPORT > Failed to send/receive report");
return NULL;
}
//4. verifica se a mensagem recebida foi de sucesso
if (response_with_success(report_to_send, received_report) == NO){
puts("CLIENT-STUB > RTABLE_REPORT > RECEIVED MESSAGE WITH ERROR OPCODE or OPCODE UNEXPECTED.");
free_message2(report_to_send,NO);
free_message(received_report);
return NULL;
}
char * report_content = strdup(received_report->content.token);
free_message2(report_to_send,NO);
free_message(received_report);
return report_content;
}
/* Função para reestabelecer uma associação com uma tabela num servidor.
* address_port é uma string no formato <hostname>:<port>.
* retorna NULL em caso de erro .
*/
struct rtable_t *rtable_rebind(struct rtable_t *rtable, char* server_address_and_port ){
int task = SUCCEEDED;
if (rtable != NULL){
task = rtable_unbind(rtable); //faz unbind da rtable corrente
}
if(task == FAILED){
return NULL;
}
struct rtable_t *new_rtable;
new_rtable = rtable_bind(server_address_and_port); //faz um novo unbind a uma "nova" rtable
if(new_rtable == NULL){
return NULL;
}
// new_rtable->retry_connection = NO;//ALTEREI AQUI
return new_rtable;
}
/*
* Função que liberta toda a memória alocada a uma estrutura rtable
* (Atualizado para Projeto 5)
*/
void rtable_destroy (struct rtable_t *rtable){
free (rtable->server_address_and_port);
free (rtable->server_to_connect.ip_address);
free (rtable);
}
/*
* Inicializa a estrutura rtable_connection
* (Projeto 5)
*/
struct rtable_connection* rtable_init (char * config_file){
//1. endereços de todos os servidores
char ** servers_ip_port = NULL;
int n_servers = get_system_rtables_info(SYSTEM_CONFIGURATION_FILE,&servers_ip_port);
if (n_servers == FAILED) {
puts("n_servers not enough");
return NULL;
}
//3. Vai criar as duas rtables iniciais:
//3.1 SWITCH
int switch_position = 0;
char* switch_address = servers_ip_port[switch_position];
struct rtable_t *rtable_switch = rtable_bind(switch_address);
if (rtable_switch == NULL) {
puts("\t--- rtable_init > rtable_switch is nulll)");
return NULL;
}
//3.2 REPLICA
char* replica_address = get_random_replica_address (servers_ip_port, n_servers, -1);
int replica_position = rtable_connection_find_address(servers_ip_port,n_servers, replica_address);
//2. Cria uma estrutura rtable_connection
struct rtable_connection* new_rtable_connection = rtable_connection_create(servers_ip_port, n_servers, switch_position, rtable_switch, replica_position, rtable_bind(replica_address) );
free(replica_address);
/* if replica or switch null any error there or before happened and returns null */
if ( new_rtable_connection->rtable_replica == NULL ||
new_rtable_connection->rtable_switch == NULL )
{
return NULL;
}
return new_rtable_connection;
}
/*
* Função que cria uma nova estrutura rtable_connection (isto é, que inicializa
* a estrutura e aloca a memória necessária).
* (Projeto 5)
*/
struct rtable_connection * rtable_connection_create(char ** servers_ip_port, int n_servers, int switch_position, struct rtable_t *rtable_switch, int replica_position, struct rtable_t * rtable_replica)
{
//allocs memory
struct rtable_connection * new_rtable_connection = (struct rtable_connection*) malloc (sizeof(struct rtable_connection));
if ( new_rtable_connection != NULL ) {
new_rtable_connection->servers_addresses_and_ports = malloc (sizeof(char*) * n_servers);
if ( new_rtable_connection->servers_addresses_and_ports == NULL ) {
rtable_connection_destroy(new_rtable_connection);
return NULL;
}
int i; for( i = 0; i < n_servers; i++)
new_rtable_connection->servers_addresses_and_ports[i] = strdup(servers_ip_port[i]);
//apenas para inicializar tudo
new_rtable_connection->switch_position = switch_position;
new_rtable_connection->rtable_switch = rtable_switch;
new_rtable_connection->replica_position = replica_position;
new_rtable_connection->rtable_replica = rtable_replica;
}
return new_rtable_connection;
}
/*
* Função que atualiza o endereço do switch e rtable_switch
* Retorna SUCCEEDED se tudo correu bem
* (Projeto 5)
*/
int rtable_assign_new_server (struct rtable_t * rtable, char * switch_address_and_port) {
//faz bind a um novo switch
rtable = rtable_bind(switch_address_and_port);
return rtable != NULL ? SUCCEEDED : FAILED;
}
/* AQUIII */
/* atualiza a posição do switch
int switch_position = rtable_connection_find_address(rtable_connection->servers_addresses_and_ports, rtable_connection->servers_addresses_and_ports, rtable_connection->total switch_address_and_port);
if (switch_position == FAILED){
return FAILED;
}*/
//rtable_connection->switch_position = switch_position;
int rtable_connection_server_rebind (struct rtable_connection * rtable_connection, int rebindSwitch ) {
return rebindSwitch ? rtable_connection_switch_rebind(rtable_connection) : rtable_connection_replica_rebind(rtable_connection);
}
/*
* Trata de todo o processo de ligação um novo switch:
* 0. faz unbind do switch atual
* 1. envia mensagem do tipo REPORT a rtable_replica
* 2. faz uma ligação ao novo switch
* (Projeto 5)
*/
int rtable_connection_switch_rebind (struct rtable_connection * rtable_connection){
int taskSuccess = FAILED;
//0. faz unbind do switch atual
taskSuccess = rtable_unbind(rtable_connection->rtable_switch);
if (taskSuccess == FAILED) {
puts("\t--- failed to unbind with current switch");
}
//1. envia mensagem do tipo REPORT
char * new_switch_address = rtable_report(rtable_connection);
if (new_switch_address == NULL) {
free(new_switch_address);
puts("\t--- failed to get new switch");
return FAILED;
}
//2. faz uma ligação ao novo switch
taskSuccess = rtable_assign_new_server(rtable_connection->rtable_switch, new_switch_address);
if (taskSuccess == FAILED) {
puts ("\t--- failed to connect to new_switch");
}
/* updates the switch position */
rtable_connection->switch_position = rtable_connection_find_address(rtable_connection->servers_addresses_and_ports, rtable_connection->total_servers , new_switch_address);
free(new_switch_address);
return taskSuccess;
}
/*
* Trata de todo o processo de ligação a uma nova replica
* 0. faz unbind da replica atual
* 1. escolhe nova replica aleatoriamente
* 2. liga-se a nova replica escolhida
* (Projeto 5)
*/
int rtable_connection_replica_rebind (struct rtable_connection * rtable_connection) {
int taskSuccess = FAILED;
//0. faz unbind do switch atual
rtable_unbind(rtable_connection->rtable_replica);
//1. envia mensagem do tipo REPORT
char * new_replica_address = get_random_replica_address(rtable_connection->servers_addresses_and_ports, rtable_connection->total_servers, rtable_connection->replica_position);
if (new_replica_address == NULL) {
free(new_replica_address);
puts ("\t--- failed to get new_switch_address");
return FAILED;
}
printf("rtable_connection_replica_rebind > new_replica_address is %s\n", new_replica_address);
//2. faz uma ligação ao novo switch
taskSuccess = rtable_assign_new_server(rtable_connection->rtable_replica, new_replica_address);
if (taskSuccess == FAILED) {
puts ("\t--- failed to connect to new replica");
}
/* updates the switch position */
rtable_connection->replica_position = rtable_connection_find_address(rtable_connection->servers_addresses_and_ports, rtable_connection->total_servers , new_replica_address);
return taskSuccess;
}
/*
* Encontra em que posição da lista de servers_addresses_and_ports se encontra determinado address_and_port_to_find
* Retorna a posição ou FAILED
* (Projeto 5)
*/
int rtable_connection_find_address (char** addresses_and_ports, int n_servers, char * address_and_port_to_find) {
int pos = 0;
for ( pos = 0; pos < n_servers; pos++ ) {
if (strcmp(addresses_and_ports[pos], address_and_port_to_find) == 0){
return pos;
}
pos++;
}
//não encontrou na lista
return FAILED;
}
/*
* Inicia o processo de disconectar de uma dada rtable_connection
* Retorna SUCCEEDED em caso de sucesso
* (Projeto 5)
*/
int rtable_disconnect (struct rtable_connection * rtable_connection){
int task = FAILED;
//desligar de switch
struct rtable_t * rtable_switch = rtable_connection_get_switch(rtable_connection);
task = rtable_unbind(rtable_switch);
free(rtable_switch);
if (task == FAILED){
puts("FAILLED TO UNBIND to SWITCH");
return task;
}
//desligar de replica
struct rtable_t * rtable_replica = rtable_connection_get_replica(rtable_connection);
task = rtable_unbind(rtable_replica);
free(rtable_replica);
if (task == FAILED){
puts("FAILLED TO UNBIND to REPLICA");
return task;
}
return task;
}
/*
* Liberta toda a memoria alocada a uma estrutura rtable_connection
* (Projeto 5)
*/
void rtable_connection_destroy (struct rtable_connection * rtable_connection){
if ( rtable_connection != NULL ) {
rtable_destroy(rtable_connection->rtable_switch);
rtable_destroy(rtable_connection->rtable_replica);
if (rtable_connection != NULL && rtable_connection->servers_addresses_and_ports != NULL){
int pos;
for (pos = 0; pos < rtable_connection->total_servers; pos++){
if (rtable_connection->servers_addresses_and_ports[pos] != NULL){
free (rtable_connection->servers_addresses_and_ports[pos]);
}
}
}
free (rtable_connection->servers_addresses_and_ports);
free (rtable_connection);
}
}
/*
* Retorna o switch de uma dada rtable_connection, NULL em caso de erro
* (Projeto 5)
*/
struct rtable_t * rtable_connection_get_switch (struct rtable_connection * rtable_connection){
return rtable_connection->rtable_switch != NULL? rtable_connection->rtable_switch:NULL;
}
/*
* Retorna o switch de uma dada rtable_connection, NULL em caso de erro
* (Projeto 5)
*/
struct rtable_t * rtable_connection_get_replica (struct rtable_connection * rtable_connection){
return rtable_connection->rtable_replica != NULL? rtable_connection->rtable_replica:NULL;
}
/*
* Random selection of a replica from a server list
* (Projeto 5)
*/
char* get_random_replica_address (char ** servers_list_address, int n_servers, int current_replica_position) {
int replica_position = current_replica_position;
//para garantir que o novo switch não é o anterior
while (replica_position == current_replica_position) {
replica_position = get_random_number(1, n_servers);
}
return servers_list_address[replica_position];
}