When to use sizeof(sockaddr_in) vs sizeof(sockaddr)?

Started by
6 comments, last by jkf 19 years, 8 months ago
I'm writing e UDP client/server app, and I'm having a devil of a time trying to figure out exactly what the last arguments to sendto() and recvfrom() are supposed to be. All of the sources I've found today say that in the case of sendto(), the last argument is sizeof(sockaddr_in). However, I'm looking at code I wrote a few months ago, and it's using sizeof(sockaddr). I'm assuming that at one point I found a source that said to use that, but I could be wrong. Should I just use sizeof(sockaddr_in)? In the case of recvfrom(), I've found sources that differ in regards to using sizeof(sockaddr_in) or sizeof(sockaddr) as the last argument. Is there a clear answer as to which one to use? To further confuse myself, I checked the man pages for these functions, and noticed that for the second-to-last argument, they both take a pointer to a sockaddr. Now, isn't the last argument in both these of functions supposed to relate to this second-to-last argument? If so, shouldn't the last argument be the sizeof the second-to-last argument (although why sendto & recvfrom would need this information passed to them rather than just finding it themselves is puzzling)? If not, then what exactly are these sizeof arguments meant to be referring to, and why the heck does recvfrom() require a pointer? It seems like an odd thing to change the value of, and if it does change the value, I haven't seen any examples that make use of this.
Advertisement
sockaddr is a structure that is dependant on the protocol used. I would say it is better to use sockaddr as opposed to sockaddr_in, in case one is to use IPv6, for instance.
Look at this.
I've only done a little winsock programming, so I'm afraid I can't give you more information than this.

regards,
jflanglois
Taken from the Winsock 2 MSDN reference:
int sendto(  SOCKET s,  const char* buf,  int len,  int flags,  const struct sockaddr* to,  int tolen);


The first four paramaters are fairly standard network sending, and I think they are the same TCP and UDP.

The second last (sockaddr) struct should contain the details of who you are sending the packet to (IP Addr and Port No).

The final paramater should be the size of this structure. Depending on the protocol, it will be one of 'sockaddr_in', 'sockaddr_in6', or 'sockaddr_in6_old'. I've only ever used sizeof(sockaddr_in) here, and everything has worked quite well.

If you are talking about unix sockets, I think that the rules are the same.
Quote:Original post by Stagz
The second last (sockaddr) struct should contain the details of who you are sending the packet to (IP Addr and Port No).

The final paramater should be the size of this structure. Depending on the protocol, it will be one of 'sockaddr_in', 'sockaddr_in6', or 'sockaddr_in6_old'.

Just to be clear, I'm not challenging the fact that this works; I'm trying to understand what's going on, because I see some appearant inconsistincies. If you're passing the sizeof the structure you are sending, then why would you use sizeof(sockaddr_in | sockaddrin_6 | sockaddr_in6_old) when, according to the function prototype, the structure is none of these? Why isn't it always sizeof(sockaddr)? Are you not always passing a sockaddr structure? And if not, then shouldn't the rule be to simply pass the sizeof whatever structure you're sending?
Hello BerwynIrish,

if ipv4 both these struct are the same size. 16 bytes.
according to my man pages sendto and recvfrom use sockaddr not sockaddr_in.

But I believe they both hold the same data. They just have diffrent names for their data members.

I think sockaddr_in is used to in function for getting network info and stuff and relate to rpc.

Lord Bart :)

Referenced from Unix Network Programming, by the late Richard Stevens...

Never use a sockaddr struct directly. The only reason sockaddr was defined is because in 1982 when the BSD socket API was being developed, ANSI C didn't have a void * type. The sockaddr was defined to provide a generic socket address structure. Typically, its defined as something similar to this...

struct sockaddr {  uint8_t      sa_len;  sa_family_t  sa_family;   /* address family: AF_xxx value */  char         sa_data[14]; /* protocol specific address */};


No real useful information there. When doing internet traffic, always use sockaddr_in or sockaddr_in6 if you're doing IPv6. sockaddr_in is usually defined as something similar to this...

struct sockaddr_in {  uint8_t         sin_len;      /* lenght of structure (16) */  sa_family_t     sin_family;   /* AF_INET */  in_port_t       sin_port;     /* 16 bit TCP or UDP port number */                                /* network byte ordered */  struct in_addr  sin_addr;     /* 32 bit IPv4 address */                                /* network byte ordered */  char            sin_zero[8];  /* unused */};


You can safely cast this struct to sockaddr, and from the first two fields, the system can tell what kind of socket address it really is. Both of these structs are 16 bytes in length, so in this case, using sizeof(sockaddr) works, but isn't "correct". If you ever use unix domain or IPv6 sockets, those structs are longer and using the wrong sizeof() will break things.

To summarize, for IPv4 sockets, always use sockaddr_in but cast it to a sockaddr * when making calls with it. Personally, I don't use sizeof(struct sockaddr_in). I use sizeof on the name of my sockaddr_in struct. This makes changes a little easier as if I ever need to change what struct is used, I change the definition/declaration and the compile takes care of the rest.

Hope this helped.

[Edited by - jkf on August 3, 2004 1:07:26 PM]
Thanks guys, my questions are pretty much cleared up. Although I'm still curious as to why recvfrom() asks for a pointer to an object that holds a sizeof(whatever) value, rather than just a sizeof(whatever) value like sendto() asks for, it doesn't appear to be a critical point for my purposes. Just one more question...
Quote: If you ever use unix or IPv6 sockets, those structs are longer and using the wrong sizeof() will break things.

Does "unix sockets" refer to the use of any type of socket under a unix platform, or does it refer to a specific type of socket used by unix?
Quote:Original post by BerwynIrish
Thanks guys, my questions are pretty much cleared up. Although I'm still curious as to why recvfrom() asks for a pointer to an object that holds a sizeof(whatever) value, rather than just a sizeof(whatever) value like sendto() asks for, it doesn't appear to be a critical point for my purposes. Just one more question...

When you call recvfrom, it takes whatever sockaddr type struct that you pass it, and it fills it in with the details of the machine that sent the packet to you. It asks for a pointer to the sizeof value so revcfrom can pass you the proper length.

Quote:Original post by BerwynIrish
Quote: If you ever use unix or IPv6 sockets, those structs are longer and using the wrong sizeof() will break things.

Does "unix sockets" refer to the use of any type of socket under a unix platform, or does it refer to a specific type of socket used by unix?

They're more properly called unix domain sockets. The basic difference is, instead of using IP addresses and port numbers to identify a socket, it uses a path on the filesystem, e.g. /tmp/foo.sock. They aren't used all that often because they are limited to the local machine. You can't use a unix domain socket to talk to a program on a different computer. But, if two programs on the same computer need to talk to each other, unix domain sockets are much faster than creating a normal IP connection.

This topic is closed to new replies.

Advertisement