API using sockaddr_storage - sockets

I'm trying to do some IP agnostic coding and as suggested by various sources I tried to use sockaddr_storage. However all the API calls (getaddrinfo, getnameinfo) still depend on struct sockaddr. And casting between them isn't exactly a good option, gves rise to a lot of other problems.
And casting to sockaddr_in and sockaddr_in6 separately sort of defeats the purpose of me trying to use sockaddr_storage.
Anybody who has effectively used sockaddr_storage in devloping a simple client server socket application.

The problem with jointly doing IPV6 and IPV4 programming is that a pure sockaddr struct itself is not big enough to hold a sockaddr_in6. So if you need to blindly pass around an address that could be either sockaddr_in or sockaddr_in6, sockaddr_storage is a bit easier to use.
At the end of the day, whether you are using sockaddr_in, sockaddr_in6, or sockaddr_storage, you'll have to cast those pointers to make a call to sendto, recvfrom, connect, accept, and many other socket functions. It's just a known nuance of socket programming. Just let go of the feeling of doing something unsafe. Your code will be ok.
Now when writing network code that is meant to work for both IPV4 and IPV6, you can easily get into a trap of having an abundance of switch statements to handle the different network types. Code then gets messy like the following:
if (addr.ss_family == AF_INET)
sendto(sock, buffer, len, 0, (sockaddr*)&addr, sizeof(sockaddr_in))
else (addr.ss_family == AF_INET6)
sendto(sock, buffer, len, 0, (sockaddr*)&addr, sizeof(sockaddr_in6));
And then that type of "if family == AF_INET" expression can easily start to repeat itself over and over. That's what you want to avoid.
Assuming you are using C++, you'll find that an abstraction class for a socket address object is incredibly useful. I have an example on github here and here. The CSocketAddress class is backed by a union of {sockaddr, sockaddr_in, sockaddr_in6} and can be constructed with a sockaddr_storage. If I had known about sockaddr_storage before I had started this class, I would have used that instead of the union thing. In any case, it allows me to write code as follows:
CSocketAddress addr;
...
sendto(sock, buffer, len, 0, addr.GetSockAddr(), addr.GetSockAddrLength());
Likewise, an "accept" statement looks like this:
sockaddr_storage addrstorage = {};
int len = sizeof(sockaddr_storage);
accept(sock, (sockaddr*)&addrstorage, &len);
CSocketAdddress addr(addrstorage); // construct an address object to pass around everywhere else
This was incredibly helpful for the code paths that call bind, send, and recv. Now my STUN server and client code paths no longer have to know anything about the family type of the socket address. They just work with "CSocketAddress" objects. The only IPV4 and IPV6 specific code is during the client and server initialization - when the address objects are actually constructed. Fortunately, that was partially abstracted out as well.
You might also want to peruse the helper functions here. There's some more useful stuff for resolving hostnames, enumerating adapters, etc... in an IP agnostic way. It's Linux code, but some of it should map ok to Windows and winsock.
I am almost done adding TCP support to this code base. In the process of adding support for SOCK_STREAM, I have not had to make a single change nor add any new code to deal with the differences in IPV4 and IPV6 address structures.

I don't generally see the need for struct sockaddr_storage. It's purpose is to allocate enough space for the sockaddr structure of any given protocol, but how often do you need to do that in IP-version-agnostic code? Generally you call getaddrinfo() and it gives you a bunch of struct sockaddr *s, and you don't care whether they're sockaddr_in or sockaddr_in6, you just pass them along as-is to bind() and connect() (no casting required).
In typical client/server code, the main place I can think of where struct sockaddr_storage is useful is to reserve space for the second parameter to accept(). In this case I agree it's ugly to have to cast it to struct sockaddr * once for accept() and again for getnameinfo(). But I can't see a way around those casts. This is C. Structure inheritance always involves lots of casts.

Related

Explain line "s = socket(res->ai_family, res->ai_socktype, res->ai_protocol)"

