3

According to https://stackoverflow.com/a/5328190, I can use

std::string ip ="192.168.1.54";
std::stringstream s(ip);
int a,b,c,d; //to store the 4 ints
char ch; //to temporarily store the '.'
s >> a >> ch >> b >> ch >> c >> ch >> d;
std::cout << a << "  " << b << "  " << c << "  "<< d;

to convert an IP to its 4 bytes. Buw how do I put them inside a

struct sockaddr
  {
    __SOCKADDR_COMMON (sa_);    /* Common data: address family and length.  */
    char sa_data[14];       /* Address data.  */
  };

?

Should I just simply copy the 4 bytes in the first 4 bytes of sa_data?

Guerlando OCs
  • 1,886
  • 9
  • 61
  • 150

2 Answers2

6

You don't actually use a struct sockaddr directly. You would instead populate a struct sockaddr_in which is made to hold an IPv4 address and port, then pass the address of that struct to functions that expect a struct sockaddr *.

To populate the address field of a sockaddr_in from a C string, you can use inet_addr.

For example:

struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = inet_addr(ip.c_str());
sin.sin_port = 0;

When calling recvfrom, the addrlen parameter should be a pointer to a variable which is set to the size of the structure pointed to by the src_addr parameter. For example:

struct sockaddr_in peerAddr;
socklen_t len = sizeof(peerAddr);
recvfrom(sock, data, capacity, 0, (struct sockaddr *)&peerAddr, &len);
dbush
  • 205,898
  • 23
  • 218
  • 273
  • Thank you! So I should just pass this but casting to a pointer to `sockaddr`? How can I fill the lenght just as `recvfrom(sock, data, capacity, 0, &peerAddr, &len);` fills `len`? Should I just do `len = sizeof sin`? I've opened a bounty, please help me – Guerlando OCs Aug 02 '20 at 23:27
5

A better way to do this is with getaddrinfo, something like

struct addrinfo params = { 0 };
params.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV; // adjust
params.ai_family = AF_UNSPEC;
params.ai_socktype = SOCK_STREAM; // adjust
params.ai_protocol = IPPROTO_TCP; // adjust

struct addrinfo *addrs;
int status = getaddrinfo(ip.c_str(), port.c_str(), &params, &addrs);
if (status == EAI_SYSTEM) {
  fprintf(stderr, "%s:%s: %s\n", ip.c_str(), port.c_str(), strerror(errno));
  return -1;
} else if (status) {
  fprintf(stderr, "%s:%s: %s\n", ip.c_str(), port.c_str(), gai_strerror(status));
  return -1;
}
for (struct addrinfo *ai = addrs; ai; ai = ai->ai_next) {
  // do something with ai->ai_addr etc here
}
freeaddrinfo(addrs);
return 0;

You'll need to adjust the lines marked "adjust" for your application. You'll also need to supply a port number (inconveniently, it takes this as a string, because it can also accept a protocol name).

The advantages of doing it this way are: Each entry in the addrs linked list has all the data you need to create and connect a socket to that address; it seamlessly handles IPv6 for you; and, if you take out the AI_NUMERICHOST, it seamlessly handles domain names for you as well.

zwol
  • 135,547
  • 38
  • 252
  • 361