I'm trying to get a program (client) to communicate with another (server) using sockets in C, but I'm constantly getting the error "Invalid Argument" from the server.
I'll try to show the pieces of code that are relevant to this issue after explaining what's happening:
When it comes to the Client, I assume that everything is working correctly: The client sends a request to server and the server receives the message correctly, but then when the server attempts to reply I get an "Invalid Argument" error.
This is the declaration of the variables used by the main function of the server:
int port = DEFAULT_PORT;
int sock;
struct sockaddr_in hostAdress, clientAdress;
socklen_t clientAdressLength;
Here I do the binding of the socket to the hostAdress:
sock = socket(PF_INET,SOCK_DGRAM,0);
memset(&hostAdress, 0, sizeof(struct sockaddr_in));
memset(&clientAdress, 0, sizeof(struct sockaddr_in));
hostAdress.sin_family = AF_INET;
hostAdress.sin_port = htons(port);
hostAdress.sin_addr.s_addr = INADDR_ANY;
bind(sock, (struct sockaddr*) &hostAdress, sizeof(hostAdress));
After a bit of code, I go into a loop receiving information, using recvfrom in this manner:
recvfrom(sock, dataBuffer, sizeof(dataBuffer), 0, (struct sockaddr*)&clientAdress, &clientAdressLength);
When the server receives the request, it identifies it and jumps to this function (this behaviour is confirmed):
handle_helloRQ(sock, clientAdress, clientAdressLength);
While I am aware that "clientAdressLength" could be obtained doing sizeof(clientAdress), somehow doing this fixed this same issue last time I had it.
This function is declared as:
int handle_helloRQ(int sock, struct sockaddr_in server_addr, socklen_t server_addr_length)
In this function, the main variables are:
char buffer[512];
size_t bufferSize = sizeof(buffer);
memset(&buffer, 0, sizeof(buffer));
stshort(2, buffer);
strcat(buffer+2, "Hello World");
stshort is a simple macro that places a short int in the first 2 bytes of the buffer. This works as intended.
Once that is done, it attempts to do the following:
sendto(sock, buffer, bufferSize, 0, (struct sockaddr*)&server_addr, server_addr_length);
... And this is when things go wrong. sendto returns -1, and using perror("sendto"); I get an "Invalid Argument" error.
I tried a thousand different ways of imputing the parameters, but I can not find an error. I have exhausted my other options when it comes to this kind of problems (namely, asks the teachers of my university and show the code to a few more advanced colleagues), and no one seemed to be able to find the error.
As a side note, I do use
close(sock);
when the server receives the signal to be closed, but I may have had to force-close it once before it managed to reach this function.
To whoever is reading this, thank you for your time!
Try this instead:
sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); // <-- add protocol
...
clientAdressLength = sizeof(clientAdress); // <-- add this
recvfrom(sock, dataBuffer, sizeof(dataBuffer), 0, (struct sockaddr*)&clientAdress, &clientAdressLength);
...
handle_helloRQ(sock, (struct sockaddr*)&clientAdress, clientAdressLength); // <-- pass address by pointer
...
close(sock);
int handle_helloRQ(int sock, struct sockaddr* recip_addr, socklen_t recip_addr_length)
{
char buffer[512];
memset(&buffer, 0, sizeof(buffer));
stshort(2, buffer);
strcat(buffer+2, "Hello World");
sendto(sock, buffer, sizeof(buffer), 0, recip_addr, recip_addr_length);
...
}
Related
I have the following schema:
program in terminal A (<process 1>):
Stored:
<process 1>: <portnumber 51340>
<process 2>: <portnumber 58432>
program in terminal B (<process 2>):
Stored:
<process 1>: <portnumber 51340>
<process 2>: <portnumber 58432>
So I have an UDP socket connection between them to send and recieve an struct:
int socketID = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in servaddr = {0};
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(0);
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
int rc = bind(socketID, (const struct sockaddr *)&servaddr, sizeof(servaddr));
socklen_t sockaddrlen = sizeof(servaddr);
int getsocket = getsockname(socketID, (struct sockaddr *)&servaddr, &sockaddrlen);
Before I do the sendto I do:
fprintf(stdout, "Using procPort %d\n", idPort);
servaddr.sin_port = htons(<portNumber 58432>);
fprintf(stdout, "Using port %d\n", &toSocketID.sin_port);
sendto(fromSocketID, &msg, sizeof(struct message), 0, (const struct sockaddr *)&toSocketID, toSocketIDLen);
And it prints:
Using procPort 58432
Using port 58432
All is OK until here. Here's the problem, when, before I do the recvfrom I do:
servaddr.sin_port = htons(<portNumber 58432>);
fprintf(stdout, "Using procPort %d\n", <portNumber 58432>);
fprintf(stdout, "Using port %d\n", servaddr.sin_port);
struct message * recievedMsg = malloc(sizeof(struct message));
recieveResult = recvfrom(socketID, recievedMsg, sizeof(*recievedMsg), 0, (const struct sockaddr *)&servaddr, sizeof(servaddr));
And it prints:
Using procPort 58432
Using port 16612
And it does not recieve the message, I think this is because of the magic change in the port, that 16612 that doesn't appear anywhere in my program. But it could also be because of the configuration. Do you see what's wrong? I'm losing my mind.
Edit:
Some of you are arguing about byte swapping.
Other outputs for the second part:
Using procPort 50912
Using port 57542
Using procPort 33592
Using port 14467
Using procPort 42115
Using port 33700
These snippets make it hard to really get a big picture, but I'm pretty sure your compiler is telling you what the problem is.
struct sockaddr_in servaddr = {0};
...
receiveResult = recvfrom(socketID,
receivedMsg, sizeof(*receivedMsg),
0,
(const struct sockaddr *)&servaddr, sizeof(servaddr));
As the compiler notes, you're passing a last parameter as an integer, but it's supposed to be a pointer. The idea is that you tell recvfrom how big your address structure is, but on return the kernel tells YOU how much of that structure it's using.
I'm surprised it's not faulting due to giving a small integer as a pointer.
Also, the second-to-last parameter shouldn't be const.
Change this to (formatting just for readability here):
socklen_t addrsize = sizeof servaddr;
receiveResult = recvfrom(socketID,
receivedMsg, sizeof *receivedMsg,
0,
(struct sockaddr *)&servaddr, &addrsize);
EDIT: Moral of the story: always turn on compiler warnings and understand them, not just make them go away. Throwing in random casts will likely silence the compiler but it will remove the good advice.
When you use a cast, you're telling the compiler "trust me", and if you lie to the compiler, it will get its revenge.
EDIT 2: Other things in the code can't be right.
I can't see what the type of toSocketID is, but I can't see any construction where this would be right:
fprintf(stdout, "Using port %d\n", &toSocketID.sin_port);
I would imagine ntohs(toSocketID->sin_port) seems more plausible.
I have been working on a proxy server. It has to connect to another "monitor" program and get connection address information from that program. That program in running on a known ip and port. If I use the following to connect it works fine:
struct hostent *serv;
int sockfd;
struct sockaddr_in serv_addr;
serv = gethostbyname("localhost");
sockfd = socket(AF)INET, SOCK_STREAM, 0);
if (sockfd < 0)
/* Error handling */
bzero((char *) &serv_addr, sizeof (serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *) server->h_addr, (char *) &serv_addr.sin_addr.s_addr, server->h_length);
serv_addr.sin_port = htons(portno); // portno is an int holding the port number
if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
/* error handling */
However I wanted to use the exact ip address instead of local host, they may not alway be on the same machine, and gethostbyname () is obsolete. I attempted to use getaddrinfo() like this:
struct addrinfo hints, *server;
int sockfd, i;
char *host = "192.168.2.4";
char *port = "4044";
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = 0;
hints.ai_protocol = IPPROTO_TCP; // have also tried it with 0
i = getaddrinfo(host, port, &hints, &server);
if (i != 0)
/* Error handling */
sockfd = socket(server->ai_family, server->ai_socktype, server->ai_protocol);
freeaddrinfo (server); // have also tried without this line
if (sockfd < 0)
/* Error handling */
printf("Attempting to connect\n");
if (connect(sockfd, server->ai_addr, server->ai_addrlen) != -1)
/* Error handling */
printf("Connection attempt complete\n");
This second attempt hangs for a long time on the connect() command and finally returns in error. I have gone over the examples in several places and searched previous questions here on stackoverflow but can't find the problem, or why one works and the other doesn't. I think it has something to do with the server->ai_addr value but have not been able to verify it yet.
Any help would be appreciated, am I doing something obviously wrong? I don't know where else to look for more ideas to check.
EDIT UPDATE:
I have figured out one problem. In the line if (connect (/* */) != -1)
it should have been != 0. One of the samples I was looking at used a bind() statement instead. If I use the local host address with the second may it will work with that change. However I still can't connect to a specific ip address node. I am beginning to suspect that the ip address I was given isn't one that this computer can receive network traffic on. I am not sure how to check that though. I will see If I can figure out any more info on the error with using the specific ip address and edit again with the information.
EDIT UPDATE: I added #include and tried to print out the error code after the system call returns. I also printed out the return. It returns a -1 which according to the documentation I found just means an error occurred when I try to print out the errno it seg faults.
fprintf(stderr, "Error Code %s\n", errno); // seg faults
However changing it to:
fprintf(stderr, "Error Code %d\n", errno); // returns Error Code 60
Try to replace
hints.ai_flags = 0;
with
hints.ai_flags = AI_NUMERICHOST;
and see what happens.
The ip address that I was given is not the ip on the computer I am using. I finally decided that the ip address had to be the problem. I found the ip address on my computer and got the server program to bind to it. I also put it in as the ip address for the code included above instead of local host and it was able to connect regardless of rather the server was on that specific ip address or simply connected to INADDR_ANY.
I am tying to connect to a bit torrent tracker, http://tracker.thepiratebay.org. The gethostbyname() keeps returning null, how should I fix this? Also do you see anything else wrong with this code?
int sock;
struct sockaddr_in servAddr;
int portNum = 80;
if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0){
printf("fail create socket");
return 0;
}
char *path = "http://tracker.thepiratebay.org/";
struct hostent *hp = gethostbyname(path);
if(hp==NULL){
printf("null");
else{
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;
memcpy( (char *) &servAddr.sin_addr.s_addr, (char *) hp->h_addr, hp->h_length );
servAddr.sin_port = htons(portNum);
}
//send request to tracker server
if (send(sock, requestToSend, strlen(requestToSend), 0) != strlen(requestToSend)){
printf("fail send");
return 0;
}
The problem here is that http://tracker.thepiratebay.org/ is a URL, but gethostbyname() expects just the host name. The host name is tracker.thepiratebay.org.
It would make it much easier if you just use libcurl, which will handle all of that HTTP stuff for you. It is extremely common to use libcurl in applications that connect to HTTP servers; it is an excellent library. It's certainly easier than socket programming.
Use getaddrinfo()
The modern alternative to gethostbyname() is getaddrinfo(). It's not that gethostbyname() doesn't do what you want, rather, getaddrinfo() is simply better in every conceivable way.
struct addrinfo hint, *ap;
memset(&hint, 0, sizeof(hint));
hint.ai_family = AF_UNSPEC;
hint.ai_socktype = SOCK_STREAM;
int r = getaddrinfo("tracker.thepiratebay.org", "http", &hint, &ap);
This will not only get you the address for the host you want, but it will also fill in the port number. You can use "http" as the port, or you can use "80" for the port, they are the same thing (as long as /etc/services has the right entry).
Other problems
This line is wrong.
memcpy( (char *) &servAddr.sin_addr.s_addr, (char *) hp->h_addr, hp->h_length );
You don't know that gethostbyname() returned an IPv4 address, and it is foolish to try and copy it into a struct sockaddr_in. If gethostbyname() returned an IPv6 address, you have just smashed your stack and your program will crash -- or worse, it might not crash.
Either check that it returns an IPv4 address, or simply copy hp->h_addr into a generic struct sockaddr that was returned from malloc(hp->h_length). This is a bit ugly but it's the way it goes.
Finally, it is wrong to cast the arguments to memcpy(). It's not an error, but it's wrong. Don't do it, it can cause otherwise legitimate compiler errors to be suppressed, e.g., if you accidentally cast an int to char *.
I am an experienced Linux socket programmer and am writing a server application which has many outgoing interfaces. Now server socket binds to a random source port in the start of the process along with INADDR_ANY.
Later at some point when submitting response to a specific node, i need to assign a fixed source ip address. The standard way to do this is calling bind. However, bind is called once for the port number, successive calls fail with invalid argument error.
Creating a new socket is not really a good choice since i will have to be doing this very often upon responding to some clients.
I have also explored SO and a lot of socket options such as IP_FREEBIND, but it doesn't quite suite my scenario.
Perhaps using IP_PKT_INFO and setting source address might work unless it suffers the same problem i.e. not allowing a socket once bound to INADDRANY to rebind to a fixed source ip latter.
Is there a way to unbind an existing socket or an alternate way to setting source ip address in outgoing packet?
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if(sock < 0)
printf("Failed creating socket\n");
struct sockaddr_in addr;
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(1500);
addr.sin_addr.s_addr = INADDR_ANY;
// first bind succeeds
if ( (status = bind(sock, (struct sockaddr *) &addr, sizeof(addr))) < 0)
printf("bind error with port %s\n", strerror(errno));
struct sockaddr_in src_addr;
memset(&src_addr, 0, sizeof(struct sockaddr_in));
src_addr.sin_family = AF_INET;
if (inet_aton("10.0.2.17", &(src_addr.sin_addr)) == 0)
printf("Failed copying address\n");
// second bind fails
if((status = bind(sock, (struct sockaddr *)&src_addr, sizeof(src_addr))) < 0)
printf("re bind error with ip %s\n", strerror(errno));
Any ideas in this regard will be highly appreciated. I have gone through considerable material on sockets, SO etc. but no success yet.
I finally found the solution myself so accepting my own answer (shameless but correct plugin), supplemented with code sample.
I originally wanted to rewrite source address of an outgoing packet without creating the socket again where the socket was already bound. Calling bind multiple times fail for this case, and (in my particular situation), i was not able to just have separate sockets for each source ip and use it.
I found some references in IP_PACKET_INFO but it was a pain to get it to work correctly. Following reference was helpful.
Setting source of udp socket
Sample Code
Here is a trivial application which creates a udp socket, binds it to a local port, then before sending a particular message, it appends the outgoing source ip address. Keeping in mind that in my case, i created a sudo interface and assigned it another ip. The send call will fail if this is not the case.
int status=-1;
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if(sock < 0)
printf("Failed creating socket\n");
int opt = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
struct sockaddr_in bind_addr;
memset(&bind_addr, 0, sizeof(struct sockaddr_in));
bind_addr.sin_family = AF_INET;
bind_addr.sin_port = htons(44000); // locally bound port
if((status = bind(sock, (struct sockaddr *)&bind_addr, sizeof(bind_addr))) < 0)
printf("bind error with port %s\n", strerror(errno));
// currently using addr as destination
struct sockaddr_in addr;
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(80); // destination port
if (inet_aton("74.125.236.35", &(addr.sin_addr)) == 0)
printf("Failed copying remote address\n");
else
printf("Success copying remote address\n");
struct sockaddr_in src_addr;
memset(&src_addr, 0, sizeof(struct sockaddr_in));
src_addr.sin_family = AF_INET;
if (inet_aton("10.0.2.17", &(src_addr.sin_addr)) == 0)
printf("Failed copying src address\n");
else
printf("Success copying src address\n");
char cmbuf[CMSG_SPACE(sizeof(struct in_pktinfo))];
char msg[10] = "hello";
int len = strlen(msg);
struct msghdr mh;
memset(&mh, 0, sizeof(mh));
struct cmsghdr *cmsg;
struct in_pktinfo *pktinfo;
struct iovec iov[1];
iov[0].iov_base = msg;
iov[0].iov_len = len;
mh.msg_name = &addr; // destination address of packet
mh.msg_namelen = sizeof(addr);
mh.msg_control = cmbuf;
mh.msg_controllen = sizeof(cmbuf);
mh.msg_flags = 0;
mh.msg_iov = iov;
mh.msg_iovlen = 1;
// after initializing msghdr & control data to
// CMSG_SPACE(sizeof(struct in_pktinfo))
cmsg = CMSG_FIRSTHDR(&mh);
cmsg->cmsg_level = IPPROTO_IP;
cmsg->cmsg_type = IP_PKTINFO;
cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
pktinfo = (struct in_pktinfo*) CMSG_DATA(cmsg);
//src_interface_index 0 allows choosing interface of the source ip specified
pktinfo->ipi_ifindex = 0;
pktinfo->ipi_spec_dst = src_addr.sin_addr;
int rc = sendmsg(sock, &mh, 0);
printf("Result %d\n", rc);
The key statement is
pktinfo->ipi_spec_dst = src_addr.sin_addr;
where we are specifying the source ip address to be used. The rest of things like cmsg struct etc. are merely used in order to be able to write ipoktinfo struct ourselves
There is no way to unbind and rebind an existing socket.
Why don't you create a socket for each interface instead? Since the UDP/IP protocol is connectionless, you can choose the source IP address by choosing which socket you use to send the reply with; there is no need to use the same socket the incoming datagram was received on.
The downsides are that you can no longer bind to the wildcard address, and you must use select(), poll(), multiple threads, or some other mechanism to receive datagrams from multiple sources concurrently. You'll also need some logic to efficiently pick the socket based on the client IP address.
In most cases, I suspect that adding a few route entries to route each remote IP address to the desired host IP address, and using a separate socket for each host IP address and port combination, solves the issues perfectly -- and using the very efficient kernel functionality to do so. While the behaviour may be an application requirement, I suspect it is better solved using the network interface configuration instead. Unfortunately, often the requirements are written by semi-functional idiots better suited for manual labor, and your hands are tied.. if so, I commiserate.
If you have a test network with workstations having multiple physical network interfaces, I can provide a simple example C99 test program you can use to verify the design works.
I have the following typical code in C under Linux to get UDP data:
sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
mysock.sin_family = AF_INET;
mysock.sin_addr.s_addr = INADDR_ANY;
mysock.sin_port = my_port;
bind(sock, &mysock, sizeof(mysock);
recvfrom(sock, buf, PKTSZ, 0, &client, len);
All the above code works, but now I have a need to find out the sender's udp port, is there a structure or system call I can use to retrieve such info when I receive a udp packet ?
thanks
recvfrom(sock, buf, PKTSZ, 0, &client, len);
The senders socket address is stored in the client variable of your code. To access the senders port use sockaddr_in instead of sockaddr. Example:
sockaddr_in client;
int len = sizeof(client);
recvfrom(sock, buf, PKTSZ, 0, (struct sockaddr *)&client, (socklen_t *)&len);
int port = ntohs(client.sin_port);
References:
Beej's Guide to Network Programming and MSDN
recvfrom() is supposed to return that to you in the fifth argument (struct sockaddr*).
EDIT:
Use something like this
struct sockaddr_in client;
recvfrom(... (struct sockaddr*)&client ...);
client.sin_port should be the sender's port.
UDP sender port would be transient. I don't think you could use that for anything other than for reporting.
The fifth argument can be cast to struct sockaddr_in, and there sin_port is the remote port number.
Casting the client to sockaddr_in solves my problem.
Yes! Remember the ntohs() above all! It wasn't until I used the programmer's calculator that I realized it WAS stored as BigEndian 15B3, not the presumably ephemeral port B315!