int s;
struct addrinfo hints, *res;
getaddrinfo("www.example.com", "http", &hints, &res);
s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
Please explain the last line of code
The notion of socket is a very generic communication means.
It could deal with communication between local processes, communication between your process and some internal aspects of your system's kernel (events...), communication through the network...
Even when it deals with the network, there exists many protocol families and many protocols.
That's why, when we create a socket (with the socket() call on your last line), we have to provide several parameters in order to select the right properties of the required socket.
man 2 socket mainly explains the first parameter (domain or protocol family) but the other parameters are explained in subsequent pages since they depend on the choice made with this first parameter.
Note that once a socket is obtained with the socket() call, you may need to provide many other settings by other system calls, depending on your intention (bind() for a server, connect() for a client... many settings exist).
In your example, it seems that you want to reach an HTTP server named www.example.com.
You could have hardcoded the fact that such a server can be reached with the AF_INET protocol family (for ipv4, or AF_INET6 for ipv6), through a TCP connection (type SOCK_STREAM, protocol 0) but the getaddrinfo() function can help provide all these details and some other to be used in subsequent system calls (IP address and port number to be specified in a subsequent connect() call for example).
All this information stands in the members of the returned struct addrinfo.

Internet socket address, Extra padding?

While trying to do some socket programming I came across some interesting detail, that detail being the sockaddr_in struct size, it's 14 bytes in size
From my understanding that extra padding is used for typecasting the different types of IP addresses but in theory, couldn't you sneak in malicious code if there's any padding left after the type casting?
Extra padding to me seems like unused memory.
The sockaddr and sockaddr_in structures are typically only used for communication between an application and the kernel/runtime. They are constructed by functions like inet_aton(), and passed to functions like bind(). They are generally not sent over the network, or stored in files. As such, there's no way to "sneak in" a "malicious" (or otherwise faulty) value. Even if this did occur, the extra data would simply be ignored by the recipient.
The padding was probably added in an attempt to support future network address formats which might be larger than IPv4 addresses. Ironically, this was insufficient to support IPv6 addresses, which are 16 bytes long.

New to socket programming, questions regarding "select()"

Currently in my degree we're starting to work with sockets.
I Have a couple of questions regarding polling for input from sockets,
using the select() function.
int select( int nfds,
fd_set *readfds,
fd_set *writefds,
fd_set *exceptfds,
const struct timespec *timeout);
We give select "nfds" param, which would normally would
be the maximum sockets number we would like to monitor. How can i watch only one specific socket instead of the range of 0 to nfds_val sockets ?
What are the file descriptors objects that we use? what is their purpose,
and why can't we just point "select" to the relevant socket structure?
I've read over the forum regarding Blocking and Non-Blocking mode of select, but couldn't understand the meaning or uses of each, nor how to implement such, would be glad if someone could explain.
Last but not least (only for the time being :D ) - When binding a socketaddr_in to socket number, why does one needs to cast to socketaddr * and not leave it as sockaddr_in * ?
I mean except for the fact that bind method expects this kind of pointer type ;)
Would appreciate some of the experts answers here :)
Thank you guys and have a great week!
We give select "nfds" param, which would normally would be the maximum sockets number we would like to monitor. How can i watch only one specific socket instead of the range of 0 to nfds_val sockets ?
Edit. (sorry, the previous text here was wrong) Just provide your socket descriptor + 1. I'm pretty sure it doesn't mean OS will check all the descriptors in [0, 1... descriptor] range.
What are the file descriptors objects that we use? what is their purpose, and why can't we just point "select" to the relevant socket structure?
File descriptors are usually integer values given to the user by OS. OS uses descriptors to control physical and logical resources - one file descriptor means OS has given you something file-like to control. Since Berkeley Sockets have read and write operations defined, they are file-like and socket objects essentially are plain file descriptors.
Answering why can't we just point "select" to the relevant socket structure? - we actually can. What exactly to pass to select depends on OS and language. In C you place your socket descriptor (plain int value most probably) into a fd_set. fd_set is then passed to select.
Edit.
An tiny example for Linux:
fd_set set;
FD_ZERO(&set);
FD_SET(socket_fd, &set);
// check if socket_fd is ready for reading
result = select(socket_fd + 1, &set, NULL, NULL, NULL);
if (result == -1) report_error(errno);
Docs.
Windows has similar code.
I've read over the forum regarding Blocking and Non-Blocking mode of select, but couldn't understand the meaning or uses of each, nor how to implement such, would be glad if someone could explain.
A blocking operation makes your thread wait until it is done. It's 99% of functions you use. If there are sockets ready for some IO, blocking select will return something immediately. It there are no such sockets, the thread will wait for them. Non-blocking select, in the latter case, won't wait and will return -1 (error).
As an example, try to implement single threaded server that is capable of working with multiple clients, including long operations like file transfer happening simultaneously. You definitely don't want to use blocking socket operations in this case.
Last but not least (only for the time being :D ) - When binding a socketaddr_in to socket number, why does one needs to cast to socketaddr * and not leave it as sockaddr_in * ? I mean except for the fact that bind method expects this kind of pointer type ;)
Probably due to historical reasons, but I'm not sure. And there seems to be a fine answer on SO already.

