UDP Server works only on local network - c

I'm trying to run an UDP Client-Server message exchange program for a university course, when I try it in a local network even with different PCs works really fine. But the moment I try to run it on different internet connections it seems like the server doesn't receive anything. I am running Ubuntu and allowed the specific port for UDP connection but maybe I'm missing something else
Server side:
int sockfd;
struct sockaddr_in servaddr;
//creating socket file descriptor
if( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0){
perror("socket creation failed");
exit(EXIT_FAILURE);
}
memset(&servaddr, 0 , sizeof(servaddr));
//filling server information
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_port = htons(PORT);
//bind the socket with server address
if( bind(sockfd,(const struct sockaddr *) &servaddr ,sizeof(servaddr)) < 0){
perror("bind failed");
exit(EXIT_FAILURE);
}
Client side:
int main(int argc, char ** argv) {
int sockfd;
char username[MAXLENGHT];
struct sockaddr_in servaddr;
//creating socket file descriptor
if( (sockfd = socket(AF_INET,SOCK_DGRAM, 0)) < 0 ){
perror("socket creation failed!");
exit(EXIT_FAILURE);
}
memset(&servaddr,0, sizeof(servaddr));
//filling server info
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
servaddr.sin_addr.s_addr = inet_addr(argv[1]);
I am using as address 192.168.1.179 and the port I am using is 8080

... when I try it in a local network even with different PCs works really fine.
For this reason I doubt that it is a problem in your program.
maybe I'm missing something else
First of all, most internet connections today use a NAT.
This means that one internet access (e.g. at your home) has one IP address in the internet (called the "global address") and multiple computers share that IP address.
The computer's IP address (e.g. 192.168.1.179) is only valid in the local network; in other local networks, there are other computers having that address.
If you send a UDP packet to the IP address of the computer (192.168.1.179), both computers must be in the same local network.
If you send a UDP packet to the "global IP address" of the internet access, the router does not know which computer shall receive the packet because all computers in the local network share the same "global address".
You may configure your router (e.g. WLAN router) in a way that it knows that UDP packets from the internet to port 8080 shall be sent to the computer 192.168.1.179. This is called "port forwarding".
The sending computer must send the UDP packet to the "global IP address" of the internet access, not to the IP address of the computer (192.168.1.179) in this case.
And if it's not your internet access (e.g. it is not your WLAN router), you already have a problem here.
However, because this has nothing to do with programming, it is out of scope on this web site; you might ask further questions on the SuperUser web site, which also belongs to the StackExchange network. Your account (user name and password) is valid on all StackExchange web sites.
Today, many internet connections even use CGNAT.
This means that even multiple customers share one IP address in the internet.
In this case, it depends on your internet provider if it is possible at all to receive UDP packets:
If your internet access shares the IP address with another person that also wants to receive UDP packets on port 8080, there is a problem...

Related

Linux, C, socket: how to specify TCP client port with structure sockaddr_storage

I am trying to create Linux tool with multiple TCP connections, which supports both IPv4 and IPv6 so I choose to use "sockaddr_storage".
Now, my question is, how do I bind client side socket to a specified (or random) TCP port?
For TCP client side, in one thread, if I just create 10 sockets and then connect() to server, then those 10 sockets will use sequential TCP ports in client side, for example, starting from 54594, then 54596, 54600, 54602, etc.
Now, I would like to bind those client sockets to different (randomized) TCP ports, how do I do with sockaddr_storage?
Thanks!
=============adding code ============
struct sockaddr_storage local_addr;
sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)
(*(struct sockaddr_in*)&local_addr).sin_port = 0;
local_addr_size = sizeof(local_addr);
bind(sockfd, (struct sockaddr *)&local_addr, local_addr_size);
............
connect(sockfd, p->ai_addr, p->ai_addrlen)
I would like to bind those client sockets to different (randomized) TCP ports
That happens automatically when you call connect() without calling bind() first. You don't need to write any code for this, and sockaddr_storage therefore doesn't come into it at all.

