I am stuck with my UDP talker app. The goal for the moment is to initialize the server, register a client and then proceed to send something to that client. I've worked my way through Beej's network guide and coded the following library implementation:
This inizializes the server
int init_udp_server(const char *port_string){
/** Check the input data **/
if(port_string == NULL)
port_string = DEFAULT_PORT;
/** Get the information for the server **/
memset(&addrinfo_hints, 0, sizeof addrinfo_hints);
/* Use either protocol (v4, v6) */
addrinfo_hints.ai_family = AF_UNSPEC;
/* Use UDP socket type */
addrinfo_hints.ai_socktype = SOCK_DGRAM;
/* Use system IP */
addrinfo_hints.ai_flags = AI_PASSIVE;
if( (ret = getaddrinfo(NULL, port_string, &addrinfo_hints, &addrinfo_server))
!= 0 ){
printf("Server:getaddrinfo: %s\n", gai_strerror(ret));
return -1;
}
/** Loop through the list returned by getaddrinfo and get socket **/
for( addrinfo_queue = addrinfo_server; addrinfo_queue != NULL;
addrinfo_queue = addrinfo_queue->ai_next){
if((sockfd = socket(addrinfo_queue->ai_family,
addrinfo_queue->ai_socktype, addrinfo_queue->ai_protocol)) == -1){
error("Server: get socket failed");
continue;
}
if(bind(sockfd, addrinfo_queue->ai_addr, addrinfo_queue->ai_addrlen)
== -1){
close(sockfd);
error("Server: Bind to socket error");
continue;
}
break;
}
/* If we got to addrinfo_queue == NULL, we did not get a valid socket */
if(addrinfo_queue == NULL){
error("Server: Could not bind a socket");
return -1;
}
/* We do not need the addrinfo_server anymore */
freeaddrinfo(addrinfo_server);
return 0;
}
This registers the client
int udp_server_setup_client(const char *client_addr, const char *port_string, int client_nr){
/** Check the input data **/
if(port_string == NULL)
port_string = DEFAULT_PORT;
if(client_addr == NULL){
error("No valid client list");
return -1;
}
if(client_nr < 0 || client_nr > 7){
error("No valid client Nr.");
return -1;
}
memset(&addrinfo_hints, 0, sizeof addrinfo_hints);
/* Use either protocol (v4, v6) */
addrinfo_hints.ai_family = AF_UNSPEC;
/* Use UDP socket type */
addrinfo_hints.ai_socktype = SOCK_DGRAM;
/* Get the information for the client */
if( (ret = getaddrinfo( client_addr, port_string, &addrinfo_hints,
¤t)) != 0 ){
printf("Client:getaddrinfo: %s\n", gai_strerror(ret));
return -1;
}
else{
/* We read out the IP, kind of a nice check to see wheter all went fine */
char ip4[INET_ADDRSTRLEN];
struct sockaddr_in *sa = (struct sockaddr_in*) current->ai_addr;
inet_ntop(AF_INET, &(sa->sin_addr),ip4, INET_ADDRSTRLEN);
printf("Clients address: %s\n",ip4);
addrinfo_clients[client_nr] = current;
}
return 0;
}
And finally this is for writing
int udp_server_write(const char *buffer, int buffer_size, int client_nr){
/* Sanity check of the input */
if(client_nr > (MAX_NR_CLIENTS - 1) || client_nr < 0){
error("Not a valid client");
return -1;
}
if(buffer == NULL){
error("Not a valid buffer address");
return -1;
}
/* Just so we type less */
current = addrinfo_clients[client_nr];
socklen = sizeof current->ai_addr;
if((ret = sendto(sockfd, (void*)buffer, buffer_size, 0,
(sockaddr*)current->ai_addr, socklen)) == -1){
printf("Failed to send message to client %i\n", client_nr);
printf("Error Code: %s\n",gai_strerror(ret));
return -1;
}
else if(ret < buffer_size){
printf("Wrote only %i of %i bytes\n", ret, buffer_size);
return -1;
}
return ret;
}
I call the functions like this
init_udp_server("3334");
udp_server_setup_client("192.168.1.5", "3334", 0);
udp_server_write(send_buf, 256, 0);
As soon as sendto() is called I get an error: Failed to send message to client 0 Error Code: Bad value for ai_flags I checked it with gdb and found that the addrinfo struct is filled correctly, and the address of the client is valid. Any one an idea where to look? I am running out of ideas...
thanks, wenzlern
When calling sendto()
, the last parameter is being set to sizeof current->ai_addr
, which is wrong. current->ai_addr
is defined as a sockaddr*
pointer, so sizeof current->ai_addr
will always return 4 on a 32-bit system and 8 on a 64-bit system. It just happens that IPv4 addresses are 4 bytes in size, so sizeof current->ai_addr
will only work for IPv4 addresses on 32-bit systems, but will always fail for IPv6 addresses on 32-bit systems and all addresses on 64-bit systems. You need to use current->ai_addrlen
instead of sizeof
.
Also, passing -1 to gai_strerror()
is not valid. It expects you to pass in a real error code, such as the return value of getaddrinfo()
and getnameinfo()
. sendto()
does not return an actual error code. When it fails, you have to use WSAGetLastError()
on Windows or errno
on other systems to get the actual error code.
Try this:
if ((ret = sendto(sockfd, (char*)buffer, buffer_size, 0, (sockaddr*)current->ai_addr, current->ai_addrlen)) == -1)
{
#ifdef _WIN32
ret = WSAGetLastError();
#else
ret = errno;
#endif
printf("Failed to send message to client %i\n", client_nr);
printf("Error Code: (%d) %s\n", ret, gai_strerror(ret));
return -1;
}