about setsockopt() and getsockopt() function - c

for what especially the socket options are used i.e setsockopt() and getsockopt() in socket programming ?

For example you want to set or know receive buffer size
1)
int skt, int sndsize;
err = setsockopt(skt, SOL_SOCKET, SO_RCVBUF, (char *)&sndsize,
(int)sizeof(sndsize));
err = getsockopt(skt, SOL_SOCKET, SO_RCVBUF, (char *)&sockbufsize, &size);
2) Reuse address
int on = 1;
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)

For many different things including changing the size of send and receive buffers, length of timeouts, multicasting, keeping the connection alive, disabling Nagel algorithm, etc.
There are levels of options depending on what network layer you what to interact with: socket itself, IP, TCP, and so forth.

As already mentioned they are used for setting/getting various options for a socket.
For example, if you are testing a server application that crashes, you don't wont to wait a certain number of minutes before the kernel let you reuse the port avoiding the "Address already in use" error messages. This can be avoided if you use the SO_REUSEADDR option, letting other sockets to bind to the same port unless there is an active listener bound already.
You can also retrieve data about a socket, such as the number of lost packets / retransmissions etc by using the TCP_INFO on linux machines.
Basically, you can configure all the fine settings.
Options for setsockopt(2) and getsockopt(2).

Superficially, sockets look like a bidirectional pipe which is useful because standard system calls such as write, read, close can be used on them just like on normal pipes or even files. Even if you add socket-specific calls (listen, connect, bind, accept), there is a useful level of abstraction that hides away details in favor of the notion of streaming or datagram sockets.
But as soon as protocol-specific details come into play and specific settings need to be tuned (for example send/receive buffers, timeout settings), a very generic interface is needed to account for the different settings and their specific data formats. getsockopt, setsockopt are part of this generic interface.
int getsockopt(int sockfd, int level, int optname,
void *optval, socklen_t *optlen);
int setsockopt(int sockfd, int level, int optname,
const void *optval, socklen_t optlen);
The protocol-specific options are selected using level and optname and the protocol-specific data is hidden in a buffer, so the two system calls do not need to know anything about the settings of every protocol the OS may support -- it's enough if your application and the actual protocol implementation know about those details.

Related

What is the difference between setsockopt and ioctl with SIOCSIFFLAGS?

To set a network interface to promiscuous mode, for example, one can use setsockopt as
struct packet_mreq opt;
opt.mr_ifindex = the_very_interface_index;
setsockopt(socket_fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, (void*)&opt, sizeof(opt));
On the other hand, as packet(7) suggested, one can also use ioctl with SIOCSIFFLAGS option, like
struct ifreq req;
strcpy(req.ifr_name, the_very_interface_name);
ioctl(socket_fd, SIOCGIFFLAGS, &req);
req.ifr_flags |= IFF_PROMISC;
ioctl(socket_fd, SIOCSIFFLAGS, &req);
I understand these two ways are completely equivalent, but is there any difference? Otherwise, why is there two ways to do the same thing?
There is very little difference between the two, as can be seen by perusing the source. Specifically, consider callers of __dev_set_promiscuity.
The setsockopt interface eventually calls dev_set_promiscuity.
The ioctl interface ends up calling dev_change_flags.
There has always been some duplication of mechanisms due to the file descriptor interface to devices. For example send() vs write(). To be honest, I have never thought too deeply about it. I imagine ioctl interfaces are a natural thing to add for generic devices, and setsockopt interfaces are natural to add for sockets, so both end up existing. You could think of sockets as a higher level abstraction over the network device, so a higher level interface to modify options would not be an unreasonable addition.

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 use select function when you have UDP socket

