Estamos tratando de aplicar un protocolo basado en UDP y tenemos algún problema con la función sendto().
cuando intentamos responder a la solicitud de escritura con acuse de recibo, obtenemos un "argumento no válido" de la función sendto()
este es nuestro código:
int sock; // Socket sockaddr_in_t echoServAddr; // Local address sockaddr_in_t echoClntAddr; // Client address unsigned int cliAddrLen; // Length of incoming message data_packet_t echoBuffer; wrq_packet_t wrqBuffer; unsigned short echoServPort; // Server port int recvMsgSize; // Size of received message ack_packet_t Ack; struct timeval timeout; fd_set fds; /* Create socket for sending/receiving datagrams */ if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) perror("TTFTPERROR: socket() failed"); /* Construct local address structure */ memset(&echoServAddr, 0, sizeof(echoServAddr)); echoServAddr.sin_family = AF_INET; echoServAddr.sin_addr.s_addr = htonl(INADDR_ANY); echoServAddr.sin_port = htons(echoServPort); /*Bind to the local address */ if (bind(sock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0) perror("TTFTPERROR: bind() failed"); FD_ZERO(&fds); FD_SET(sock, &fds); timeout.tv_sec = WAIT_FOR_PACKET_TIMEOUT; timeout.tv_usec = 0; while (1) { recvMsgSize = recvfrom(sock, &wrqBuffer, FULL_PACKET_SIZE, 0, (struct sockaddr *) &echoClntAddr, &cliAddrLen); if (recvMsgSize > 0) break; // we got something! } Ack = CreateAckPacket(0); // send ack 0 if (sendto(sock, &Ack, sizeof(Ack), 0, (struct sockaddr *) &echoClntAddr, sizeof(echoClntAddr)) == -1){ perror("TTFTPERROR: sendto() failed to send ack 0"); exit(-1); }¿Podría ayudarnos a entender qué está mal?
El error probable es una combinación de la línea sendto y recvfrom unas líneas más arriba.
Lo que estás haciendo es reutilizar el sockaddr que recvfrom te dio para enviar una respuesta (ACK en este caso). Eso es absolutamente legítimo y correcto, ¿de qué otra manera podría enviar una respuesta a alguien en un protocolo sin conexión (no tiene otra forma de saber a quién enviar la respuesta, ni con qué versión de protocolo!).
Pero: mientras proporciona correctamente &cliAddrLen a recvfrom para que pueda devolver la longitud real de la dirección (que puede variar, piense en direcciones IPv4 frente a IPv6) que se escribió en el búfer echoClntAddr , luego llama a sendto con sizeof(echoClntAddr) como el tamaño de el campo de dirección.
Dado que echoClntAddr es probablemente un sockaddr_storage (de todos modos, debería serlo), su tamaño será mayor que el tamaño de la dirección de cualquier protocolo válido. Por lo tanto, es un argumento inválido. O más bien, la dirección es.
En su lugar, debe llamar a sendto con cliAddrLen (e inicializar cliAddrLen en sizeof(echoClntAddr) antes de llamar a recvfrom ).
También tenga mucho cuidado de pasar una dirección IP VÁLIDA y EXISTENTE al parámetro de bind(): echoServAddr.sin_addr.s_addr
Si no tiene una interfaz de red expuesta con esa dirección IP exacta, el enlace no fallará en algunas plataformas (ESP32, por ejemplo), PERO sendto() definitivamente fallará. ¡Pasé 2 días depurando eso y estoy enojado!