I have a server implementation where I need 2 separate sockets - 1 IPv4 socket socket listening on a particular IPv4 address and server port X, and an IPv6 socket listening on a particular IPv6 address and same server port X. The IPv4 and IPv6 addresses are on the same interface.
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(v4addr);
sin.sin_port = htons(tcp_port);
I am using evconnlistener_new_bind to create ipv4 socket and bind to it.
For IPv6 listener, the code is as below.
memset(&sin6, 0, sizeof(sin6));
sin6.sin6_family = AF_INET6;
memcpy(sin6.sin6_addr.s6_addr, v6addr_bytes, IPV6_ADDR_LEN);
sin6.sin6_port = htons(tcp_port);
fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
evutil_make_socket_nonblocking(fd)
setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void*)&on, sizeof(on))
setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&on, sizeof(on))
evutil_make_listen_socket_reuseable(fd) /* Libevent call to set SO_REUSEADDR */
evutil_make_socket_nonblocking(fd) /* Libevent call to set fd non-blocking */
bind(fd, (const struct sockaddr *)&sin6, sizeof(sin6))
As I bind my fd to the particular ipv6 address, I see a bind failure intermittently.
bind v6 failed sin6 3ffe::a00:513 - errno 99 - Cannot assign requested address
I tried to gdb in, but every time I gdb in, the bind succeeds.
I am not sure why I am seeing this problem. Can someone please help?
By default, after a socket is bound to a TCP port, the port remains reserved for one minute when the socket is closed — this is called the TCP TIME_WAIT state. TIME_WAIT avoids some race conditions that could cause data corruption, but it is usually safe to ignore TIME_WAIT on the server side.
This is done by setting the SO_REUSEADDR socket option:
int one = 1;
rc = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))
Related
Below is basic code to create a multicast socket on Linux.
I have multiple processes running the below code on one machine, each listening to a different multicast channel. Only the relevant data should be processed by each process.
Two stages in the code require an address, or INADDR_ANY.
Given I will have multiple separate multicast channels running, I'm unsure when I should use INADDR_ANY or specify the address. I don't want a process receiving the wrong multicast data.
// Create socket
int sock = socket(AF_INET, SOCK_DGRAM, 0);
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
// Create multicast group
sockaddr_in mcast_group
memset(&mcast_group, 0, sizeof(mcast_group));
mcast_group.sin_family = AF_INET;
mcast_group.sin_port = htons(mcastPort);
mcast_group.sin_addr.s_addr = INADDR_ANY; // INADDR_ANY or specific address?
// Bind socket to multicast group
bind(sock, (struct sockaddr*)&mcast_group, sizeof(mcast_group));
// Tell Kernel to join multicast group
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr(group.c_str());
mreq.imr_interface.s_addr = inet_addr(interface.c_str()); // INADDR_ANY or specific address?
setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
If each socket is listening only for multicast packets and not unicast, and only for a single multicast address, you can bind directly to the multicast address:
sockaddr_in mcast_group;
memset(&mcast_group, 0, sizeof(mcast_group));
mcast_group.sin_family = AF_INET;
mcast_group.sin_port = htons(mcastPort);
mcast_group.sin_addr.s_addr = inet_addr(group.c_str()); // bind to multicast group
bind(sock, (struct sockaddr*)&mcast_group, sizeof(mcast_group));
Note that you'll still have to join the multicast group.
bind to INADDR_ANY will receive unicast as well as multicast packets. bind to the multicast address will only receive the multicast packets. THIS IS the different between Linux socket and Windows socket programming for multicast receiving.
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 am trying to modify a multicast listener / sender example to bind the UDP / multicast socket to a specific interface and not using the INADDR_ANY macro.
I possess the IPv4 address of the interface.
I tried the following, but the socket does not receive any UDP (unicast, broadcast, multicast) packets.
struct sockaddr_in addr;
int fd, nbytes;
socklen_t addrlen;
struct ip_mreq mreq;
// my_ipv4Addr equals current IP as String, e.g. "89.89.89.89"
// create what looks like an ordinary UDP socket */
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket");
exit(1);
}
// set up addresses
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
// [-] addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_addr.s_addr = inet_addr(my_ipv4Addr);
addr.sin_port = htons(port);
// bind socket
if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
perror("bind");
exit(1);
}
// use setsockopt() to request that the kernel join a multicast group
mreq.imr_multiaddr.s_addr = inet_addr(group);
// [-] mreq.imr_interface.s_addr = htonl(INADDR_ANY);
mreq.imr_interface.s_addr = inet_addr(my_ipv4Addr);
if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq))< 0) {
perror("setsockopt");
exit(1);
}
Edit:
Let me explain the purpose of my program. I am writing a little tool, which will check, if a network supports broadcast/multicast. Therefore I own a system with two interfaces and send via Interface1 a multicast Packet and try to receive it with Interface2. But: The packet shall go through the network, not the loopack device.
The idea is to block multicast-loopback on thread1/interface1 with:
u_char loop = 0;
setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop));
And to listen on thread2/interface 2 interface-specific. Tcpdump shows, that the packets are arriving, but are dropped with my config above.
with
addr.sin_addr.s_addr=inet_addr(my_ipv4Addr);
bind(sockfd,(SA*)&addr,sizeof(addr));
you can only send out packets to the multicast group,
but you can't recv any packets, even those send out from `my_ipv4Addr'.
so addr.sin_addr.s_addr must be htonl(INADDR_ANY).
with
mreq.imr_interface.s_addr=inet_addr(my_ipv4Addr);
you can recv all packets from the multicast group,
but it send out packets with the default interface (maybe eth0),
not the one you specified (like eth1).
So this is no effect.
with
setsockopt(sockfd,SOL_SOCKET,SO_BINDTODEVICE,ETH1,strlen(ETH1));
you can send out packets through the interface ETH1,
but you can only recv packets send out from the ip associated with ETH1,
you can't recv any packets from other clients.
with
mreq.imr_interface.s_addr=inet_addr(my_ipv4Addr);
setsockopt(sockfd,IPPROTO_IP,IP_MULTICAST_IF,&mreq.imr_interface,sizeof(struct in_addr);
you can send out packets through the interface associated with my_ipv4addr,
also you can recv any packets from any clients in the multicast group.
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
//addr.sin_addr.s_addr = inet_addr(my_ipv4Addr);
addr.sin_port = htons(port);
mreq.imr_multiaddr.s_addr = inet_addr(group);
// [-] mreq.imr_interface.s_addr = htonl(INADDR_ANY);
mreq.imr_interface.s_addr = inet_addr(my_ipv4Addr);
You just need to edit your code like mine.
When binding a socket for receiving multicast traffic, if you bind to a local address, this prevents multicast packets from being received on non-Windows systems.
I first discovered this when I released version 3.6 of UFTP with the feature of binding to a specific address. Windows handles it just fine, but on Linux systems the multicast packets weren't received by the app. I had to remove the feature in the next release.
Note that you are allowed to bind directly to the multicast address:
addr.sin_addr.s_addr = inet_addr(group);
In this case, you'll receive traffic only for that multicast address on that socket. You still need to join the multicast group on a specific interface to receive however.
If you plan on receiving data from more than one multicast address on the same socket, then you need to bind to INADDR_ANY.
Either you simplified your code for the sake of understanding or i have missed something,
This is the struct
struct ip_mreqn {
struct in_addr imr_multiaddr; /* IP multicast group
address */
struct in_addr imr_address; /* IP address of local
interface */
int imr_ifindex; /* interface index */
};
ip man page - IP_ADD_MEMBERSHIP
But you are referring
mreq.imr_interface.s_addr = inet_addr(my_ipv4Addr);
What is imr_interface? Does it compile?
In case you just wrote the name above for better readibility, have you tried filling the interface index i.e. imr_ifindex to the specific interface you want to attach to.
My guess is, if you leave the imrr_address and assign the interface index only, it should bind to that interface and receive packets. See if that helps.
I'm trying to implement a basic UDP protocol wherein a Sender sends a UDP datagram to a Service, which then sends a response datagram back, using the source address and source port from the incoming datagram.
Normally you'd have the Sender also listen for the response on that port. But I want the response to be picked up by a separate program (the Listener) also running on that host. So:
On host A, Listener starts and binds to port 12345, and blocks on recvfrom.
On host A, Sender sends datagram to Service running on host B, setting the source address and port to host A, port 12345.
Service on host B sends a response to host A port 12345.
Response is picked up by Listener.
Setting the source address and port is done by binding to them. So I need both Sender and Listener to bind to the same port. Setting SO_REUSEADDR in both allows this. Note that I'm not using multicast here.
But the responses aren't reliably being picked up by Listener. There are two exceptions I've observed:
I find that if the Sender closes the socket immediately after sending the first datagram, then the response will get to the Listener.
Alternatively, if the Sender is started first and binds before the Listener, the responses will get picked up by the Listener.
I've been working from examples from the internet and haven't found documentation that clearly describes what should happen. But a few places I've seen have hinted that, for Unicast, only the most recent process to bind to the port will receive datagrams sent to it.
My question is, can I send UDP datagrams so that responses (sent using the source address and port) will be picked up by another process? If the above process can't be made to work, is there a way to set the source information on an outgoing datagram without binding to that port?
A few other points:
Each process should be started independently and be able to be restarted without interfering with the other. So I don't think I can have one open the socket and spawn the other.
I don't need to receive packets from both processes. One process only sends, and the other only receives.
Ideally, the solution would be portable enough to run on common Unixes and Windows.
Finally, if it's simply not possible then I'll fall back to using a single process to perform both functions. I'm not too stressed about it but I am interested in doing it if it is possible somehow. :-)
Networking code follows...
Sender code
void run(Options *options)
{
struct sockaddr_in si_me, si_other;
int s;
socklen_t slen = sizeof(si_other);
int reuse = 1;
struct hostent *he;
if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
die("socket");
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) != 0)
die("setsockopt");
// Bind to the "listen port", so that outgoing datagrams have the correct source information
memset((char *) &si_me, 0, sizeof(si_me));
si_me.sin_family = AF_INET;
si_me.sin_port = htons(options->listen_port);
si_me.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(s, (struct sockaddr *) &si_me, sizeof(si_me)) != 0)
die("bind");
memset((char *) &si_other, 0, sizeof(si_other));
si_other.sin_family = AF_INET;
si_other.sin_port = htons(options->service_port);
if (!(he = gethostbyname2(options->service_host, AF_INET)))
die("gethostbyname2");
memmove(&si_other.sin_addr.s_addr, he->h_addr, he->h_length);
while (1)
{
int len;
char *buf;
// Create outgoing message in buf
...
if (sendto(s, buf, len, 0, (struct sockaddr *) &si_other, slen) == -1)
die("sendto");
}
close(s);
}
Listener code
static void run(Options *options)
{
struct sockaddr_in si_me, si_other;
int s;
socklen_t slen = sizeof(si_other);
char buf[BUFLEN];
int reuse = 1;
if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
die("socket");
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) != 0)
die("setsockopt");
// Bind to the same "listen port" to pick up responses to datagrams sent by Sender
memset((char *) &si_me, 0, sizeof(si_me));
si_me.sin_family = AF_INET;
si_me.sin_port = htons(options->listen_port);
si_me.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(s, (struct sockaddr *) &si_me, sizeof(si_me)) == -1)
die("bind");
while (1)
{
int nr;
nr = recvfrom(s, buf, BUFLEN, 0, (struct sockaddr *) &si_other, &slen);
if (nr == -1)
die("recvfrom");
// Process the received message
...
}
close(s);
}
A related question is Using netcat to send a UDP packet without binding, where one answer seems to suggest it should be possible using SO_SOCKADDR, but did not quite explain how it would work in my case.
is there a way to set the source information on an outgoing datagram
without binding to that port?
There is no portable way. A solution for Linux, using IP_PKTINFO, is this answer to How to re bind a udp socket in Linux.
1: You can send from different port on B
A binds 12345 sends to B:12345
B:12345 - process 1 - recv
B:12346 - process 2 - send to A:12345
2: You can construct packet with fake back address with raw sockets
First solution is better
I'm binding a client TCP socket to a specific local port. To handle the situation where the socket remains in TIME_WAIT state for some time, I use setsockopt() with SO_REUSEADDR on a socket.
It works on Linux, but does not work on Windows, I get WSAEADDRINUSE on connect() call when the previous connection is still in TIME_WAIT.
MSDN is not exactly clear what should happen with client sockets:
[...] For server applications that need to bind multiple sockets to the same port number, consider using setsockopt (SO_REUSEADDR). Client applications usually need not call bind at all—connect chooses an unused port automatically. [...]
How do I avoid this?
When you create a socket with socket(), it has only a type and a protocol family. The ideal is to bind() it to a local address:port too.
The error you mentioned normally happens when the last connection to the same host:port didn't have a graceful shutdown (FIN/ACK FIN/ACK). In these cases, the socket stays in TIME_WAIT state for a certain period of time (OS dependent, but adjustable).
What happens then is when you try to connect() to the same host and same port, it uses the default socket's name/address/port/etc, but this combination is already in use by your zombie socket. To avoid this, you can change the local address:port used to establish the connection by calling bind() after the socket creation, providing the sockaddr struct filled with your local address and a random port.
int main() {
int ret, fd;
struct sockaddr_in sa_dst;
struct sockaddr_in sa_loc;
char buffer[1024] = "GET / HTTP/1.1\r\nHost: www.google.com\r\n\r\n";
fd = socket(AF_INET, SOCK_STREAM, 0);
// Local
memset(&sa_loc, 0, sizeof(struct sockaddr_in));
sa_loc.sin_family = AF_INET;
sa_loc.sin_port = htons(LOCAL_RANDOM_PORT);
sa_loc.sin_addr.s_addr = inet_addr(LOCAL_IP_ADDRESS);
ret = bind(fd, (struct sockaddr *)&sa_loc, sizeof(struct sockaddr));
assert(ret != -1);
// Remote
memset(&sa_dst, 0, sizeof(struct sockaddr_in));
sa_dst.sin_family = AF_INET;
sa_dst.sin_port = htons(80);
sa_dst.sin_addr.s_addr = inet_addr("64.233.163.104"); // google :)
ret = connect(fd, (struct sockaddr *)&sa_dst, sizeof(struct sockaddr));
assert(ret != -1);
send(fd, buffer, strlen(buffer), 0);
recv(fd, buffer, sizeof(buffer), 0);
printf("%s\r\n", buffer);
}
UPDATE: As using a specific local port is a requirement, consider setting SO_LINGER with l_onoff=1 and l_linger=0 so your socket won't block upon close/closesocket, it will just ignore queued data and (hopefully) close the fd. As a last resort you can adjust the TIME_WAIT delay by changing the value of this registry key (highly discouraged!):
HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\TcpTimedWaitDelay
You don't specify which Windows platform you're running on, that may affect things as may the security principal that you're running under (i.e. are you admin?)...
This may help: http://blogs.msdn.com/wndp/archive/2005/08/03/Anthony-Jones.aspx
Be careful in binding the local port NOT to use the loopback address "127.0.0.1", or you will get connection timeouts. Better not to populate the sa_loc.sin_addr.s_addr at all - that works just fine.