Sockets sendto() returning EINVAL - c

I'm trying to send a UDP packet in C. I have the following sendto():
char* msg = "Hello";
//ret is the return value of getaddrinfo, the address is AF_INET (IPv4)
//and the sock_type is SOCK_DGRAM (UDP)
struct sockaddr_in *ip = (struct sockaddr_in *)ret->ai_addr;
if ((sendto(sock, msg, strlen(msg), 0, (struct sockaddr *)ip,
sizeof(struct sockaddr *))) != -1) {
printf("msg sent successfully");
} else {
printf("Error sending msg: %s\n", strerror(errno));
}
However, it's returning an error saying there's an invalid argument. Looking at the manpage I can't really tell which one is the invalid argument. Any ideas?
EDIT: Here's all my code
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <errno.h>
int main(int argc, const char *argv[])
{
/*
* Help the technically challenged among us who have no idea
* what on God's green Earth they are doing with this thing.
*/
if (argc != 2) {
printf("usage: routetracer <ip address or hostname>\n");
return -1;
}
/*
* hints- parameters for return value of getaddrinfo
* ret- return value of getaddrinfo
*/
struct addrinfo hints, *ret;
int status;
char ipv4[INET_ADDRSTRLEN];
int ttl = 0;
char* msg = "Hello";
int last_hop = 0;
//define what we want from getaddrinfo
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET; //IPv4
hints.ai_socktype = SOCK_DGRAM; //UDP packets
//call getaddrinfo to fill ret, w/ error chk
if ((status = getaddrinfo(argv[1], NULL, &hints, &ret)) != 0) {
printf("getaddrinfo: %s\n", gai_strerror(status));
return -1;
}
//extract IPv4 address from ret
struct sockaddr_in* ip = (struct sockaddr_in *)ret->ai_addr;
//convert address from pure numbers to something easier to read
inet_ntop(ret->ai_family, &(ip->sin_addr), ipv4, INET_ADDRSTRLEN);
//kindly inform the user of which hostname they are connecting to
printf("Route for: %s\n", ipv4);
//create a socket
int sock = socket(ret->ai_family, ret->ai_socktype, ret->ai_protocol);
ttl = 1;
if ((setsockopt(sock, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl))) != -1) {
printf("TTL set successfully\n");
} else {
printf("Error setting TTL: %s\n", strerror(errno));
}
if ((sendto(sock, msg, strlen(msg), 0, ret->ai_addr,
ret->ai_addrlen)) != -1) {
printf("msg sent successfully");
} else {
printf("Error sending msg: %s\n", strerror(errno));
}
return 0;
}
Running the program gives the following output:
$ ./routetracer www.google.com
Route for: 173.194.46.82
TTL set successfully
Error sending msg: Invalid argument

