We receive multicast data to two machines- Prod and Dev. The below code worked on Prod, but has never worked on Dev (even though the boxes should be set up identically). However, when I run
tshark -i <interface> -c 50
on Dev packets are being received from the same multicast address and port as Prod.
I have posted the code below. The program reaches the log line "Listening for packets" but then appears to simply block on recvfrom().
I would like to clarify I am not doing anything daft. Is there anything else I can check to see what's happening with the packets? I cannot speak with our vendor yet because they will simply run tshark and say the problem must be with our code.
std::string address("1.2.3.4"); // Not real address
const char *group = address.c_str();
int port = 26477;
_sock = socket(AF_INET, SOCK_DGRAM, 0);
assert(_sock >= 0);
u_int yes = 1;
int result = setsockopt(_sock, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes));
assert(result >= 0);
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(port);
result = bind(_sock, (struct sockaddr *)&addr, sizeof(addr));
assert(result >= 0);
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr(group);
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
result = setsockopt(_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq));
assert(result >= 0);
LOG("Listening for packets...."); // CODE REACHES HERE
while (1)
{
socklen_t addrlen = sizeof(addr);
const size_t maxNumBytesToRead = MSGBUFSIZE - 1;
// I think code is just blocking here, waiting for packets
const int nbytes = recvfrom(_sock, msgbuf, maxNumBytesToRead, 0, (struct sockaddr *)&addr, &addrlen);
}
You're specifying INADDR_ANY as the interface to join the multicast group on. This means the system will choose a default interface. If your system has more than one active interface, it might not be the one you intended.
What's probably happening here is that your PROD machine happens to be joining on the desired interface, while the DEV machine is joining on a different interface.
Change mreq.imr_interface to contain the IP address of the network interface you want to bind to.
Related
I'm learning C by writing a small application that sends a DNS query to a specified server. Here is an example of the network code:
int send_query()
{
int sockfd;
struct sockaddr_in server;
if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
perror("cannot create socket\n");
}
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(53);
inet_pton(AF_INET, "8.8.8.8", &(server.sin_addr));
sendto(sockfd, const void *buffer, size_t length, 0, (struct sockaddr *) &server, sizeof(server));
}
This works fine as the query is succesfully sent, and a reply is recieved. However, by sniffing the traffic with Wireshark I can see the message: Destination unreachable (Port unreachable).
I found out that I can avoid this by calling bind() before sendto():
int send_query()
{
int sockfd;
struct sockaddr_in server;
if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
perror("cannot create socket\n");
}
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(53);
inet_pton(AF_INET, "8.8.8.8", &(server.sin_addr));
if(bind(sockfd, (struct sockaddr *) &server, sizeof(server)) < 0) {
perror("bind failed\n");
}
sendto(sockfd, const void *buffer, size_t length, 0, (struct sockaddr *) &server, sizeof(server));
}
Now the Destination unreachable (Port unreachable) message is gone, but the application has to be run with root privileges as it will bind to port 53.
Is it possible to modify the code so a random non-privileged source port is used instead?
Problem solved
The problem occured because of a stupid mistake. I had simply commented out recvfrom(). As I was sniffing the traffic while testing the application, I could see the response and error arrving at my computer, and mistakenly confused this as the application was receving. Because I don't know what the hell I'm doing, I started to mess around with bind() etc. and this avalanche of failure started.
For brevity I did not post all the code, but the issue had probably been solved instantly if had did that instead.
You can bind to port 0 to let the OS randomly pick one available for you (just like INADDR_ANY is 0). See https://stackoverflow.com/a/1077305/3543692
Also, binding to port 53 makes no sense. The 53 port is the port of the DNS server, not the DNS client. Think if all the DNS clients on your computer use 53 for DNS client port, then only one DNS request to a server can be proceeded concurrently. Typically, all clients (both TCP/UDP) use random unused ports assigned by OS.
I would like to ask about the getpeername() function since it returns data as the title states. I tried to get value directly from accept() function, and the result also happens the same. Value of port seems to appear randomly even though value of address is correct(address is 127.0.0.1 since I run multi-processes on an only machine). The return code of getpeername() is 0 (status = 0). I'm using gcc version 4.8.1. I write a peer 2 peer chat application without server. The following is my code:
struct sockaddr_in addr;
socklen_t addr_len;
int tempPort, serverSockfd;
char test[100];
// Get serverSockfd successfully....
serverSockFd = initializeSock(PORT) // In this function I initialize socket(), bind() and listen(), serverSockFd is returned by the value of socket()
addr_len = sizeof addr;
newSock = accept(serverSockfd, (struct sockaddr *)&addr, &addr_len);
tempPort = ntohs(addr.sin_port);
inet_ntop(AF_INET, &(addr.sin_addr), test, sizeof test);
printf("tempPort\t%d\n", tempPort);
printf("test\t%s\n", test);
addr_len = sizeof addr;
if ((status = getpeername(newSock, (struct sockaddr *) &addr, &addr_len)) != 0){
printf("getpeername() error!\n");
}
tempPort = ntohs(addr.sin_port);
inet_ntop(AF_INET, &(addr.sin_addr), test, sizeof test);
printf("tempPort\t%d\n", tempPort);
printf("test\t%s\n", test);
Thanks very much for any your comment. Here is a partial code in initializeSock():
sd = socket(AF_INET, SOCK_STREAM, 0);
if(sd < 0)
{
perror("SocketInit(): socket() error!\n");
exit(1);
}
ret_val = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char*) &flag, sizeof(flag));
if(ret_val == -1)
{
perror("SocketInit(): setsockopt(SO_REUSEADDR) error!\n");
exit(1);
}
gethostname(hostname,100);
host_entry = gethostbyname(hostname);
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(inet_ntoa(*(struct in_addr *)*host_entry->h_addr_list));
ret_val = bind(sd, (struct sockaddr*) &addr, sizeof(addr));
if(ret_val == -1)
{
perror("SocketInit(): bind() error!\n");
printf("For port:%d\n",port);
exit(1);
}
....
return sd;
This is the code to connect to server part of a peer. ConnectSock(portOfPeerA):
sd = socket(AF_INET, SOCK_STREAM, 0);
if(sd < 0)
{
perror("ConnectToServer(): socket() error!\n");
exit(1);
}
if (port != 0) {
addr.sin_family = AF_INET;
addr.sin_port = htons(portOfPeerA);
addr.sin_addr.s_addr = inet_addr(inet_ntoa(*(struct in_addr *)*host_entry->h_addr_list));
// Do I need to bind() the port of peer B when it would like to connect to peer A?
ret_val = connect(sd, (struct sockaddr*)&addr, sizeof(addr));
if(ret_val == -1)
{
printf("Error connect());
exit(1);
}
...
I don't know which port you accept from the peer, but if the peer is connecting to your server (e.g. then one calling accept) it will connect from a (more or less) random port, that's how TCP works. It connects from a fixed port only if the peer explicitly binds to that port before connecting.
This means, that the peers originating port is not defined on the server side (where your code fragments are from) but on the client side (the side which calls connect and where you only do connect but no bind).
But, please note that it might give problems with repeated connections, if both client and server use fixed IP and ports, because then you will get the same 4-tupel in TCP which defines the connections for repeated connections and thus go into all this trouble with the various TIME_WAIT states. So it is better to let the client just pick an available port and not force it to use a specific one.
getpeername() (and accept()) reports the IP and port that the remote party is locally bound to on its end. If the remote party is a client that did not call bind() before calling connect() then connect() performs an implicit bind to a random available port. That is what you are seeing, and that it typical usage. Most clients do not need to call bind() before connect(), but there are use cases where doing so is necessary, so don't rule it out.
For one of my classes I have to program a server and a client, and we were given some sample code to work with. Here is the snippet I am confused about:
main()
{
int sock, sock_current, cc, fromlen, tolen; /*sd is the socket */
int addrlen;
struct sockaddr_in sin;
struct sockaddr_in pin;
/* get an internet domain socket */
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
/* complete the socket structure */
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(PORT);
/* bind the socket to the port number */
if (bind(sock, (struct sockaddr *) &sin, sizeof(sin)) == -1) {
perror("bind");
exit(1);
}
I think that the purpose of the sockaddr_in struct sin is to store a local IP address to associate with sock when it gets bound. Am I correct on that? If I am correct, how does this snippet of code accomplish that? I don't get it:
/* complete the socket structure */
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(PORT);
The bind function assigns a local protocol address to a socket. The purpose of sin here is to tell bind which local address to assign.
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET; //it's an IPv4 address
sin.sin_addr.s_addr = INADDR_ANY; //wildcard IP address
sin.sin_port = htons(PORT); //bind to this port number
In addition to what Yu said (which is all correct), if you don't call bind before calling listen() (which is likely right after the snippet you posted), it will listen on a random TCP port (because you opened an IPv4 TCP socket when you called socket()).
This is actually useful sometimes -- I have an app that broadcasts the port it runs on over the LAN for clients to find it, so it doesn't matter what port it's on.
Also, you can bind before you call connect(), if you want, to force what port or interface the outgoing connection will be made on, but this is also uncommon.
I have a socket server running on multiple machines. It works like a charm besides on one machine.
The server binds correctly but returns an error (EFAULT) when the client attempts to connect.
Perhaps someone has an idea what the source of the problem might be. Thanks a lot in advance!
Some information about the machine:
Linux version 2.6.18.3
gcc version 3.3.5 (Debian 1:3.3.5-13)
The socket server source is pretty straight forward.
...
...
struct sockaddr_in server_addr;
struct sockaddr* client;
socklen_t alen;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
...
}
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(port);
if(bind(sockfd, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0){
...
}
if(listen(sockfd,BACKLOG) == -1){
...
}
alen = sizeof(client);
new_fd = accept(sockfd, client, &alen);
if (new_fd == -1) {
/*
* this part of the code is executed
* errno is set to 14
*/
}
Thank you for pointing me in the right direction.
Use this:
struct sockaddr_in client;
...
alen = sizeof(client);
new_fd = accept(sockfd, (struct sockaddr *) &client, &alen);
accept expects a pointer to an existing buffer which it'll fill in. You have two errors, you set alen to the size of a pointer, and you pass an uninitialized pointer to accept.
From the accept(2) man page:
EFAULT The addr argument is not in a writable part of the user address
space.
Check to make sure that you've allocated client appropriately.
I have a network server application written in C, the listener is bound using INADDR_ANY so it can accept connections via any of the IP addresses of the host on which it is installed.
I need to determine which of the server's IP addresses the client used when establishing its connection - actually I just need to know whether they connected via the loopback address 127.0.0.1 or not.
Partial code sample as follows (I can post the whole thing if it helps):
static struct sockaddr_in serverAddress;
serverAddress.sin_family = AF_INET;
serverAddress.sin_addr.s_addr = INADDR_ANY;
serverAddress.sin_port = htons(port);
bind(listener, (struct sockaddr *) &serverAddress, sizeof(serverAddress));
listen(listener, CONNECTION_BACKLOG);
SOCKET socketfd;
static struct sockaddr_in clientAddress;
...
socketfd = accept(listener, (struct sockaddr *) &clientAddress, &length);
The solution to my specific problem (thanks to zildjohn01) in case anyone needs it, is shown below:
int isLocalConnection(int socket){
struct sockaddr_in sa;
int sa_len = sizeof(sa);
if (getsockname(socket, &sa, &sa_len) == -1) {
return 0;
}
// Local access means any IP in the 127.x.x.x range
return (sa.sin_addr.s_addr & 0xff) == 127;
}
You can use the getsockname function.
The getsockname() function retrieves the locally-bound name of the specified socket
From your code
socketfd = accept(listener, (struct sockaddr *) &clientAddress, &length);
Analyse the returned clientAddress. This is what you need.