I want to make a multi client - one server quiz application. In this, firstly, the clients will connect to the server and will registered themselves. Then, the server will multicast a question to every client, who have registered themselves to the server. The clients will then respond with the answer, which will be send only to the server. And then server will send the the score of each client to the respective client.
This is what I am trying to do in the above application-
1. As I have too multicast, thats why I am Making my server socket asSOCK_DGRAM (i.e.,UDP). Then I am using CLASS-D ip address, for making a group( to which server will multicast). Then is using setsockopt, I am adding the clients to this group, so that they can recieve the question.
2.As I want to listen the answers from all the clients, so I was thinking of using select. It uses the socket descriptor to select between various clients, as to know which is ready for reading.
But the problem is, when I am using SOCK_DGRAM socket, it doesnot perform listen and accept functionality. So, I will not get a socket descriptor(which is returned by accept). Thats why, I will not be able to use select(as it uses only file descriptors).
So, how am I to proceed, as I want to use UDP functionality - MULTICASTING, as well as TCP functionality - a socket descriptor for each connection.
Even when using UDP and unconnected sockets, you can still use functions like select. Simply bind the server socket to an address, and use that socket for select. When the socket is readable a client has sent something with e.g. sendto and you can do e.g. recvfrom.
However, I would really recommend you to use TCP sockets, it will make many things simpler, especially when it comes to the communication protocol (remember that UDP packages can be lost or come out of order, you have to handle that yourself).
As you said, select is not usefull here since you only have one socket on the server side.
This socket is used to send datagrams with sendto
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
in dest_addr you specify the destination address for the datagram.
Using recvfrom(2) on a UDP socket is similar :
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
src_addr is the sender address, so you are able to identify the client which has sent the response.
recvfrom calls are blocking until data are available for reading (unless you set the socket to unblocking).
You could just loop to receive all the responses.
You're on the right track but you don't need listen() or accept(). Just select for readability. When the socket becomes readable, read it. You probably don't need select() for this at all, really, just a blocking read, with a timeout if you like.

Streaming on UDP

I have the following issue here: I want to write a server streaming data on a UDP socket on a specific port, and clients should be able to connect to it and receive the data that is being sent out without too much hassle: they just connect, and from the moment they start they should get data using recvfrom from the server.
I have some problems with setting up the network related parts. So, here is a rough piece of code that I try to make work:
int udpSock = socket(AF_INET, SOCK_DGRAM, 0);
if(udpSock == -1)
{
perror("Could not create audio output socket");
exit(1);
}
struct sockaddr_in *sin = (struct sockaddr_in*)&gOutgoingAddr;
sin->sin_port = htons(40200);
if(bind(udpSock, (const sockaddr*)sin, sizeof(struct sockaddr_in)) == -1)
{
perror("Cannot bind audio socket");
exit(1);
}
int buffer_size = 0;
char* data = get_next_buffer(&buffer_size);
while(buffer_size > 0)
{
if(sendto(udpSock, (const void*)(data), buffer_size, 0, NULL, 0) == -1)
{
perror("sendto failure");
}
data = get_next_buffer(&buffer_size);
}
Do not worry about the gOutgoingAddr variable, it is obtained correctly using getifaddrs, it is valid. I am troubled regarding the parametrization of the sendto method, becasue right now the output of the application is:
sendto failure: Destination address required
That's true, because I don't have a destination address, since all the examples I have found till now show when the server gets a client connection, and there is the address. But since I don't have a client yet connected, I'd still want to stream out.
I appreciate all help, I have no idea what Ishould put for the parameters of sendto:
The gOutgoingAddress which is the address where I create the socket? I have tried this, but if I use the tcpdump linux command on the specified port, I get nothing.
Should I create a multicast socket? This somehow makes no sense...
Something else?
Thanks,
frc
You cannot stream out to "nowhere". Streaming data via UDP is not multicast. That means if you have 100 clients connected, you must send exactly the same data 100-times, once to each of the clients that shall receive it. Multicast was not really part of the initial IPv4 design. It has been added later on and is not widely supported. This is contrary to IPv6, where multicast has been part of the initial design. The only thing you could do it broadcast the traffic within your local network. This will only work if all clients are in your local network segment. To broadcast your server would simply send the data to 255.255.255.255 and to a fixed UDP port. All clients then have to listen on that specific port and will receive the data. Please note, that on most systems you need special permissions for broadcasting (e.g. it is not common that only programs running with root privileges are allowed to broadcast traffic, as broadcasts pollute your network, since all broadcast packets are sent to all clients in the network, whether they care for them or not). Without broadcasts, you have only unicast and unicast means one sender, one receiver. For one sender multiple receiver, you must send out the same data multiple times to multiple addresses.
What is audioUdpSock by the way?
Shoudn't you be using udpSock instead?
Do a recvfrom in your server, and have the client send a message (with whatever content you want, this is just a way to establish the connection, a greeting). Then the server will have the client address from the recvfrom, and can send packet to it.
As UDP socket are connection-less (there is no need for accept and connect when using UDP socket), you need to have another way to inform the server of the existence of the client (and the client need to have an out-of-bound way to know the server address, generally, the user give it, or it is hard-coded).
If you can have multiple clients, then you'll have to use select, poll, ... on the socket to know when it is safe to call recvfrom without blocking (or you could configure your socket to be non-blocking).
Edit: I highly recommend Beej's Guide to Network Programming to everyone, and for your question, you can directly go to the sample usage of Datagram Socket.

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