As Barmar points out, one reason for the EINVAL
is the incorrect:
sizeof(struct sockaddr *)
which gives the size of a pointer. See Socket programming: sendto always fails with errno 22 (EINVAL).
The second reason seems to be sin_port
, which getaddrinfo
returns as 0
. Changing it to 80
say clears up the EINVAL
, as in:
((struct sockaddr_in *)ret->ai_addr)->sin_port = htons(80); // test
Here port 80 here is not HTTP, but instead (for UDP) is Google's experimental QUIC Chromium.
Wikipedia http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers states that Port 0 is for UDP reserved, and for TCP is unofficially reserved as a "programming technique for specifying system-allocated (dynamic) ports".
And as an aside (and referring to the original question), you may not need bother with the variable ip
. You are casting ret->ai_addr
to struct sockaddr_in *
, and then back again to its original type.
And, as Remy Lebeau points out, it is better to use the service
parameter of getaddrinfo
. So putting this all together, your code could look more like:
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET; //IPv4
hints.ai_socktype = SOCK_DGRAM; //UDP packets
if ((status = getaddrinfo(argv[1], "80", &hints, &ret)) != 0) {
printf("getaddrinfo: %s\n", gai_strerror(status));
return -1;
}
assert(ret->ai_family == AF_INET); // guaranteed
assert(ret->ai_socktype == SOCK_DGRAM); // guaranteed
assert(((struct sockaddr_in *)ret->ai_addr)->sin_port == htons(80)); // guaranteed
// ...
if ((sendto(sock, msg, strlen(msg), 0, ret->ai_addr, ret->ai_addrlen)) != -1) {
// ...