netclient.cc 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. // CODYlib -*- mode:c++ -*-
  2. // Copyright (C) 2020 Nathan Sidwell, nathan@acm.org
  3. // License: Apache v2.0
  4. // Cody
  5. #include "internal.hh"
  6. #if CODY_NETWORKING
  7. // C
  8. #include <cerrno>
  9. #include <cstring>
  10. // OS
  11. #include <netdb.h>
  12. #include <unistd.h>
  13. #include <arpa/inet.h>
  14. #include <netinet/in.h>
  15. #include <sys/un.h>
  16. #ifndef AI_NUMERICSERV
  17. #define AI_NUMERICSERV 0
  18. #endif
  19. // Client-side networking helpers
  20. namespace Cody {
  21. int OpenSocket (char const **e, sockaddr const *addr, socklen_t len)
  22. {
  23. char const *errstr = nullptr;
  24. int fd = socket (addr->sa_family, SOCK_STREAM, 0);
  25. if (fd < 0)
  26. {
  27. errstr = "creating socket";
  28. fail:;
  29. int err = errno;
  30. if (e)
  31. *e = errstr;
  32. if (fd >= 0)
  33. close (fd);
  34. errno = err;
  35. return -1;
  36. }
  37. if (connect (fd, addr, len) < 0)
  38. {
  39. errstr = "connecting socket";
  40. goto fail;
  41. }
  42. return fd;
  43. }
  44. int OpenLocal (char const **e, char const *name)
  45. {
  46. sockaddr_un addr;
  47. size_t len = strlen (name);
  48. if (len >= sizeof (addr.sun_path))
  49. {
  50. errno = ENAMETOOLONG;
  51. return -1;
  52. }
  53. memset (&addr, 0, offsetof (sockaddr_un, sun_path));
  54. addr.sun_family = AF_UNIX;
  55. memcpy (addr.sun_path, name, len + 1);
  56. return OpenSocket (e, (sockaddr *)&addr, sizeof (addr));
  57. }
  58. int OpenInet6 (char const **e, char const *name, int port)
  59. {
  60. addrinfo *addrs = nullptr;
  61. int fd = -1;
  62. char const *errstr = nullptr;
  63. fd = socket (AF_INET6, SOCK_STREAM, 0);
  64. if (fd < 0)
  65. {
  66. errstr = "socket";
  67. fail:;
  68. int err = errno;
  69. if (e)
  70. *e = errstr;
  71. if (fd >= 0)
  72. close (fd);
  73. if (addrs)
  74. freeaddrinfo (addrs);
  75. errno = err;
  76. return -1;
  77. }
  78. addrinfo hints;
  79. hints.ai_flags = 0;
  80. hints.ai_family = AF_INET6;
  81. hints.ai_socktype = SOCK_STREAM;
  82. hints.ai_protocol = 0;
  83. hints.ai_addrlen = 0;
  84. hints.ai_addr = nullptr;
  85. hints.ai_canonname = nullptr;
  86. hints.ai_next = nullptr;
  87. if (int err = getaddrinfo (name, nullptr, &hints, &addrs))
  88. {
  89. errstr = gai_strerror (err);
  90. // What's the best errno to set?
  91. errno = 0;
  92. goto fail;
  93. }
  94. sockaddr_in6 addr;
  95. memset (&addr, 0, sizeof (addr));
  96. addr.sin6_family = AF_INET6;
  97. for (struct addrinfo *next = addrs; next; next = next->ai_next)
  98. if (next->ai_family == AF_INET6
  99. && next->ai_socktype == SOCK_STREAM)
  100. {
  101. sockaddr_in6 *in6 = (sockaddr_in6 *)next->ai_addr;
  102. in6->sin6_port = htons (port);
  103. if (ntohs (in6->sin6_port) != port)
  104. errno = EINVAL;
  105. else if (!connect (fd, next->ai_addr, next->ai_addrlen))
  106. goto done;
  107. }
  108. errstr = "connecting";
  109. goto fail;
  110. done:;
  111. freeaddrinfo (addrs);
  112. return fd;
  113. }
  114. }
  115. #endif