Socket bind with wildcard ip

I have a created a UDP socket and bind that socket to inaddr_any (0.0.0.0) and and some
well known port number. As per my understanding this socket can receive data over all the interfaces of the machine over the specified port number.
But When i will call send() it will use the default IP address as the source address.
How is the default IP address chosen?
If I want to use some other interface (other than the default) for sending the data, how can this be done?
Context of the problem:
I am implementing LDP protocol. It can have many hello adjacencies. Thus i am creating a server to recv data from the other interfaces of the router. Once the hello adjacency is formed, then hello messages are to sent be on the specific interface over UDP over which the hello adjacency is created.
The default IP address is chosen based on the network the packet is sent to. For example if you have two interfaces, one connected to network A and the other connected to network B, if you send a packet to network B the packet will be sent with the IP address of the second interface. For this reason, most of the time you don't have to worry about it.
If you have two network interfaces connected to the same network, you can bind the socket to the address of one of them, and the packet will go out with that address. For example, this will bind an IP socket to 192.168.122.1, if allowed by the network stack:
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("192.168.122.1");
addr.sin_port = 0;
if (bind(s, (struct sockaddr*) &addr, sizeof addr) == -1) {
perror("bind");
}

C bind to a specified TCP port

i have created a Linux network app with C and it kind of works
except that it every time i run it , it binds to a new Random port
//Create Socket
int socket_desc;
socket_desc=socket(AF_INET,SOCK_STREAM,0);
if (socket_desc==-1)
perror("Create socket");
struct sockaddr_in address;
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
//Port defined Here:
address.sin_port=htons(81);
//Bind
bind(socket_desc,(struct sockaddr *)&address,sizeof(address));
listen(socket_desc,32);
//Do other stuff (includes accepting connections)
as you can see i have specified port but it still chooses a free Random port
any help or link to a good tutorial on this is appreciated
You need to use port number greater than 1024. Port numbers less then 1024 are reserved ports and are used by standard services.
There are two reasons of this behaviour (when you specify port, but system binds socket to a random one):
If you ask for port below 1024. This is certainly your case
If you forgot to use htons() function. In this case bytes of port number are used in wrong order and that leads to #1.

multicast bind - Address already in use

I try to do bind a multicast port in my app. Previously the code always worked, but on this server it (often, but not always) fails...
The error message is Address already in use, which I don't quite understand, as it's possible to bind the same address from multiple applications (and even from the same application)...
What could cause this? I know someone would ask for it, so here is the code:
int fd = socket(PF_INET, SOCK_DGRAM, 0);
/* yes, that's a valid socket, verified.... */
u_int val = 1;
if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
perror("Reusing ADDR failed");
exit(1);
}
struct sockaddr_in saddr;
saddr.sin_family = PF_INET;
saddr.sin_addr.s_addr = inet_addr(multicast_group_ip);
saddr.sin_port = htons(port);
/* yes, valid multicast ip address and port, verified */
if(bind(fd, (struct sockaddr *) &saddr, sizeof(struct sockaddr_in)) == -1)
//FAILS....
You can actually have multiple datagram sockets bound to the same multicast group and port. However, all of these sockets should set the SO_REUSEADDR option. Based on your code you seem to be doing this, but it sounds like there is another process on your server that has bound a socket to the same multicast group and port without setting that option. The solution would be to ensure that all the processes on this particular server which are binding sockets to that multicast group and port set the SO_REUSEADDR option.
EDIT:
To respond to your recent comments above, one way you can actually reproduce this is to create two simple multicast listening programs that both bind a datagram socket to the same port and group. Have one of the programs set the SO_REUSEADDR option but not the other. Run the program that does not have SO_REUSEADDR set and you should see multicast data coming through. While leaving this program up, run the second program that does have SO_REUSEADDR set and you should see that it will not receive any multicast data while the first program is still receiving it (this should replicate the problem you originally described).
Finally, shut down both programs, then modify the first program to set SO_REUSEADDR, and repeat the steps above. You should now see both programs receiving the multicast traffic.
It's possible to have multiple open sockets on the same host:port from the one process, it's impossible to have more than process to be listening (i.e., bound) to the same host:port.
Perhaps, you have previous instance of your server process unkilled.
Another option mentioned by Wug is that you trying to bind to port lower than 1024 while not being root. Range of low ports 1-1024 is reserved for applications with effective UID == 0, e.g., started by root. seems to be wrong assumption since you'd get different error in such case, not already in use.