Try:
if ((sendto(sock, msg, strlen(msg), 0, (struct sockaddr *)ip,
sizeof(struct sockaddr_in))) != -1) {
You're giving it the size of a pointer, not the size of the structure. And it needs to be the specific structure type, not the generic type.

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) {
// ...

Related

getaddrinfo linux manpage server example but using TCP instead of UDP

I'm trying to convert the server program example from getaddrinfo's linux manpage from UDP to TCP.
When running the program without any change first, I can communicate with a netcat client using UDP :
gcc main.c
./a.out 1234
netcat -u 127.0.0.1 1234
// this works here, I can send messages to the server
Then if I try with TCP :
netcat 127.0.0.1 1234
^ this doesn´t connect and exists directly
I tried to change some attributes in the addrinfo struct :
hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
hints.ai_socktype = SOCK_STREAM; /* Stream socket */
hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */
And it doesn´t connect either.
Here is the whole code :
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netdb.h>
#define BUF_SIZE 500
int
main(int argc, char *argv[])
{
struct addrinfo hints;
struct addrinfo *result, *rp;
int sfd, s;
struct sockaddr_storage peer_addr;
socklen_t peer_addr_len;
ssize_t nread;
char buf[BUF_SIZE];
if (argc != 2) {
fprintf(stderr, "Usage: %s port\n", argv[0]);
exit(EXIT_FAILURE);
}
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
hints.ai_socktype = SOCK_STREAM; /* Stream socket */
hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */
hints.ai_protocol = 0; /* Any protocol */
hints.ai_canonname = NULL;
hints.ai_addr = NULL;
hints.ai_next = NULL;
s = getaddrinfo(NULL, argv[1], &hints, &result);
if (s != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
/* getaddrinfo() returns a list of address structures.
Try each address until we successfully bind(2).
If socket(2) (or bind(2)) fails, we (close the socket
and) try the next address. */
for (rp = result; rp != NULL; rp = rp->ai_next) {
sfd = socket(rp->ai_family, rp->ai_socktype,
rp->ai_protocol);
if (sfd == -1)
continue;
if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0)
break; /* Success */
close(sfd);
}
freeaddrinfo(result); /* No longer needed */
if (rp == NULL) { /* No address succeeded */
fprintf(stderr, "Could not bind\n");
exit(EXIT_FAILURE);
}
/* Read datagrams and echo them back to sender */
for (;;) {
peer_addr_len = sizeof(peer_addr);
nread = recvfrom(sfd, buf, BUF_SIZE, 0,
(struct sockaddr *) &peer_addr, &peer_addr_len);
if (nread == -1)
continue; /* Ignore failed request */
char host[NI_MAXHOST], service[NI_MAXSERV];
s = getnameinfo((struct sockaddr *) &peer_addr,
peer_addr_len, host, NI_MAXHOST,
service, NI_MAXSERV, NI_NUMERICSERV);
if (s == 0)
printf("Received %zd bytes from %s:%s\n",
nread, host, service);
else
fprintf(stderr, "getnameinfo: %s\n", gai_strerror(s));
if (sendto(sfd, buf, nread, 0,
(struct sockaddr *) &peer_addr,
peer_addr_len) != nread)
fprintf(stderr, "Error sending response\n");
}
}
How to make this server program accept TCP connections with netcat ?

Address family not supported by protocol UDP C Error sending

I'm trying to implement communication by UDP protocol, and I'm getting an error: "Error sending: Address family not supported by protocol". I've checked in Google for this problem but couldn't managed to find answer.
Please be patient, I'm only starting my adventure with coding in C.
Here is a C code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#define BUFLEN 512
// define function that deals with errors
void error(const char *msg)
{
perror(msg); // print error msg
exit(1); // exit the main() function
}
int main(int argc, char *argv[])
{
struct sockaddr_in serv1_addr, serv2_addr, cli1_addr, cli2_addr; //definicja struktur adresów servera i clienta
struct hostent *server; //defines host addres struct
int cl1_sockfd, se1_sockfd, se2_sockfd, i, c1len = sizeof(cli1_addr), c2len = sizeof(cli2_addr), recv_len, portno1,portno2; // creates inits
int cli1_len = sizeof(cli1_addr);
int cli2_len = sizeof(cli2_addr);
char buf[BUFLEN];
if (argc < 4) {
fprintf(stderr,"ERROR, no port provided\n"); // deal with wrong port
exit(1);
}
//tworzenie soceketu servera
if ((se1_sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1){
error("socket1"); //if socket() return -1 -- error
}
if ((se2_sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1){
error("socket2"); //if socket() return -1 -- error
}
//zero out the structure
memset( &serv1_addr, 0, sizeof(serv1_addr)); //put zero into structure
memset( &serv2_addr, 0, sizeof(serv2_addr)); //put zero into structure
portno1 = atoi(argv[2]); // get port number
portno2 = atoi(argv[3]);
serv1_addr.sin_family = AF_INET; // specify address family (IPv4)
serv1_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
serv1_addr.sin_port = htons(portno1); // set port number
serv2_addr.sin_family = AF_INET; // specify address family (IPv4)
serv2_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
serv2_addr.sin_port = htons(portno2); // set port number
if(connect(se1_sockfd,(struct sockaddr *) &serv1_addr, sizeof(serv1_addr)) < 0)
error ("ERROR connecting1"); //if connection failed
if(connect(se2_sockfd,(struct sockaddr *) &serv2_addr, sizeof(serv2_addr)) < 0)
error ("ERROR connecting2"); //if connection failed
while(1) //inf loop
{
printf("Please enter the message: "); //write the msg to socket
bzero(buf, 512); //fill buffer with zeros
fgets(buf, 512, stdin); //read into buffer
if( sendto( se1_sockfd, buf, BUFLEN, 0, (struct sockaddr*) &cli1_addr, cli1_len) < 0)
error ("Error sending1");
if( sendto( se2_sockfd, buf, BUFLEN, 0, (struct sockaddr*) &cli2_addr, cli2_len) < 0)
error ("Error sending2");
if (recvfrom(se1_sockfd, buf, BUFLEN, 0, (struct sockaddr *) &cli1_addr, &cli1_len) == -1){
error("recivfrom()1"); //if reciving failed -- error
}
printf("Data: %s\n", buf);
if (recvfrom(se2_sockfd, buf, BUFLEN, 0, (struct sockaddr *) &cli2_addr, &cli2_len) == -1){
error("recivfrom()2"); //if reciving failed -- error
}
printf("Data: %s\n", buf);
}
close(se1_sockfd);
close(se2_sockfd);
return 0;
}
Thanks for your help. ;)
Your issue is likely because of uninitialized destination address. sendto() takes destination address as the one before the last argument. But you are trying to provide not-initialized address (like for recvfrom())
if( sendto( se1_sockfd, buf, BUFLEN, 0, (struct sockaddr*) &cli1_addr, cli1_len) < 0)
error ("Error sending1");
^^^
Try serv1_addr instead ?
Also need to provide appropriate size.
One more thing. As long as you use sendto() - no need to perform connect(). UDP is connectionless and connect() only establishes default destination address for those who is going to use send() on such socket. But this is not your case because you provide destination address each time you call sendto(). Even more - you may use different addresses each time.
P.S. Reference: sendto()

C socket programming: Invalid argument error on connect()

I'm writing a client side as part of a TCP client server program.
My code reaches the connect part and throws an Invalid argument error, I have gone through the code several times and I couldn't find the problem.
The code receives 3 arguments, first one is an IP address or a hostname, second one is port and the third is the maximum length of the message to be sent.
My code uses getaddrinfo in order to convert the ip address or hostname, creates the needed variables, starts a connection, read from file, send data and receive data.
I run the code with:
gcc -std=gnu99 -O3 -Wall -o pcc_client pcc_client.c
./pcc_client 127.0.0.1 2233 4
The output is:
sockaddr_in initialized
Error starting connection : Invalid argument
#include <stdlib.h>
#include <stdio.h>
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <dirent.h>
#define FILE_ADDR "/dev/urandom"
int main(int argc, char *argv[]) {
if (argc != 4) {
printf("should receive 3 arguments Received %d args\n", argc);
exit(1);
}
//Get command line arguments
unsigned int port = atoi(argv[2]);
int length = atoi(argv[3]); //Number of bytes to read
char* buffer = malloc(length * sizeof(char)); //Buffer to hold data read from file
char* recvBuf = malloc(10 * sizeof(char)); // Buffer to hold response from server
struct addrinfo hints, *servinfo, *p;
struct sockaddr_in *serv_addr;
int rv;
char ip[100];
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
if ((rv = getaddrinfo(argv[1], argv[2], &hints, &servinfo)) != 0) {
perror("getaddrinfo error\n");
return 1;
}
for (p = servinfo; p != NULL; p = p->ai_next) {
serv_addr = (struct sockaddr_in *) p->ai_addr;
strcpy(ip, inet_ntoa(serv_addr->sin_addr));
}
// inet_aton(ip, &h.sin_addr);
freeaddrinfo(servinfo);
//Initialize socket
int sockfd;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) //Error creating socket
{
perror("Error creating socket \n");
exit(1);
}
printf("socket created\n");
//Initialize sockaddr_in structure
memset((void*)serv_addr, 0,(size_t) sizeof(*serv_addr));
serv_addr->sin_family = AF_INET;
serv_addr->sin_port = htons(port);
serv_addr->sin_addr.s_addr = inet_addr("127.0.0.1"); //change?
//Initialize connection
if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { //Error connecting
perror("Error starting connection \n");
exit(1);
}
printf("connect succesful\n");
exit(0);
}
You are using serv_addr all wrong.
You have declared serv_addr as a sockaddr_in* pointer. After getaddrinfo() exits successfully, you are looping through the output list, assigning serv_addr to point at every ai_addr in the list, and then you free the list, leaving serv_addr pointing at invalid memory. You then trash memory when you try to populate serv_addr with data. And then you end up not even passing a valid pointer to a sockaddr_in to connect() at all, you are actually passing a pointer to a pointer to a sockaddr_in, which is why it complains about an "invalid argument".
In fact, you are going about this situation all wrong in general. When using getaddrinfo(), since it returns a linked list of potentially multiple socket addresses, you need to loop through the list attempting to connect() to every address until one of them is successful. This is especially important if you ever want to upgrade the code to support both IPv4 and IPv6 (by setting hints.ai_family = AF_UNSPEC;).
Try something more like this instead:
int main(int argc, char *argv[])
{
if (argc != 4)
{
printf("should receive 3 arguments Received %d args\n", argc);
exit(1);
}
struct addrinfo hints, *servinfo, *p;
int sockfd = -1;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET; // or AF_UNSPEC
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
int rv = getaddrinfo(argv[1], argv[2], &hints, &servinfo);
if (rv != 0)
{
perror("getaddrinfo error\n");
return 1;
}
for (p = servinfo; p != NULL; p = p->ai_next) {
//Initialize socket
sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (sockfd < 0) continue;
//Initialize connection
rv = connect(sockfd, p->ai_addr, (socklen_t) p->ai_addrlen);
if (rv == 0) break;
close(sockfd);
sockfd = -1;
}
freeaddrinfo(servinfo);
if (sockfd < 0) //Error creating/connecting socket
{
perror("Error creating/connecting socket \n");
exit(1);
}
printf("connect successful\n");
...
close(sockfd);
exit(0);
}
You define serv_addr
struct sockaddr_in *serv_addr;
Then you use it
memset((void*)serv_addr, 0,(size_t) sizeof(*serv_addr));
serv_addr->sin_family = AF_INET;
serv_addr->sin_port = htons(port);
serv_addr->sin_addr.s_addr = inet_addr("127.0.0.1"); //change?
But nowhere in between those two places in the code do you initialize the pointer! That means serv_addr is uninitialized and its value is indeterminate and will point to some seemingly random location. Dereferencing the pointer will lead to undefined behavior.
The simple and natural and de facto standard solution is to make serv_addr not a pointer, but a structure object:
struct sockaddr_in serv_addr;
Then when you need a pointer you use the address-of operator &.
The issue above is further complicated by you actually using the & operator when calling connect. With serv_addr being a pointer, then &serv_addr is a pointer to the pointer. It will be of type struct sockaddr_in **. It is this issue, with the pointer to the pointer, that leads to the error message, since the pointer you send in is not a pointer to a sockaddr_in structure object.
By using a structure object as shown above will solve this problem as well.

Need help in understanding Sockets getaddrinfo

I have been trying to learn sockets programming, and came across this website: http://beej.us/guide/bgnet/output/html/multipage/index.html which is really good. I was able to understand, but after writing a test program myself I ended up with a problem which I cannot figure after 3 hours. Have very limited time, so thought asking experts help here.
This is my server program:
/**
* Program showing how sockets can be used
*/
#include <stdio.h> // For printf
#include <strings.h> // For bzero, memset
#include <stdlib.h> // For exit, atoi
#include <unistd.h> // For close
#include <sys/socket.h> // For socket
#include <sys/types.h> // For types
#include <arpa/inet.h> // For inet_addr
#include <netdb.h> // Import module network database
#include <errno.h> // To access the global errno that holds last system call error
#include <assert.h> // For asserting
#define ADDRESSINFO_GET_SUCCESS 0
const int kSuccess = 0;
const char *kMyPort = "3490"; // Can be either port num or name of the service
const int kMaxListenConn = 10; // How many connections queue will hold
// Utility function to get socket address, IPv4 or IPv6:
void* getSocketAddress(const struct sockaddr *sa)
{
// Cast socketaddr to sockaddr_in to get address and port values from data
if (sa->sa_family == PF_INET) {
return &(((struct sockaddr_in *)sa)->sin_addr);
}
return &(((struct sockaddr_in6 *)sa)->sin6_addr);
}
// Utility function to get socket address string
void getSocketAddressString(const struct sockaddr *sd, char *ipAddr)
{
inet_ntop(sd->sa_family, getSocketAddress(sd), ipAddr, INET6_ADDRSTRLEN);
}
int createAndBindSocket(const struct addrinfo *addrList)
{
int status = -1; // Invalid status
int socketFileDesc = -1; // Invalid descriptor
const struct addrinfo *addrIt;
/*
* STEP 2.1: Loop through all the addrinfo nodes and bind to the one we can
*/
for (addrIt = addrList; addrIt != NULL; addrIt = addrIt->ai_next)
{
char ipAddr[INET6_ADDRSTRLEN];
inet_ntop(addrIt->ai_family, getSocketAddress(addrIt->ai_addr), ipAddr, sizeof ipAddr);
printf("IP: %s\n", ipAddr);
/*
* STEP 2.2: Crete the socket file descriptor for our IP address
*/
socketFileDesc = socket(addrIt->ai_family, addrIt->ai_socktype, addrIt->ai_protocol);
if (socketFileDesc == -1) {
fprintf(stderr, "Failed to create socket with error: %d\n", errno);
perror("socket"); // Get error desc
continue; // Try next address
}
/*
* STEP 2.3: Set socket behaviour by making ip address to be re-used if used already
*/
int yes=1;
if (setsockopt(socketFileDesc, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
{
perror("setsockopt");
exit(1);
}
printf("Port %d\n",((struct sockaddr_in *)addrIt->ai_addr)->sin_port);
/*
* STEP 2.4: Bind our socket with ip address and port number to listen
*/
status = bind(socketFileDesc, addrIt->ai_addr, addrIt->ai_addrlen);
if (status != kSuccess) {
fprintf(stderr, "Failed to bind socket with error:%d\n", errno);
perror("bind"); // Get error desc
// Clear socket
close(socketFileDesc);
socketFileDesc = -1;
continue; // Try next address
}
}
return socketFileDesc;
}
int main()
{
int status = -1; // Status is invalid
struct addrinfo hints; // Holds our hints to get address info
struct addrinfo *addrList; // Contains our address info
/*
* STEP 1: Setup service details
*/
// Make sure struct is empty
bzero(&hints, sizeof hints); // memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; // Don't care IPv4 or v6
hints.ai_socktype = SOCK_STREAM; // Use TCP stream sockets
hints.ai_flags = AI_PASSIVE; // Use my local IPs or you igore this and provide IP manually in first arg
status = getaddrinfo(NULL, kMyPort, &hints, &addrList);
if (status != kSuccess) {
fprintf(stderr, "Failed to get address info with error: %s\n", gai_strerror(status));
exit(1);
}
/*
* STEP 2: Create a socket and bind it
*/
int socketFileDesc;
socketFileDesc = createAndBindSocket(addrList);
freeaddrinfo(addrList); // Done with list
if (socketFileDesc == -1) {
exit(1);
}
/*
* STEP 3: Listen to the port for incoming connections
*/
status = listen(socketFileDesc, kMaxListenConn); // Second arg is number of incoming connections in queue
if (status != kSuccess) {
fprintf(stderr, "Failed to listen to the port\n");
perror("listen");
goto exit;
}
printf("Server is listening at the port %s\n", kMyPort);
struct sockaddr_storage inConnAddr; // Big enough to hold both IPv4 and v6
socklen_t inConnAddrLen = sizeof inConnAddr;
const size_t kMaxBufferSize = 50;
char buff[kMaxBufferSize] = {0};
long bytesReceived = -1;
long bytesSent = 0;
int clientSockfd;
while (1) {
/*
* STEP 4: Accept incoming connections
*/
inConnAddrLen = sizeof inConnAddr;
clientSockfd = accept(socketFileDesc, (struct sockaddr *)&inConnAddr, &inConnAddrLen);
// Got new connection ?
if (clientSockfd == -1) {
perror("accept"); // Print error description
continue; // Continue to look for new connections
}
//
// Got connection, create child process to handle request
//
if (!fork()) {
close(socketFileDesc); // No need with child
char ipAddr[INET6_ADDRSTRLEN];
getSocketAddressString((struct sockaddr *)&inConnAddr, ipAddr);
printf("Child process created for hanlding request from %s\n", ipAddr);
/*
* STEP 5: Receive and Send data to requests
*/
bytesReceived = recv(clientSockfd, &buff, kMaxBufferSize - 1, 0);
if (bytesReceived > 0)
{
printf("Data from client %s\n", buff);
while (bytesSent < bytesReceived) {
bytesSent = send(clientSockfd, buff, bytesReceived, 0);
printf("Bytes sent %ld\n", bytesSent);
}
}
if (bytesReceived < 0) {
perror("recv");
}
else if (bytesReceived == 0) {
printf("Connection closed by server\n");
}
close(clientSockfd); // Close socket
exit(0);
}
}
exit:
/*
* STEP 5: Close the socket
*/
close(socketFileDesc);
return 0;
}
This is my client program:
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <netdb.h>
#include <strings.h>
#include <arpa/inet.h>
const char kSuccess = 0;
// Utility function to get socket address
void* getSocketAddress(const struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &( ((struct sockaddr_in *)sa)->sin_addr );
}
return &( ((struct sockaddr_in6 *)sa)->sin6_addr );
}
// Utility function to get socket address string
void getSocketAddressString(const struct sockaddr *sd, char *ipAddr)
{
inet_ntop(sd->sa_family, getSocketAddress(sd), ipAddr, INET6_ADDRSTRLEN);
}
int createAndConnectSocket(const struct addrinfo *addrList)
{
int socketFileDesc = -1; // Invalid descriptor
const struct addrinfo *addrIt;
/*
* STEP 2.1: Loop through all the addrinfo nodes and bind to the one we can
*/
for (addrIt = addrList; addrIt != NULL; addrIt = addrIt->ai_next)
{
/*
* STEP 2.2: Crete the socket file descriptor for our IP address
*/
socketFileDesc = socket(addrIt->ai_family, addrIt->ai_socktype, addrIt->ai_protocol);
if (socketFileDesc == -1) {
fprintf(stderr, "Failed to create socket with error: %d\n", errno);
perror("socket"); // Get error desc
continue; // Try next address
}
/*
* STEP 2.3: Set socket behaviour by making ip address to be re-used if used already
*/
int yes=1;
if (setsockopt(socketFileDesc, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
{
perror("setsockopt");
exit(1);
}
char ipAdd[INET6_ADDRSTRLEN];
getSocketAddressString(addrIt->ai_addr, ipAdd);
((struct sockaddr_in *)addrIt->ai_addr)->sin_port = atoi("3490");
printf("IP is %s::%d\n", ipAdd,((struct sockaddr_in *)addrIt->ai_addr)->sin_port);
// Connect to the socket
int status;
status = connect(socketFileDesc, addrIt->ai_addr, addrIt->ai_addrlen);
if (status != kSuccess) {
perror("connect");
close(socketFileDesc);
socketFileDesc = -1;
continue;
}
}
return socketFileDesc;
}
int main(int argc, char* argv[])
{
// Check we have data from arguments
if (argc < 3 || argc > 3) {
perror("Invalid command");
printf("Usage: %s hostname portnumber\n", argv[0]);
printf(" %s 192.168.1.2 3490\n", argv[0]);
}
// Setup server address info
struct addrinfo *serverInfo;
struct addrinfo hints;
int status = -1;
memset(&hints, 0, sizeof hints); // Make sure it is empty
hints.ai_family = AF_INET; // IPv4
hints.ai_socktype = SOCK_STREAM; // Use socket stream
((struct sockaddr_in *)&hints.ai_addr)->sin_port = atoi(argv[2]);
status = getaddrinfo(argv[1], "3490", &hints, &serverInfo);
if (status != kSuccess) {
fprintf(stderr, "Failed to get address info %s\n", gai_strerror(status));
exit(1);
}
printf("Connecting to %s::%s...\n", argv[1], argv[2]);
// Create and bind socket
int sockfd = createAndConnectSocket(serverInfo);
freeaddrinfo(serverInfo); // We are done with serverinfo
if (sockfd == -1) {
exit(1);
}
// Send and receive data from server
long bytesReceived = -1;
long bytesSent = 0;
const size_t kMaxBufferSize = 50;
char buff[kMaxBufferSize];
const char *msg = "Hi! I am client!";
size_t msgLen = strlen(msg);
printf("Connected to server\n");
// Loop to send and receive data
while (1) {
while (bytesSent < msgLen) {
bytesSent = send(sockfd, msg, msgLen, 0);
printf("Bytes sent %ld\n", bytesSent);
}
bytesReceived = recv(sockfd, &buff, kMaxBufferSize - 1, 0);
if (bytesReceived > 0)
{
printf("Data received from server: %s\n", buff);
}
else if (bytesReceived < 0) {
perror("Read error");
break;
}
else if (bytesReceived == 0) {
printf("Connection closed by server\n");
break;
}
}
// Close socket
close(sockfd);
return 0;
}
My problem is: Even though I have set the port and IP in getaddrinfo() call, but when it is binding or connecting the port number found in sockaddr struct is wrong as it is different value. I do know what is happing here, and I get connection refused message when I do that because of that.
Can anyone please take a look at my program and tell me why I am getting connection refused ? I would really appreciate if someone can suggest any improvements in my code.
Thanks
You're not connecting to the port you think you're connecting to.
((struct sockaddr_in *)addrIt->ai_addr)->sin_port = atoi("3490");
The value of sin_port must be in network byte order, i.e. big endian. You're instead assigning the value 3490 (via atoi) directly, so the value is in host byte order. Your platform is most likely using little endian byte ordering.
As a result instead of connecting to port 3490 (0DA2 hex) you're connecting to port 41485 (A2 0D hex).
You need to use the htons function, which converts a 16 bit value (since sin_port is a 16 bit field) from host byte order to network byte order. Also, there's no need to use atoi here. Just use a numeric constant instead.
((struct sockaddr_in *)addrIt->ai_addr)->sin_port = htons(3490);

sockaddr value changes unexpectedly after calling getaddrinfo()

I am programming an UDP client. I want to bind the socket to a given port on the client machine, so that the same port is always used for all sends. I get the sockaddr for the server using getaddrinfo, and I do the same to get the sockaddr which I pass to the call to getaddrinfo. However, after the second call to getaddrinfo the address of the server machine changes, and I end up sending the packet from the client machine to the client machine itself.
The following code is a standalone example that reproduces the error:
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define SERVER_HOST "www.google.com"
#define UDP_PORT "4000"
static struct sockaddr_in *destination_addr = NULL;
static int client_port;
int main(){
uint8_t bytes[5] = { 0xaa, 0xab, 0xac, 0xad, 0xaf}; //some data to send
uint16_t length = 5;
int status;
//initialize socket and bind
if (destination_addr == NULL) {
struct addrinfo hints;
struct addrinfo *servinfo, *p;
srand(time(NULL));
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE;
if ((status = getaddrinfo(SERVER_HOST, UDP_PORT, &hints, &servinfo)) != 0) {
printf("Unable to send UDP. Reason: %s", gai_strerror(status));
return 0;
}
for (p = servinfo; p != NULL; p = p->ai_next) {
if (p->ai_addr != NULL)
destination_addr = (struct sockaddr_in *) p->ai_addr;
}
client_port = 1027 + rand()%50000;
freeaddrinfo(servinfo);
printf("Created destination_addr with IP %s\n", inet_ntoa(destination_addr->sin_addr));
}
int send_socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (send_socket_fd == -1) {
printf("Unable to create UDP socket. Reason: %s", strerror(errno));
return 0;
}
printf("IP after socket creation is %s\n", inet_ntoa(destination_addr->sin_addr));
int yes = 1;
if (setsockopt(send_socket_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof (int)) == -1) {
perror("setsockopt");
return 0;
}
printf("IP after sockopt is %s\n", inet_ntoa(destination_addr->sin_addr));
// bind to local address
char str_client_port[6];
snprintf(str_client_port, 5, "%d", client_port);
struct addrinfo *source_addr_info;
struct addrinfo hints;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
// ***** destination_addr changes after this call *****
getaddrinfo (NULL, str_client_port, &hints, &source_addr_info);
printf("IP after getaddrinfo is %s\n", inet_ntoa(destination_addr->sin_addr));
bind(send_socket_fd, source_addr_info->ai_addr, source_addr_info->ai_addrlen);
printf("IP after binding is %s\n", inet_ntoa(destination_addr->sin_addr));
// send
int bytes_sent = sendto(send_socket_fd, bytes, length, 0, (struct sockaddr *)destination_addr, sizeof *destination_addr);
printf("Sent to IP %s\n", inet_ntoa(destination_addr->sin_addr));
if (bytes_sent != length){
if (bytes_sent == -1){
printf("UDP send failed. Reason: %s", strerror(errno));
}
else {
printf("UDP: not all bytes could be sent.");
}
}
close(send_socket_fd);
return 1;
}
The output generated by the execution of this program in my machine is:
Created destination_addr with IP 64.233.167.105
IP after socket creation is 64.233.167.105
IP after sockopt is 64.233.167.105
IP after getaddrinfo is 0.0.0.0
IP after binding is 0.0.0.0
Sent to IP 0.0.0.0
I am rather new to socket programming in C, and pretty sure I am doing some silly mistake, but after googling a lot and trying many things, I am still stuck with this. Any idea?
Solved. As #molbdnilo pointed out, the error was caused by the call to freeaddrinfo. To fix it I now copy the value pointed by p->ai_addr, so that it is not lost when freeing. I substituted:
if (p->ai_addr != NULL)
destination_addr = (struct sockaddr_in *) p->ai_addr;
with
if (p->ai_addr != NULL){
destination_addr = malloc(sizeof *destination_addr);
memcpy(destination_addr, (struct sockaddr_in *)p->ai_addr, sizeof *p->ai_addr);
}
and it worked.

Resources