News for hackers. Stuff that matters.
Re:Tell HN: C Experts Panel – Ask us anything about C by loeg on Tuesday April 14, 2020 @12:02PM (#22867600)
BSD sockets are weird in that the first struct's (sockaddr) size wasn't big enough, so APIs all take a nominal pointer to sockaddr but may require larger storage (sockaddr_storage) depending on the actual address.

  /*
   * Structure used by kernel to store most
   * addresses.
   */
  struct sockaddr {
          unsigned char   sa_len;         /* total length */
          sa_family_t     sa_family;      /* address family */
          char            sa_data[14];    /* actually longer; address value */
  };


  /*
   * RFC 2553: protocol-independent placeholder for socket addresses
   */
  #define _SS_MAXSIZE     128U
  #define _SS_ALIGNSIZE   (sizeof(__int64_t))
  #define _SS_PAD1SIZE    (_SS_ALIGNSIZE - sizeof(unsigned char) - \
                              sizeof(sa_family_t))
  #define _SS_PAD2SIZE    (_SS_MAXSIZE - sizeof(unsigned char) - \
                              sizeof(sa_family_t) - _SS_PAD1SIZE - _SS_ALIGNSIZE)
  
  struct sockaddr_storage {
          unsigned char   ss_len;         /* address length */
          sa_family_t     ss_family;      /* address family */
          char            __ss_pad1[_SS_PAD1SIZE];
          __int64_t       __ss_align;     /* force desired struct alignment */
          char            __ss_pad2[_SS_PAD2SIZE];
  };
Re:Tell HN: C Experts Panel – Ask us anything about C by wahern on Tuesday April 14, 2020 @01:12PM (#22868538)
struct sockaddr_storage is insufficient as well. A Unix domain socket path can be longer than `sizeof ((struct sockaddr_un){ 0}).sun_path`. That's a major reason why all the socket APIs take a separate socklen_t argument. Most people just assume that a domain socket path is limited to a relatively short string, but it's not (except possibly Minix, IIRC).
Re:Tell HN: C Experts Panel – Ask us anything about C by asveikau on Tuesday April 14, 2020 @01:43PM (#22868968)
> A Unix domain socket path can be longer than `sizeof ((struct sockaddr_un){ 0}).sun_path`

Hm, I didn't realize this, or if I knew this I had forgotten. It makes sense because sun_path is usually pretty small, I believe 108 chars is the most common choice, and typically file paths are allowed to be much longer.

Do you have a citation for this behavior? I can't seem to find it, though I'm not looking very hard.

I guess you are right that any syscall taking a struct sockaddr * also has a length passed to it... Some systems have sa_len inside struct sockaddr to indicate length, but IIRC linux does not. I've often thought that length parameter was sort of redundant, because (1) some platforms have sa_len, and (2) even without that, you should be able to derive length from family. But your Unix domain socket example breaks (2). Without being able to do that, I start to imagine that the kernel would need to probe for NUL chars terminating the C string anytime it inspects a struct sockaddr_un, rather than block-copying the expected size of the structure -- that would be needlessly complicated.

Re:Tell HN: C Experts Panel – Ask us anything about C by wahern on Tuesday April 14, 2020 @04:08PM (#22870825)
So I just reran some tests on my existing VMs and it turns out I remembered wrong. Here's the actual break down:

* Solaris 11.4: .sun_path: 108; bind/connect path maximum: 1023. Length seems to be same as open. Interestingly, open path maximum seems to be 1023 (judged by trying ls -l /path/to/sock), although I always thought it was unbounded on Solaris.

* MacOS 10.14: .sun_path: 104, bind/connect path maximum: 253. Length can be bigger than .sun_path but less than open path limit.

* NetBSD 8.0: .sun_path: 104, bind/connect path maximum: 253. Same as MacOS.

* FreeBSD 12.0: .sun_path: 104, bind/connect path maximum: 104.

* OpenBSD 6.6: .sun_path: 104, bind/connect path maximum: 103 (104 - 1).

* Linux 5.4: .sun_path: 108, bind/connect path maximum: 108.

* AIX 7.1: .sun_path: 1023, bind/connect path maximum: 1023. Yes, .sun_path is statically sized to 1023! And like Solaris, open path maximum seems to be 1023 (as judged by trying ls -l /path/to/socket). Thanks to Polar Home, polarhome.com, for the free AIX shell account.

Note that all the above lengths are exclusive of NUL, and the passed socklen_t argument did not include a NUL terminator.

For posterity: on all these systems you can still create sockets with long paths, you just have to chdir or use bindat/connectat if available. My test code confirmed as much. And AFAICT getsockname/getpeername will only return the .sun_path path (if anything) used to bind or connect, but that's a more complex topic (see https://github.com/wahern/cqueues/blob/e3af1f63/PORTING.md#g...)

Re:Tell HN: C Experts Panel – Ask us anything about C by asveikau on Tuesday April 14, 2020 @04:26PM (#22871029)
Linux also has the unusual extension of: if sun_path[0] is NUL, the path is not a filesystem path and the rest of the name buffer is an ID. I don't remember if that can have embedded NULs in that ID. I believe so.