Unix Domain Socket: Using datagram communication between one server process and several client processes

I would like to establish an IPC connection between several processes on Linux. I have never used UNIX sockets before, and thus I don't know if this is the correct approach to this problem.
One process receives data (unformated, binary) and shall distribute this data via a local AF_UNIX socket using the datagram protocol (i.e. similar to UDP with AF_INET). The data sent from this process to a local Unix socket shall be received by multiple clients listening on the same socket. The number of receivers may vary.
To achieve this the following code is used to create a socket and send data to it (the server process):
struct sockaddr_un ipcFile;
memset(&ipcFile, 0, sizeof(ipcFile));
ipcFile.sun_family = AF_UNIX;
strcpy(ipcFile.sun_path, filename.c_str());
int socket = socket(AF_UNIX, SOCK_DGRAM, 0);
bind(socket, (struct sockaddr *) &ipcFile, sizeof(ipcFile));
...
// buf contains the data, buflen contains the number of bytes
int bytes = write(socket, buf, buflen);
...
close(socket);
unlink(ipcFile.sun_path);
This write returns -1 with errno reporting ENOTCONN ("Transport endpoint is not connected"). I guess this is because no receiving process is currently listening to this local socket, correct?
Then, I tried to create a client who connects to this socket.
struct sockaddr_un ipcFile;
memset(&ipcFile, 0, sizeof(ipcFile));
ipcFile.sun_family = AF_UNIX;
strcpy(ipcFile.sun_path, filename.c_str());
int socket = socket(AF_UNIX, SOCK_DGRAM, 0);
bind(socket, (struct sockaddr *) &ipcFile, sizeof(ipcFile));
...
char buf[1024];
int bytes = read(socket, buf, sizeof(buf));
...
close(socket);
Here, the bind fails ("Address already in use"). So, do I need to set some socket options, or is this generally the wrong approach?
Thanks in advance for any comments / solutions!
There's a trick to using Unix Domain Socket with datagram configuration. Unlike stream sockets (tcp or unix domain socket), datagram sockets need endpoints defined for both the server AND the client. When one establishes a connection in stream sockets, an endpoint for the client is implicitly created by the operating system. Whether this corresponds to an ephemeral TCP/UDP port, or a temporary inode for the unix domain, the endpoint for the client is created for you. Thats why you don't normally need to issue a call to bind() for stream sockets in the client.
The reason you're seeing "Address already in use" is because you're telling the client to bind to the same address as the server. bind() is about asserting external identity. Two sockets can't normally have the same name.
With datagram sockets, specifically unix domain datagram sockets, the client has to bind() to its own endpoint, then connect() to the server's endpoint. Here is your client code, slightly modified, with some other goodies thrown in:
char * server_filename = "/tmp/socket-server";
char * client_filename = "/tmp/socket-client";
struct sockaddr_un server_addr;
struct sockaddr_un client_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sun_family = AF_UNIX;
strncpy(server_addr.sun_path, server_filename, 104); // XXX: should be limited to about 104 characters, system dependent
memset(&client_addr, 0, sizeof(client_addr));
client_addr.sun_family = AF_UNIX;
strncpy(client_addr.sun_path, client_filename, 104);
// get socket
int sockfd = socket(AF_UNIX, SOCK_DGRAM, 0);
// bind client to client_filename
bind(sockfd, (struct sockaddr *) &client_addr, sizeof(client_addr));
// connect client to server_filename
connect(sockfd, (struct sockaddr *) &server_addr, sizeof(server_addr));
...
char buf[1024];
int bytes = read(sockfd, buf, sizeof(buf));
...
close(sockfd);
At this point your socket should be fully setup. I think theoretically you can use read()/write(), but usually I'd use send()/recv() for datagram sockets.
Normally you'll want to check error after each of these calls and issue a perror() afterwards. It will greatly aid you when things go wrong. In general, use a pattern like this:
if ((sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
perror("socket failed");
}
This goes for pretty much any C system calls.
The best reference for this is Steven's "Unix Network Programming". In the 3rd edition, section 15.4, pages 415-419 show some examples and lists many of the caveats.
By the way, in reference to
I guess this is because no receiving process is currently listening to this local socket, correct?
I think you're right about the ENOTCONN error from write() in the server. A UDP socket would normally not complain because it has no facility to know if the client process is listening. However, unix domain datagram sockets are different. In fact, the write() will actually block if the client's receive buffer is full rather than drop the packet. This makes unix domain datagram sockets much superior to UDP for IPC because UDP will most certainly drop packets when under load, even on localhost. On the other hand, it means you have to be careful with fast writers and slow readers.
The proximate cause of your error is that write() doesn't know where you want to send the data to. bind() sets the name of your side of the socket - ie. where the data is coming from. To set the destination side of the socket, you can either use connect(); or you can use sendto() instead of write().
The other error ("Address already in use") is because only one process can bind() to an address.
You will need to change your approach to take this into account. Your server will need to listen on a well-known address, set with bind(). Your clients will need to send a message to the server at this address to register their interest in receiving datagrams. The server will recieve the registration messages from clients using recvfrom(), and record the address used by each client. When it wants to send a message, it will have to loop over all the clients it knows about, using sendto() to send the message to each one in turn.
Alternatively, you could use local IP multicast instead of UNIX domain sockets (UNIX domain sockets don't support multicast).
If the question intended to be about broadcasting (as I understand it), then according to unix(4) - UNIX-domain protocol family, broadcasting it is not available with UNIX Domain Sockets:
The Unix Ns -domain protocol family does not support
broadcast addressing or any form of "wildcard" matching
on incoming messages. All addresses are absolute- or
relative-pathnames of other Unix Ns -domain sockets.
May be multicast could be an option, but I feel to know it's not available with POSIX, although Linux supports UNIX Domain Socket multicast.
Also see: Introducing multicast Unix sockets.
It will happen because of
server or client die before unlink/remove for bind() file associate.
any of client/server using this bind path, try to run server again.
solutions :
when you want to bind again just check that file is already associate then unlink that file.
How to step :
first check access of this file by access(2);
if yes then unlink(2) it.
put this peace of code before bind() call,position is independent.
if(!access(filename.c_str()))
unlink(filename.c_str());
for more reference read unix(7)
Wouldn't it be easier to use shared memory or named pipes? A socket is a connection between two processes (on the same or a different machine). It isn't a mass communication method.
If you want to give something to multiple clients, you create a server that waits for connections and then all the clients can connect and it gives them the information. You can accept concurrent connections by making the program multi-threaded or by forking processes. The server establishes multiple socket-based connections with multiple clients, rather than having one socket that multiple clients connect to.
You should look into IP multicasting instead of Unix-domain anything. At present you are just trying to write to nowhere. And if you connect to one client you will only be writing to that client.
This stuff doesn't work the way you seem to think it does.
You can solve the bind error with the following code:
int use = yesno;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&use, sizeof(int));
With UDP protocol, you must invoke connect() if you want to use write() or send(), otherwise you should use sendto() instead.
To achieve your requirements, the following pseudo code may be of help:
sockfd = socket(AF_INET, SOCK_DGRAM, 0)
set RESUSEADDR with setsockopt
bind()
while (1) {
recvfrom()
sendto()
}

Resources