I have an odd problem with a UDP server I’m working on. The very first udp packet received has no information on the source of the packet. Subsequent udp packets all appear to be fine and correctly display the ip address from which the packet was received. I have no clue what is causing this behavior, probably some stupid mistake, or some obscure bug. I’m using on a Linux machine running Debian.
fd_set master;
fd_set read_fds;
int fdmax;
int i;
int bytes_sent;
int bytes_recv;
socklen_t addr_len;
struct sockaddr_storage their_addr;
// provides users information needed to connect
serv_info *server_info;
server_info = (serv_info*) serv_config;
// Create UDP listener socket
int info_sock = createDGRAMSocket(NULL, server_info->port, 1);
char buffer[1024];
int len;
int send_response;
FD_SET(info_sock, &master);
fdmax = info_sock;
bytes_recv = recvfrom(i, buffer, sizeof(buffer), 0, (struct sockaddr *)&their_addr, &addr_len);
printf("Info started \n");
while (running) {
read_fds = master;
select(fdmax+1, &read_fds, NULL, NULL, NULL);
for (i = 0; i <= fdmax; i++) {
if (FD_ISSET(i, &read_fds)) {
bytes_recv = recvfrom(i, buffer, sizeof(buffer), 0, (struct sockaddr *)&their_addr, &addr_len);
printf("length %u: %s\n", bytes_recv, buffer);
send_response = 0;
switch (buffer[0]) {
// Handle different packet types
}
struct sockaddr_in *sin = (struct sockaddr_in *)&their_addr;
unsigned char *ip = (unsigned char *)&sin->sin_addr.s_addr;
printf("IP: %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]);
if (send_response) {
bytes_sent = sendto(info_sock, buffer, len, 0, (struct sockaddr *)&their_addr, sizeof(struct sockaddr_storage));
if (bytes_sent < 0) {
printf("[ERROR] Packet Send Failed %d (%s) %d\n", bytes_sent, buffer, len);
}
}
}
}
};
close(info_sock);
You need to initialize
addr_lentosizeof(their_addr). According to the man page:Since you aren’t initializing
addr_lenit seems to be taking on a value of 0 (this is highly undefined behavior). In this case,recvfrom()will not fill in thetheir_addrbuffer, but as the man page indicatesaddr_lenwill return a value greater than was supplied to the call. So after the first calladdr_lenis taking on a value that is allowing the next calls torecvfrom()to properly fill in thetheir_addrbuffer. Relying on this is unsafe though.