I'm working on migrating some code from IPv4 only to IPv6, and of course I need to retain backwards compatibility for IPv4.
I have read through some documents and guides for converting my code, and have seen it written that using many of the newer APIs (like inet_pton() instead of inet_addr()) will just work in both IPv4 and IPv6.
However, in some cases it still isn't clear when I need to write code to handle each protocol in a different way. Specifically, I don't know whether a IPv6 address (family AF_INET6 using sockaddr_storage structure) will work on a local network.
So for example, let's say I create such an address using the built in constant in6addr_loopback, and then I try to use that for a parameter to a bind() call.
Will this work in both IPv4 and IPv6, or I need to create the right address type (AF_INET vs AF_INET6) for each case? Does it matter whether I am connecting to a local socket (i.e. the loopback as in this case) as opposed to a socket on an external device?
My client code is running on iPhone/iPad hardware in case it matters.
Every interface will derive a link local ipv6 address using mac address. This address is sufficient for communication within local network.
Regarding creation of socket, you need to specify the family (AF_INET and AF_INET6) and initialize and bind it.
IPv4:
struct sockaddr_in serv_addr, cli_addr;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
IPv6:
struct sockaddr_in6 serv_addr, cli_addr;
sockfd = socket(AF_INET6, SOCK_STREAM, 0);
serv_addr.sin6_family = AF_INET6;
serv_addr.sin6_addr = in6addr_any;
serv_addr.sin6_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
hope this helps!
Related
I have a simulator application which Unix Domain datagram sockets, which sends data to socket path for.ex /var/lib/XYZ.
sendto is returning -2 which is due to other end no peer is there(no other unix domian socket application is running)
I would like to write a datagram client/peer application using Unix Domain Sockets for receiving data from the server/simulator(which is sending data to /var/lib/XYZ).
My code is as follows:
#define BUF_SIZE 1024
#define SV_SOCK_PATH "/var/lib/XYZ"
#define SV_SOCK_PATH2 "/var/lib/ABC"
creation of Unix Domain sockets as below:
struct sockaddr_un svaddr, claddr;
....
sfd = socket(AF_UNIX, SOCK_DGRAM, 0);
if (sfd == -1)
printf("socket creation failed");
memset(&claddr, 0, sizeof(struct sockaddr_un));
claddr.sun_family = AF_UNIX;
strncpy(claddr.sun_path, SV_SOCK_PATH2, sizeof(claddr.sun_path) - 1);
if (bind(sfd, (struct sockaddr *) &claddr, sizeof(struct sockaddr_un)) == -1)
printf("bind failed");
/* Construct address of server */
memset(&svaddr, 0, sizeof(struct sockaddr_un));
svaddr.sun_family = AF_UNIX;
strncpy(svaddr.sun_path, SV_SOCK_PATH, sizeof(svaddr.sun_path) - 1);
while(1)
{
int len=sizeof(struct sockaddr_un);
numBytes = recvfrom(sfd, resp, BUF_SIZE, 0, (struct sockaddr*)&svaddr,&len);
if (numBytes == -1)
printf("recvfrom error");
else{
printf("no of bytes received from server: %d",(int)numBytes);
printf("Response %d: %s\n", (int) numBytes, resp);
}
}
remove(claddr.sun_path);
//exit(EXIT_SUCCESS);
}
but the program is not receiving anything...is there anything missed out??
When it comes to datagrams, there is no real client or server. Either side attempting to send is responsible for addressing datagrams to the other. So, in your code, the setup is all wrong. You're apparently attempting to direct the "server" (but really not a server, just the other peer) to send to you via svaddr but that isn't how it works.
For a datagram AF_UNIX socket, the sender either needs to explicitly specify the receiver's address in a sendto call, or it needs to first connect its socket to the receiver's address. (In the latter case, it can then use send instead of sendto since the peer address has been specified via connect.)
You can't specify the sending peer's address in the recvfrom call. The socket address argument in the recvfrom is intended to return to you the address from which the datagram was sent. Whatever is in that variable will be overwritten on successful return from recvfrom.
One way datagram peer programs are often structured: the "server" creates a well-known path and binds to it, then a "client" creates its own endpoint and binds to it (constructing a unique socket address for itself), then the client can sendto the server's well-known socket. The server, by using recvfrom to obtain the client's address along with the datagram, can then use sendto along with the address to return a message to the client (without needing to connect its socket). This provides a sort of client-server paradigm on top of the fundamentally equal-peer orientation of the datagram socket.
Finally, I should mention that it's usually a good idea to use fully specified pathnames to ensure both peers are using the same address even if started from different directories. (Normally, with AF_UNIX, the address is a path name in the file system used to "rendezvous" between the two peers -- so without a full path "some_socket" is "./some_socket" in the current working directory. Some systems, such as linux, also support an abstract "hidden" namespace that doesn't require a full path, but you must use an initial null byte in the name to specify that.)
(Running on VS2017, Win7 x64)
I am confused about the point of SO_REUSEADDR and SO_EXCLUSIVEADDRUSE. And yes, I've read the MSDN documentation, but I'm obviously not getting it.
I have the following simple code in two separate processes. As expected, because I enable SO_REUSEADDR on both sockets, the second process's bind succeeds. If I don't enable this on any one of these sockets, the second bind will not succeed.
#define PORT 5150
SOCKET sockListen;
if ((sockListen = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
{
printf("WSASocket() failed with error %d\n", WSAGetLastError());
return 1;
}
int optval = 1;
if (setsockopt(sockListen, SOL_SOCKET, `SO_REUSEADDR`, (char*)&optval, sizeof(optval)) == -1)
return -1;
SOCKADDR_IN InternetAddr;
InternetAddr.sin_family = AF_INET;
InternetAddr.sin_addr.s_addr = inet_addr("10.15.20.97");
InternetAddr.sin_port = htons(PORT);
if (::bind(sockListen, (PSOCKADDR)&InternetAddr, sizeof(InternetAddr)) == SOCKET_ERROR)
{
printf("bind() failed with error %d\n", WSAGetLastError());
return 1;
}
So doesn't having to enable SO_REUSEADDR for both sockets make SO_EXCLUSIVEADDRUSE unnecessary - if I don't want anyone to foricibly bind to my port, I just don't enable SO_REUSEADDR in that process?
The only difference I can see is that if I enable SO_EXCLUSIVEADDRUSE in the first process, then attempt a bind in the second process, that second bind will fail with
a) WSAEADDRINUSE if I don't enable SO_REUSEADDR in that second process
b) WSAEACCES if I do enable SO_REUSEADDR in that second process
So I tried enabling both SO_EXCLUSIVEADDRUSE and SO_REUSEADDR in the first process but found that whichever one I attempted second failed with WSAEINVAL.
Note also that I have read this past question but what that says isn't what I'm seeing: it states
A socket with SO_REUSEADDR can always bind to exactly the same source
address and port as an already bound socket, even if the other socket
did not have this option set when it was bound
Now if that were the case then I can definitely see the need for SO_EXCLUSIVEADDRUSE.
I'm pretty sure I'm doing something wrong but I cannot see it; can someone clarify please?
As stated in the docs, SO_EXCLUSIVEADDRUSE became available on Windows NT4 SP4; before that there was only SO_REUSEADDR. So both being present has (also) historical reasons.
I think of SO_REUSEADDR as the intention to share an address (which is only really useful for UDP multicast. For unicast or TCP it really doesn´t do much since the bahaviour is non-deterministic for both sockets).
SO_EXCLUSIVEADDRUSE is a security measure to avoid my (server) application´s traffic being hijacked / rendered useless by a later binding to the same IP/port.
As I see it, you need SO_REUSEADDR for UDP multicats, and you need SO_EXCLUSIVEADDRUSE as a security measure for server applications.
I am learning WinSock UDP. Most tutorials I've seen ask me to:
On server side:
SOCKET socked = socket(PF_INET, SOCK_DGRAM, 0)
bind(...);
for(;;) { recvfrom(..); }
On client side:
SOCKET socked = socket(PF_INET, SOCK_DGRAM, 0);
sendto(...);
But I wonder how can I do other way, send data from server to client. I don't know client's port (I figured out it vary every sendto call), and I want to be able to connect client behihd NAT to server and still recive data from server.
How it is done in modern games?
There are two questions in there.
Finding the address
The function recvfrom is declared:
int recvfrom(
__in SOCKET s,
__out char *buf,
__in int len,
__in int flags,
__out struct sockaddr *from, /* <--- */
__inout_opt int *fromlen /* <--- */
);
So you can use from and fromlen in sendto.
sendto(..., (SOCKADDR *)from, *fromlen);
NAT
The NAT-box should automatically allow the server to "answer" to the datagram sent by the client. So, the mere fact that the client sent a datagram causes the NAT-box to ephemerally (a few minutes?) open a port to allow traffic return.
I have a root node(server) connected to many other nodes(clients) through TCP sockets. I want to send some data from server to client, but the data is different for each node and depends on the ip address of that node.
Thus I should have ip address of each node connected to server. How can I have that information?
When you call accept(2) you can choose to retrieve the address of the client.
int accept(int socket, struct sockaddr *restrict address,
socklen_t *restrict address_len);
You need to store those addresses and then send(2) to each what you need to send.
So the workflow should be something like this:
Keep a list of connected clients. Initially the list is empty, of course
When you accept a connection, push its details into that list (the address and the socket returned by accept(2)).
When you need to send something to every client, simply walk the list and send it (using the stored socket)
The one tricky part is that socklen_t *restrict address_len is a value-result argument, so you need to be careful with that.
This is a more nuanced question than it first appears.
If the clients are sitting behind a NAT, you may get the same IP from more than one client. This is perfectly natural and expected behavior. If you need to distinguish between multiple clients behind the same NAT, you'll need some other form of unique client id (say, IP address and port).
As long as you have access to the list of file descriptors for the connected TCP sockets, it is easy to retrieve the addresses of the remote hosts. The key is the getpeername() system call, which allows you to find out the address of the remote end of a socket. Sample C code:
// This is ugly, but simpler than the alternative
union {
struct sockaddr sa;
struct sockaddr_in sa4;
struct sockaddr_storage sas;
} address;
socklen_t size = sizeof(address);
// Assume the file descriptor is in the var 'fd':
if (getpeername(fd, &address.sa, &size) < 0) {
// Deal with error here...
}
if (address.sa.family == AF_INET) {
// IP address now in address.sa4.sin_addr, port in address.sa4.sin_port
} else {
// Some other kind of socket...
}
With a WiFi connection, UDP data is not received. It stops at:
recvfrom(sock, buf, RECV_BUF_SIZE, 0, (SOCKADDR*)&rAddr, (SOCK_LEN*)&len);
When I run the same program in iPhone simulator over ethernet it works well. What am I missing?
Look at the man page.
Like so:
recvfrom(mSock,recvBuff,1024,0,(struct sockaddr *)&from, &fromlen);
providing the parameter values you are setting are correct try this in your case try:
recvfrom(sock, buf, RECV_BUF_SIZE, 0, (struct sockaddr *)&rAddr, &len);