0

I'm experimenting with sockets in C++, and I don't understand why in the accept() function the last parameter is:

socklen_t *addr_len

And I can do this:

accept(m_sock, (struct sockaddr *)&addr, (socklen_t *)&addr);

But in the connect() function the last parameter is:

socklen_t addr_len

And i get an error when I do this:

connect(m_sock, (struct sockaddr *)&addr, (socklen_t)&addr);

error: cast from pointer to smaller type 'socklen_t' (aka 'unsigned int') loses information

In that second case, why do I have to use sizeof(addr) instead of (socklen_t)&addr?

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • 3
    The call `accept(m_sock, (struct sockaddr *)&addr, (socklen_t *)&addr);` writes the size into `addr`. `connect(m_sock, (struct sockaddr *)&addr, (socklen_t)addr);` reads the value. The former is call by reference and the latter is call by value. `accept(m_sock, (struct sockaddr *)&addr, (socklen_t *)&addr);` contains a typo and should be `accept(m_sock, (struct sockaddr *)&addr, (socklen_t *)&addr_len);` –  May 09 '21 at 14:38
  • You can read it [here](https://man7.org/linux/man-pages/man2/accept.2.html) and [here](https://man7.org/linux/man-pages/man2/connect.2.html) –  May 09 '21 at 14:43
  • 1
    Just because the compiler doesn't complain about the `accept()` call doesn't mean it's correct. On entry, the last parameter should be the address of a `socklen_t` variable that has been set to the length of the buffer whose address is passed in as the second parameter, and on return will be set to the _actual_ length of the address structure written to the address passed in the second parameter. Using `&addr` for both parameters is wrong. – TripeHound May 09 '21 at 15:02

1 Answers1

2

The last parameter of accept() is an input/output parameter passed by pointer. The caller needs to pass in the address of an allocated sockaddr_... buffer in the 2nd parameter, and pass in the address of a socklen_t variable in the 3rd parameter, where that variable specifies the buffer's allocated size. The function will copy the accepted peer's information into the caller's sockaddr_... buffer, being sure not to exceed the specified buffer size. The number of bytes copied to the buffer will be written back to the socklen_t variable upon exit.

socklen_t addr_len = sizeof(addr);
accept(m_sock, (struct sockaddr *)&addr, &addr_len);

The last parameter of connect() is an input-only parameter passed by value. The caller needs to pass in the address of an allocated and populated sockaddr_... buffer in the 2nd parameter, and pass in the value of the buffer's populated size in the 3rd parameter. The function will read from the caller's sockaddr_... buffer, being sure not to exceed the specified buffer size. The function does not write anything back to the caller, so no socklen_t variable is needed (but you can use one if you want to).

connect(m_sock, (struct sockaddr *)&addr, sizeof(addr));
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770