I'm trying to write a server that that receives a query via UDP and sends a response via UDP. The problem I'm running into is that when I try to send my response, I get a "101 Network is unreachable" error.
Based on the question here I tried to resolve this by taking out the hints.ai_flags = AI_PASSIVE; line, but then the server never successfully gets the message. I looked at the man page for addrinfo and it sounds like if the AI_PASSIVE flag is set, the socket can only recvfrom(), while if it's not set, the socket can only sendto(). I've seen a bunch of examples online with people doing both from a single socket, though; what am I missing?
Relevant code:
struct addrinfo hints;
struct addrinfo *serverinfo;
memset(&hints,0,sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE;
int status = getaddrinfo(NULL, port, &hints, &serverinfo);
int sock = socket(serverinfo->ai_family, serverinfo->ai_socktype, serverinfo->ai_protocol);
status = bind(sock, serverinfo->ai_addr, serverinfo->ai_addrlen);
freeaddrinfo(serverinfo);
// poll until there's an incoming packet
struct sockaddr sender;
socklen_t sendsize = sizeof(sender);
bzero(&sender, sizeof(sender));
recvfrom(sock, message, sizeof(message), 0, &sender, &sendsize);
// message processing
sendto(sock, response, sizeof(response), 0, (struct sockaddr *)&sender, sendsize);
Yes, I have error checking for all those calls (that's how I found the problem); it's simply been left out here for brevity's sake.
You shouldn't use a struct sockaddr to store the source address in the recvfrom call, it might not be able to represent an IP socket address.
You're supposed to use a struct sockaddr_in for an IPv4 address or a struct sockaddr_in6 for an IPv6 address, or better yet, a struct sockaddr_storage to cope with either.
struct sockaddr_storage sender;
socklen_t sendsize = sizeof(sender);
bzero(&sender, sizeof(sender));
recvfrom(sock, message, sizeof(message), 0, (struct sockaddr*)&sender, &sendsize);
Related
On linux I want to connect to a demon, via a socket in a compiled c.cgi program (cgic), which is listening for incoming socket connections. I know the server works because it will responded to 'nc' commands. Assume the server is black-boxed, I can't change it. In my client program I have:
int sockfd;
int len;
struct sockaddr_in address;
int result;
char ch[] = "get=DeviceNo";
sockfd = socket(AF_INET, SOCK_STREAM, 0);
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr("127.0.0.1");
address.sin_port = 3042;
len = sizeof(address);
result = connect(sockfd, (struct sockaddr *) &address, len);
Which returns with a "Connection Refused" error at this point. As a test I compiled the netcat into the .cgi program which does work:
system("echo '-r get=DeviceNo' | nc localhost 3042");
Am I missing something maybe how the socket class is handled within a .cgi? What should I do to try and get this socket to connect or what can I do to further troubleshoot my problem?
When working with sockaddr_in type, you need to know that both socket address sin_addr.s_addr and port sin_port must be in network byte order. Most likely your host is little-endian.
So you need to use inet_addr returns correct value, but for the socket address you need to use:
address.sin_port = htons(3042);
I want to ask if there is a possibility and if there is how do I send broadcast from my UDP server to client and after that send back response from client to server.
I need to implement an application where server sends broadcast on a subnetwork and clients are supposed to receive that message somehow and in that way would get server address so that they could send some messages back to server.
I created a socket with specified server port say 2000 and set setsockopt to SO_BROADCAST and sent some message with sendto but my client hangs on recvfrom forever. Seems like it does not receive anything from server's broadcasting. How to fix this?
SERVER:
struct sockaddr_in addr;
int socketfd,t=1;
socketfd = socket(PF_INET,SOCK_DGRAM,0);
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons("2000");
addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
if (setsockopt(socketfd, SOL_SOCKET, SO_BROADCAST ,&t, sizeof(t)))
ERR("setsockopt");
if(bind(socketfd,(struct sockaddr*) &addr,sizeof(addr)) < 0)
ERR("bind");
char *buf = "HelloFromServer!";
if(sendto(socketfd, buf, strlen(buf), 0, (struct sockaddr *)&addr, sizeof(addr)) <= 0)
{
perror("something went wrong..");
return EXIT_FAILURE;
}
CLIENT:
struct sockaddr_in addr;
int socketfd,t=1;
socketfd = socket(PF_INET,SOCK_DGRAM,0);
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons("2000");
addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
if (setsockopt(socketfd, SOL_SOCKET, SO_BROADCAST ,&t, sizeof(t)))
ERR("setsockopt");
char data[12];
struct sockaddr_in serv_addr;
socklen_t size=sizeof(serv_addr);
recvfrom(fd, (char *)data, sizeof(char[12]), 0, &serv_addr, &size);
And my client hangs on this recvfrom... and therefore I cannot get serv_addr to be stored so that I could send some message back to the server
Clients are supposed to receive that message somehow and in that way would get server address so that they could send some messages back to server.
I believe there is a problem here: for the clients to receive the message broadcasted by the server, they must first have the server's address. The only time that a socket can receive data/communications from an unknown address is a server using listen() on a port which has port forwarding set up (courtesy of the router). Thus, unless the clients already have the server address, it seems the client receiving the data would be impossible, hence the hanging on recvfrom().
The error in both server and client is in
addr.sin_port = htons("2000");
htons() takes an integer, not a string. Write
addr.sin_port = htons(2000);
instead.
I want to get the IP address of the client who’s just connected into my server running WinSock2. I’m using C.
You could get the client's IP-address and port via the call to accept().
Just pass in the appropriate data into the last two parameters.
struct sockaddr_in sa = {0}; /* for TCP/IP */
socklen_t socklen = sizeof sa;
... = accept(..., (struct sockaddr *) &sa, &socklen);
For details please read here.
Have not done it myself, but take a look at getpeername. Looks like this is what you need.
This work for me on winsock2. No need of getpeername
SOCKET newConnection;
SOCKADDR_IN addr;
int addrlen = sizeof(addr);
newConnection = accept(sListen, (SOCKADDR*)&addr, &addrlen);
char *ip = inet_ntoa(addr.sin_addr);
printf("Accepted Connection from : %s", ip);
I have a C code snippet that listens on UDP socket for incomming messages (and it works fine):
uint32_t udp_port = 101010; // example port
int sock_udp = socket(AF_INET, SOCK_DGRAM, 0);
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
server_address.sin_port = htons(udp_port);
bind(sock_udp, (struct sockaddr*) &server_address, (socklen_t) sizeof(server_address));
char buffer[20];
struct sockaddr_in sender_address;
socklen_t sender_len = (socklen_t) sizeof(struct sockaddr_in);
ssize_t rcv_len = recvfrom(sock_udp, buffer, sizeof(buffer), 0, (struct sockaddr * ) &sender_address, &sender_len);
After it I have information on the sender in sender_address structure and I can check addres, port etc. My question is: can I use recv, recvfrom or other similar function to listen for datagrams coming from a certain host? In other words, is it possible to drop datagrams from other sources without reading them?
You can "filter" and receive datagrams from a specified single source if you connect(2) the datagram socket.
If the socket sockfd is of type SOCK_DGRAM then addr is the address to
which datagrams are sent by default, and the only address from which
datagrams are received.
The standard phrases it a little different:
For SOCK_DGRAM sockets, the peer address identifies where all
datagrams are sent on subsequent send() functions, and limits the
remote sender for subsequent recv() functions
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!