da_util.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. /*
  2. * Copyright [2021] JD.com, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "da_util.h"
  17. #include "da_string.h"
  18. #include "da_log.h"
  19. static void log_and_exit(const char *cond, const char *file, int line,
  20. int panic) {
  21. log_error("assert '%s' failed @ (%s, %d)", cond, file, line);
  22. if (panic) {
  23. abort();
  24. }
  25. }
  26. void da_assert(const char * cond, const char *file, int line, int panic) {
  27. log_and_exit(cond, file, line, panic);
  28. }
  29. /*
  30. * copies at most <size-1> chars from <src> to <dst>. Last char is always
  31. * set to 0, unless <size> is 0. The number of chars copied is returned
  32. * (excluding the terminating zero).
  33. */
  34. int da_strlcpy(char *dst, const char *src, int size) {
  35. char *orig = dst;
  36. if (size) {
  37. while (--size && (*dst = *src)) {
  38. src++;
  39. dst++;
  40. }
  41. *dst = 0;
  42. }
  43. return dst - orig;
  44. }
  45. /*
  46. * net work utils
  47. */
  48. int set_reuseaddr(int fd) {
  49. int reuse;
  50. socklen_t len;
  51. reuse = 1;
  52. len = sizeof(reuse);
  53. return setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, len);
  54. }
  55. int set_nonblocking(int fd) {
  56. int flags;
  57. flags = fcntl(fd, F_GETFL, 0);
  58. if (flags < 0) {
  59. return flags;
  60. }
  61. return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
  62. }
  63. int get_soerror(int sd) {
  64. int status, err;
  65. socklen_t len;
  66. err = 0;
  67. len = sizeof(err);
  68. status = getsockopt(sd, SOL_SOCKET, SO_ERROR, &err, &len);
  69. if (status == 0) {
  70. errno = err;
  71. }
  72. return status;
  73. }
  74. bool nc_valid_port(int n) {
  75. if (n < 1 || n > UINT16_MAX) {
  76. return false;
  77. }
  78. return true;
  79. }
  80. /*
  81. * Disable Nagle algorithm on TCP socket.
  82. *
  83. * This option helps to minimize transmit latency by disabling coalescing
  84. * of data to fill up a TCP segment inside the kernel. Sockets with this
  85. * option must use readv() or writev() to do data transfer in bulk and
  86. * hence avoid the overhead of small packets.
  87. */
  88. int set_tcpnodelay(int fd) {
  89. int nodelay;
  90. socklen_t len;
  91. nodelay = 1;
  92. len = sizeof(nodelay);
  93. return setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &nodelay, len);
  94. }
  95. int set_tcpquickack(int fd)
  96. {
  97. int quickack;
  98. socklen_t len;
  99. quickack = 1;
  100. len = sizeof(quickack);
  101. return setsockopt(fd, IPPROTO_TCP, TCP_QUICKACK, &quickack, len);
  102. }
  103. ssize_t _da_sendn(int sd, const void *vptr, size_t n) {
  104. size_t nleft;
  105. ssize_t nsend;
  106. const char *ptr;
  107. ptr = vptr;
  108. nleft = n;
  109. while (nleft > 0) {
  110. nsend = send(sd, ptr, nleft, 0);
  111. if (nsend < 0) {
  112. if (errno == EINTR) {
  113. continue;
  114. }
  115. return nsend;
  116. }
  117. if (nsend == 0) {
  118. return -1;
  119. }
  120. nleft -= (size_t) nsend;
  121. ptr += nsend;
  122. }
  123. return (ssize_t) n;
  124. }
  125. ssize_t _da_recvn(int sd, void *vptr, size_t n) {
  126. size_t nleft;
  127. ssize_t nrecv;
  128. char *ptr;
  129. ptr = vptr;
  130. nleft = n;
  131. while (nleft > 0) {
  132. nrecv = recv(sd, ptr, nleft, 0);
  133. if (nrecv < 0) {
  134. if (errno == EINTR) {
  135. continue;
  136. }
  137. return nrecv;
  138. }
  139. if (nrecv == 0) {
  140. break;
  141. }
  142. nleft -= (size_t) nrecv;
  143. ptr += nrecv;
  144. }
  145. return (ssize_t) (n - nleft);
  146. }
  147. char upper(char c)
  148. {
  149. if (c >='a' && c <='z')
  150. c &= 0xDF;
  151. return c;
  152. }
  153. char lower(char c)
  154. {
  155. if(c >= 'A' && c <= 'Z')
  156. c |=0x20;
  157. return c;
  158. }
  159. int _vscnprintf(char *buf, size_t size, const char *fmt, va_list args) {
  160. int n;
  161. n = vsnprintf(buf, size, fmt, args);
  162. /*
  163. * The return value is the number of characters which would be written
  164. * into buf not including the trailing '\0'. If size is == 0 the
  165. * function returns 0.
  166. *
  167. * On error, the function also returns 0. This is to allow idiom such
  168. * as len += _vscnprintf(...)
  169. *
  170. * See: http://lwn.net/Articles/69419/
  171. */
  172. if (n <= 0) {
  173. return 0;
  174. }
  175. if (n < (int) size) {
  176. return n;
  177. }
  178. return (int) (size - 1);
  179. }
  180. int _scnprintf(char *buf, size_t size, const char *fmt, ...) {
  181. va_list args;
  182. int n;
  183. va_start(args, fmt);
  184. n = _vscnprintf(buf, size, fmt, args);
  185. va_end(args);
  186. return n;
  187. }
  188. int _da_atoi(uint8_t *line, size_t n) {
  189. int value;
  190. if (n == 0) {
  191. return -1;
  192. }
  193. for (value = 0; n--; line++) {
  194. if (*line < '0' || *line > '9') {
  195. return -1;
  196. }
  197. value = value * 10 + (*line - '0');
  198. }
  199. if (value < 0) {
  200. return -1;
  201. }
  202. return value;
  203. }
  204. /*
  205. * Unresolve the socket descriptor peer address by translating it to a
  206. * character string describing the host and service
  207. *
  208. * This routine is not reentrant
  209. */
  210. char *
  211. da_unresolve_peer_desc(int sd) {
  212. static struct sockinfo si;
  213. struct sockaddr *addr;
  214. socklen_t addrlen;
  215. int status;
  216. memset(&si, 0, sizeof(si));
  217. addr = (struct sockaddr *) &si.addr;
  218. addrlen = sizeof(si.addr);
  219. status = getpeername(sd, addr, &addrlen);
  220. if (status < 0) {
  221. return "unknown";
  222. }
  223. return da_unresolve_addr(addr, addrlen);
  224. }
  225. static int da_resolve_unix(struct string *name, struct sockinfo *si) {
  226. struct sockaddr_un *un;
  227. if (name->len >= DA_UNIX_ADDRSTRLEN) {
  228. return -1;
  229. }
  230. un = &si->addr.un;
  231. un->sun_family = AF_UNIX;
  232. da_memcpy(un->sun_path, name->data, name->len);
  233. un->sun_path[name->len] = '\0';
  234. si->family = AF_UNIX;
  235. si->addrlen = sizeof(*un);
  236. /* si->addr is an alias of un */
  237. return 0;
  238. }
  239. static int da_resolve_inet(struct string *name, int port, struct sockinfo *si) {
  240. int status;
  241. struct addrinfo *ai, *cai; /* head and current addrinfo */
  242. struct addrinfo hints;
  243. char *node, service[DA_UINTMAX_MAXLEN];
  244. bool found;
  245. ASSERT(da_valid_port(port));
  246. memset(&hints, 0, sizeof(hints));
  247. hints.ai_flags = AI_NUMERICSERV;
  248. hints.ai_family = AF_UNSPEC; /* AF_INET or AF_INET6 */
  249. hints.ai_socktype = SOCK_STREAM;
  250. hints.ai_protocol = 0;
  251. hints.ai_addrlen = 0;
  252. hints.ai_addr = NULL;
  253. hints.ai_canonname = NULL;
  254. if (name != NULL) {
  255. node = (char *) name->data;
  256. } else {
  257. /*
  258. * If AI_PASSIVE flag is specified in hints.ai_flags, and node is
  259. * NULL, then the returned socket addresses will be suitable for
  260. * bind(2)ing a socket that will accept(2) connections. The returned
  261. * socket address will contain the wildcard IP address.
  262. */
  263. node = NULL;
  264. hints.ai_flags |= AI_PASSIVE;
  265. }
  266. da_snprintf(service, DA_UINTMAX_MAXLEN, "%d", port);
  267. status = getaddrinfo(node, service, &hints, &ai);
  268. if (status < 0) {
  269. log_error("address resolution of node '%s' service '%s' failed: %s",
  270. node, service, gai_strerror(status));
  271. return -1;
  272. }
  273. /*
  274. * getaddrinfo() can return a linked list of more than one addrinfo,
  275. * since we requested for both AF_INET and AF_INET6 addresses and the
  276. * host itself can be multi-homed. Since we don't care whether we are
  277. * using ipv4 or ipv6, we just use the first address from this collection
  278. * in the order in which it was returned.
  279. *
  280. * The sorting function used within getaddrinfo() is defined in RFC 3484;
  281. * the order can be tweaked for a particular system by editing
  282. * /etc/gai.conf
  283. */
  284. for (cai = ai, found = false; cai != NULL; cai = cai->ai_next) {
  285. si->family = cai->ai_family;
  286. si->addrlen = cai->ai_addrlen;
  287. da_memcpy(&si->addr, cai->ai_addr, si->addrlen);
  288. found = true;
  289. break;
  290. }
  291. freeaddrinfo(ai);
  292. return !found ? -1 : 0;
  293. }
  294. /*
  295. * Resolve a hostname and service by translating it to socket address and
  296. * return it in si
  297. *
  298. * This routine is reentrant
  299. */
  300. int da_resolve(struct string *name, int port, struct sockinfo *si) {
  301. if (name != NULL && name->data[0] == '/') {
  302. return da_resolve_unix(name, si);
  303. }
  304. return da_resolve_inet(name, port, si);
  305. }
  306. char *da_unresolve_addr(struct sockaddr *addr, socklen_t addrlen) {
  307. static char unresolve[NI_MAXHOST + NI_MAXSERV];
  308. static char host[NI_MAXHOST], service[NI_MAXSERV];
  309. int status;
  310. status = getnameinfo(addr, addrlen, host, sizeof(host), service,
  311. sizeof(service),NI_NUMERICHOST | NI_NUMERICSERV);
  312. if (status < 0) {
  313. return "unknown";
  314. }
  315. da_snprintf(unresolve, sizeof(unresolve), "%s:%s", host, service);
  316. return unresolve;
  317. }
  318. /*
  319. * Unresolve the socket descriptor address by translating it to a
  320. * character string describing the host and service
  321. *
  322. * This routine is not reentrant
  323. */
  324. char *da_unresolve_desc(int sd)
  325. {
  326. static struct sockinfo si;
  327. struct sockaddr *addr;
  328. socklen_t addrlen;
  329. int status;
  330. memset(&si, 0, sizeof(si));
  331. addr = (struct sockaddr *)&si.addr;
  332. addrlen = sizeof(si.addr);
  333. status = getsockname(sd, addr, &addrlen);
  334. if (status < 0) {
  335. return "unknown";
  336. }
  337. return da_unresolve_addr(addr, addrlen);
  338. }
  339. bool da_valid_port(int n)
  340. {
  341. if (n < 1 || n > UINT16_MAX) {
  342. return false;
  343. }
  344. return true;
  345. }
  346. int64_t nc_usec_now(void)
  347. {
  348. struct timeval now;
  349. int64_t usec;
  350. int status;
  351. status = gettimeofday(&now, NULL);
  352. if (status < 0) {
  353. log_error("gettimeofday failed: %s", strerror(errno));
  354. return -1;
  355. }
  356. usec = (int64_t)now.tv_sec * 1000000LL + (int64_t)now.tv_usec;
  357. return usec;
  358. }