Closed GabrielBorre closed 5 months ago
Buenas! Cómo va?
Si te fijas en la última captura lo que te explota es que no le esta llegando un t_log *
válido a la función isEnableLevelInLogger()
, de hecho le llega la dirección 0x2
que no es una dirección de tu proceso ni de onda, fijate de utilizando el debugger, pararte justo antes de llamar a cualquier función de log_
a ver si le estas pasando bien la referencia.
Saludos.-
Buen día Damián! Muchas gracias por tu respuesta! Intentaremos solucionarlo por donde nos decís. Saludos y buen Domingo.
Hola Damián! Soy del mismo grupo que Gabriel. Te comento nuestras sospechas.
De la pila de funciones que te mandamos, hasta que se llama a int servidor(const char *puerto, t_log *logger)
y antes de entrar a la función list_iterate(lista, (void*) iterator)
está todo bien, las variables son estas:
El problema es que cuando entra en esa función, pierde el linkeo del logger. Nosotros sí modificamos los parámetros de iterator
justamente para que le llegue el logger que nosotros queríamos, puesto que cada servidor tendría su propio logger (entonces, debería ser pasado por parámetro de mano en mano), quedando iterator
de la siguiente manera:
void iterator(char* value, t_log *logger) {
log_info(logger,"%s", value);
}
Siguiendo con nuestra sospecha, list_iterate(lista, (void*) iterator)
llama únicamente a la firma de la función y pierde el parámetro logger. No te voy a mentir que no entendemos mucho qué hace list_iterate
según su código, sí según su nombre.
void list_iterate(t_list* self, void(*closure)(void*)) {
t_link_element **indirect = &self->head;
while ((*indirect) != NULL) {
closure((*indirect)->data);
indirect = &(*indirect)->next;
}
}
Vemos que list_iterate
recibe una lista y ¿una función anónima que recibe cualquier parámetro? A partir de acá, las variables quedan así:
Y como vemos, se desvinculó el logger. ¿Qué podríamos hacer para que cada servidor tenga su propio logger y no tengamos que hacer un pasamanos sin modificar las funciones que ya nos dan? ¿o deberíamos modificarlas de alguna forma en específico?
Muchas gracias, espero que esto sirva para ayudanos a resolver el problema. Buen domingo a todos!!
Buenas! Cómo va?
Justamente lo que mencionas de list_iterate()
es donde le pifiaron al análisis, lo que hace en la línea closure((*indirect)->data);
es pasarle el contenido de la lista, es decir, lo que uds tienen que recibe 2 parametros, solo les manda el primero y el segundo bueno... como diría un español a tomar por saco.
Este problema de no poder tener 2 parámetros en la función que se aplica a cada elemento de la lista en list_iterate()
se resuelve de 2 maneras más o menos "simples"
Manera 1: Arman un elemento de la lista más complejo que tenga más cosas. Esto lo pueden ver en los unit tests de las listas donde el list_iterate()
opera sobre un t_person *
, en lugar de un char *
.
Manera 2: Tienen una variable global con el valor que necesitan, que en su caso siendo que es un logger, es un poco la salida más fácil, teniendo en cuenta que ese logger lo van a llamar de muchos lados, capaz es más fácil tener una variable global y que desde cualquier lado le puedan pegar.
Saludos.-
¡Buenas! Solo me sumo para agregar una manera 3: usar nested functions
Entonces pueden armar una función que reciba una lista y un logger, y que adentro de ella se llame a list_iterate
pasándole como parámetro una nested function.
Saludos
Buenas Damián y Agus! Estuvimos barajando las opciones:
De la manera 1 sentimos que sumamos mucha complejidad al código, y que nos vamos a complicar mucho 😩.
De la manera 2, si bien es mucho más factible, tenemos abstraída la lógica del servidor en un archivo utils/src/server.c
, llamando a la función servidor(puerto_propio, logger)
(está en utils/src/server.c
) desde el main
de memoria. Por esto, dedujimos que una variable global tampoco nos serviría porque al toque cambiamos de archivo, y definirla como extern
haría o que tengamos un sólo logger o que tengamos que definir las funciones 3 o 4 veces para cada módulo, y para eso podemos hacerlo directamente teniendo la lógica del servidor en cada archivo.
La manera 3 nos pareció interesante puesto que quizás también nos servía en futuras ocasiones, pero creo que no la estamos implementando del todo bien ya que nos tira segmentation fault en una funcion de las commons de strings void _string_append_with_format_list(const char* format, char** original, va_list arguments)
... (un dolor de cabeza todo). Adjunto código de cómo lo implementamos (con nombres genéricos porque era para probar):
En utils/src/server.c
:
void iterator(char* value, t_log *logger) {
log_info(logger,"%s", value);
}
int servidor(const char *puerto, t_log *logger) {
int server_fd = iniciar_servidor(puerto, logger);
log_info(logger, "Servidor listo para recibir al cliente");
int cliente_fd = esperar_cliente(server_fd, logger);
t_list* lista;
while (1) {
int cod_op = recibir_operacion(cliente_fd);
switch (cod_op) {
//...
case PAQUETE:
lista = recibir_paquete(cliente_fd);
log_info(logger, "Me llegaron los siguientes valores:\n");
**funcion(lista, logger);**
break;
//...
}
void funcion(t_list *lista, t_log *logger) {
char* value;
void _funcion_adaptadora(t_list *lista) {
iterator(value, logger);
}
list_iterate(lista, (void*) _funcion_adaptadora);
}
Los parámetros de list_iterate
y de iterator
, después de la definición _funcion_adaptadora
, no se pintan 😩, así que ahí está el primer parámetro de que no funciona (y el más importante obvio!! jajaj). Lo segundo (y mucho menos importante (nótese el sarcasmo)) es la exceción de segmentation fault:
Ya decidimos que si esto no mejora, vamos a destruir la abstracción y bueno, se repetirá lógica pero al menos va a funcionar (elegimos creer).
Muchas gracias 💙
Holi! Justo en la funcion
están ocurriendo un par de cosas:
void funcion(t_list *lista, t_log *logger) {
char* value; // (1)
void _funcion_adaptadora(t_list *lista) { // (3)
iterator(value, logger); // (2)
}
list_iterate(lista, (void*) _funcion_adaptadora);
}
value
que declararon ahí está sin inicializariterator
, con lo cual de ahí seguramente venga el segfault._funcion_adaptadora
, no es la lista en sí, sino cada elemento de la misma. O sea, de ahí vendría el char* value
que esperan pasarle a iterator
:)Buenas a todos! Soy tambien parte del grupo. Logre que el servidor y el cliente se conecten con la solucion que plantearon de nested function, dejo constancia de lo que hice por si quieren corregir o por si a alguien le llega a servir. Construi la funcion de la siguiente manera para que funcione (valga la redundancia jaja)
void funcion(t_list *lista, t_log *logger){
void _iterator(char *value){
log_info(logger,"%s", value);
}
list_iterate(lista,(void*) _iterator);
}
y dentro de la funcion principal queda asi:
int servidor(const char *puerto, t_log *logger) {
int server_fd = iniciar_servidor(puerto, logger);
log_info(logger, "Servidor listo para recibir al cliente");
int cliente_fd = esperar_cliente(server_fd, logger);
t_list* lista;
while (1) {
int cod_op = recibir_operacion(cliente_fd);
switch (cod_op) {
case MENSAJE:
recibir_mensaje(cliente_fd, logger);
break;
case PAQUETE:
lista = recibir_paquete(cliente_fd);
log_info(logger, "Me llegaron los siguientes valores:\n");
funcion(lista,logger);
break;
case -1:
log_error(logger, "El cliente se desconectó. Terminando servidor");
return EXIT_FAILURE;
default:
log_warning(logger,"Operacion desconocida");
break;
}
}
return EXIT_SUCCESS;
}
muchas gracias a todos, me sirvio un montonazo el video de ejemplo jajaja saludos!
Muchísimas gracias Damián y Agus por la gran ayuda!
Cierro el issue.
Saludos y buena semana!
🐛 Cómo reproducir el error
💻 Logs