what is the protocol parameter in winsock's socket function for?

The winsock function socket expects as third parameter the protocol what usually is IPROTO_TCP for socket type SOCK_STREAM and IPROTO_UDP for socket type SOCK_DGRAM. When I pass a 0 value as the protocol parameter, TCP and UDP work as expected.
SOCKET s = socket(AF_INET, SOCK_DGRAM, 0)
// s is a valid socket
What is the IPROTO_IP protocol parameter value meant to? If it's only intented to be used with SOCK_RAW, why is there this kind of redundancy?
socket(AF_INET, SOCK_STREAM, IPROTO_TCP);
socket(AF_INET, SOCK_DGRAM, IPROTO_UDP);
What actually does the protocol parameter specify? when I can just use another value, it looks like that it's unimportant.
I want to send UDP packets (including broadcasts) from a PC with more than one netword card to a specific ethernet segment. While the IP routing normally select the network card (and source address) I would like specify the adapter(s) and think about raw sockets or any other means to achieve this goal. Probably this IPPROTO_IP may help in this case.
I think the documentation for socket (which can be found here: http://msdn.microsoft.com/en-us/library/ms740506(VS.85).aspx) is pretty clear on what the value is for and why passing 0 is fine if you don't care.
A situation where you might want to pass something different is if you wanted to set up a socket for an unusual connection type; such as bluetooth, or if you wanted to create a PGM reliable multicast socket, etc.
Your second question is unrelated to raw sockets or the protocol parameters. What you need to do is simply bind your socket to the address of the local interface that you want to use; so rather than binding to INADDR_ANY and allowing the stack to decide for you, you tell it which interface to use.

sending a packet to multiple client at a time from udp socket

I was trying to write a udp server who send an instance of a file to multiple clients.Now suppose any how I manage to know the address of those client statically(for the sake of simplicity) and now I want to send this packet to these addresses.So how exactly I need to fill the sockaddr structure to contain the address of these clients.I am taking an array of sockaddr structure(to contain client address) and trying to send at each one them at a time.Now problem is to fill the individual sockaddr structure to contain the client address.
I was trying to do something like that
sa[1].sin_family = AF_INET;
sa[1].sin_addr.s_addr = htonl(INADDR_ANY);//should'nt I replace this INADDR_ANY with client ip??
sa[1].sin_port = htons(50002);
Correct me if this is not the correct way.
All your help in this regard will be highly appreciated.
With Thanks in advance,
Mawia
sin_addr should be set to the destination address.
if (! inet_aton("1.2.3.4", &sa[1].sin_addr)) {
// Give up all hope
}
// Everything is copacetic.
Looks like you're talking about multicast. It is a bit harder than trivial.
Take a look at this thread to discover how to subscribe to a multicast group (for the client side) and how to send multicast packets (for the server side). It is discussed using python, but only low-level wrappers around socket library are used, so it should be quite simple to translate examples to any language.
As mentioned in a different answer, you're talking about multicast, but on the public Internet, that requires ISP support.
There is such a thing as an application level multicast infrastructure. This writeup, dating back to 2000, describes one such method.