/*
 * Copyright ©2026 Soham Pardeshi. All rights reserved.
 * Permission is hereby granted to students registered for University of
 * Washington CSE 333 for use solely during Summer Quarter 2026 for
 * purposes of the course. No other use, copying, distribution, or
 * modification is permitted without prior written consent. Copyrights
 * for third-party components of this work must be honored. Instructors
 * interested in reusing these course materials should contact the author.
 */

#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>

#include <cstdlib>
#include <cstring>
#include <iostream>

// Addresses in the sockets API are BINARY, inside a struct, in network
// byte order -- not strings. This program converts between the two forms:
//
//   inet_pton  "presentation" (text) -> network (binary, in the struct)
//   inet_ntop  network (binary)      -> presentation (text)
//
// Note that IPv4 and IPv6 use different structs (sockaddr_in vs.
// sockaddr_in6) of different sizes, which is why generic code passes
// around a struct sockaddr* plus a length, and why sockaddr_storage
// exists (it is big enough for either family).
int main(int argc, char** argv) {
  struct sockaddr_in sa;    // IPv4
  struct sockaddr_in6 sa6;  // IPv6
  memset(&sa, 0, sizeof(sa));
  memset(&sa6, 0, sizeof(sa6));

  sa.sin_family = AF_INET;
  sa6.sin6_family = AF_INET6;

  // Text -> binary, written directly into the address field of the struct.
  inet_pton(AF_INET, "128.95.4.1", &(sa.sin_addr));
  inet_pton(AF_INET6, "2001:db8:63b3:1::3490", &(sa6.sin6_addr));

  // Ports are also in the struct, and also in network (big-endian) order:
  // htons() converts from host order. Forgetting this is a classic bug.
  sa.sin_port = htons(80);

  // Binary -> text. The caller supplies the buffer and its size; the
  // INET*_ADDRSTRLEN constants are the required sizes.
  char v4[INET_ADDRSTRLEN];
  char v6[INET6_ADDRSTRLEN];
  inet_ntop(AF_INET, &(sa.sin_addr), v4, INET_ADDRSTRLEN);
  inet_ntop(AF_INET6, &(sa6.sin6_addr), v6, INET6_ADDRSTRLEN);

  std::cout << "IPv4: " << v4 << " port " << ntohs(sa.sin_port) << std::endl;
  std::cout << "IPv6: " << v6 << std::endl;
  std::cout << "sizeof(sockaddr_in)      = " << sizeof(sa) << std::endl;
  std::cout << "sizeof(sockaddr_in6)     = " << sizeof(sa6) << std::endl;
  std::cout << "sizeof(sockaddr_storage) = "
            << sizeof(struct sockaddr_storage) << std::endl;

  return EXIT_SUCCESS;
}