Query on the socket() function [closed] - c

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
Am I correct in my understanding that this will utilise a local port for this socket, and can anyone clarify which port it decides to use? Is there a way to control which local port the socket is opened on?

This will just create an AF_INET (ipv4) socket that does TCP. Once you call connect it will bind to a port, if not already done so via bind. If you want to pick a port number yourself, just bind manually.

Use bind to control which local port you use. You can optionally also use it to choose which network interface to use.
The following code selects port 12345 on all available interfaces
struct sockaddr_in addr;
addr.sin_family = 2;
addr.sin_addr.s_addr = INADDR_ANY;
addr.in_port = htons(12345);
int err = bind(socket, (struct sockaddr*)&addr, sizeof(addr));
If you don't care which port you use, port 0 is treated as a special case where the network stack chooses an(y) available port

The freshly created socket does not have an address until you bind(), listen(), or connect() it.
If you want to connect() or listen() on that socket, you don't necessarily have to bind to an address and port first; one will be automatically assigned. However, if you're trying to run a server that others will connect to you will probably want to first bind() to a known address and port. Sometimes you want to connect out from a particular address and port, and you here you also have to bind() first.
If you want to find the address to which an existing socket is bound, use getsockname().

Read socket(2) and and ip(7) man pages and some tutorial on Linux sockets. You also need to call the bind(2) syscall to bind to some particular port.

Related

Raw sockets receiving messages sent by itself

I was trying to write some codes using raw sockets, while I observed some strange phenomenon. Consider the code:
int rsfd = socket(AF_INET,SOCK_RAW,253);
if(rsfd<0)
{
perror("Raw socket not created");
}
else
{
struct sockaddr_in addr2;
memset(&addr2,0,sizeof(addr2));
addr2.sin_family = AF_INET;
addr2.sin_addr.s_addr = inet_addr("127.0.0.2");
/* if(connect(rsfd,(struct sockaddr*)&addr2,sizeof(addr2))<0)
{
perror("Could not connect");continue;
} */
}
Now if I remove the commented portion, whatever message I am sending through this rsfd is also being received by itself. On the other end I have already bound a socket with the ip address 127.0.0.2. When I printed the ip address of the sender socket, it is printing 127.0.0.1 but still it is receiving packets which is meant for 127.0.0.2. This problem was solved when I added that connect request which is mentioned in the commented portion. This seems weird because on the other side, no one is accepting or listen on this address and moreover, I am using sendto and recvfrom functions for sending and receiving packets which is used for connection less sockets. My question is, why is this happening? How is this connect request solvong the problem here?
Now if I [don't connect() the socket], whatever message I am sending through this rsfd is also being received by itself.
I note first that raw sockets are an extension to POSIX. Linux offers them, and I think other systems do too, but details of their behavior are not certain to be consistent across implementations.
With that said, the problem seems likely to be that you are not bind()ing your socket to any address. On Linux, for example, the docs for raw sockets note that
A raw socket can be bound to a specific local address using the
bind(2) call. If it isn't bound, all packets with the specified IP
protocol are received.
(Emphasis added.) On a system where raw sockets have that behavior, if you're sending packets to an IP loopback address via a raw IP socket that is neither bound nor connected then yes, the source socket will receive them, or at least may do.
It's unclear why connecting the socket solves the problem, or why it is even successful at all. The behavior of connect() is unspecified for socket types other than the standard ones, SOCK_DGRAM, SOCK_STREAM, and SOCK_SEQPACKET. However, the behavior you observe is consistent with connect() having an effect on raw sockets like that it has on datagram sockets, which are also connectionless:
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.
Instead of relying on that discovered behavior, however, I suggest following the documented (at least on Linux) procedure of binding the socket to an address (including a port), and communicating with it at that address.

what is significance of bind to zero address

I was seeing EADDRNOTAVAIL errors in connect() calls. I dig deeper found that naming of sockets were being done of over zero ip addresses . See following where both calls were sucessful:-
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&y, sizeof(y)); /* y is int with value 1 */
bind(s, (struct sockaddr *)lockaddr, sizeof(rtinetaddr_tp));
where
lockaddr={.sin_family=2, .sin_port=0, .sin_addr={.s_addr=0}, .sin_zero=""}
This, I found in RH site and also I have the same kernel.
My question is what if I remove doing any bind() at client side of the application? Will that be a quick cure OR will lead to any disaster?
Other way I have running sample programs without bind at client. But the app I am talking about that establishes hundreds of connections. So what may happen in worst case?
Binding to a zero address is the same as binding to INADDR_ANY (which is defined as zero). This means you can make a connection on any local IP address (server side) or use the egress interface IP address (client side). This is quite normal.
If you are not interessed in using any particular address:port on the client side, the calls to bind() aren't necessary.
The Kernel will chose the suitable interface and a random port to establish the outgoing connection initiated by the client's call to connect().

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.

How to ensure that a server listens on IPv6 if possible and IPv4 otherwise?

I am trying to write a server application that listens to both IPv6 and IPv4 connections. The proper way to accomplish this seems to be listening on IPv6 address, which will also accept IPv4 connections.
The relevant piece of code is:
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
getaddrinfo(NULL, MYPORT, &hints, &res);
(pretty much copypasted from Beej's Guide)
The problem is that at least on my system, getaddrinfo returns an entry with AF_INET first and AF_INET6 second -- whereas client's getaddrinfo returns AF_INET6 first, as per spec. With my naive approach, server picks IPv4, client picks IPv6 and the connection fails.
I tried to fix this by setting hints.ai_family = AF_INET6, but that fails on systems where IPv6 is not available.
I see two obvious solutions:
a) try asking for IPv6 first and fall back to IPv4 if that fails, or
b) walk through results of getaddrinfo, look for IPv6, and if is not present, pick the first entry
but i don't like either one too much ;) I feel that there should be a way to convince getaddrinfo to do the right thing, or perhaps a different way to accomplish my goal.
The order of the address that getaddrinfo() returns is unspecified, so you have to be prepared to handle either case. That probably means traversing the list, keeping track of the "best address seen so far".
Alternatively, you could try to bind() and listen() on all the addresses returned by getaddrinfo(). This is probably the best option, since some OSes do not accept IPv4 connections to IPv6 sockets listening on 0::0.
Your code should work the way you described. Unfortunately, there's a bug in glibc as described in launchpad bug #673708, which causes it to choose IPv4 first.
Computer configuration solution
There is a work-around which can be done on each Linux computer on which you're running your server program: edit /etc/gai.conf, enable all the default rules (uncomment them):
label ::1/128 0
label ::/0 1
label 2002::/16 2
label ::/96 3
label ::ffff:0:0/96 4
label fec0::/10 5
label fc00::/7 6
label 2001:0::/32 7
then add:
label ::ffff:7f00:1/128 8
Then your code should open IPv6 if supported, and will also accept IPv4 connections.
Code solution
If the above is not practical (it's only practical if you're willing to change the configuration on every computer you run on), then modify your code to prefer IPv6. E.g. I've done this:
Do three passes through the getaddrinfo() results.
The first pass, prefer IPv6. Attempt to clear the IPV6_V6ONLY socket option to support both IPv6 and IPv4.
The second pass, prefer IPv4.
The third pass, take whatever is available.

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