1 /*
2  * twemproxy - A fast and lightweight proxy for memcached protocol.
3  * Copyright (C) 2011 Twitter, Inc.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #ifndef _NC_UTIL_H_
19 #define _NC_UTIL_H_
20 
21 #include <stdarg.h>
22 
23 #ifdef __GNUC__
24 # define NC_GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__)
25 #else
26 # define NC_GCC_VERSION 0
27 #endif
28 #if NC_GCC_VERSION >= 2007
29 #define NC_ATTRIBUTE_FORMAT(type, idx, first) __attribute__ ((format(type, idx, first)))
30 #else
31 #define NC_ATTRIBUTE_FORMAT(type, idx, first)
32 #endif
33 
34 
35 #define LF                  (uint8_t) 10
36 #define CR                  (uint8_t) 13
37 #define CRLF                "\x0d\x0a"
38 #define CRLF_LEN            (sizeof("\x0d\x0a") - 1)
39 
40 #define NELEMS(a)           ((sizeof(a)) / sizeof((a)[0]))
41 
42 #define MIN(a, b)           ((a) < (b) ? (a) : (b))
43 #define MAX(a, b)           ((a) > (b) ? (a) : (b))
44 
45 #define SQUARE(d)           ((d) * (d))
46 #define VAR(s, s2, n)       (((n) < 2) ? 0.0 : ((s2) - SQUARE(s)/(n)) / ((n) - 1))
47 #define STDDEV(s, s2, n)    (((n) < 2) ? 0.0 : sqrt(VAR((s), (s2), (n))))
48 
49 #define NC_INET4_ADDRSTRLEN (sizeof("255.255.255.255") - 1)
50 #define NC_INET6_ADDRSTRLEN \
51     (sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") - 1)
52 #define NC_INET_ADDRSTRLEN  MAX(NC_INET4_ADDRSTRLEN, NC_INET6_ADDRSTRLEN)
53 #define NC_UNIX_ADDRSTRLEN  \
54     (sizeof(struct sockaddr_un) - offsetof(struct sockaddr_un, sun_path))
55 
56 #define NC_MAXHOSTNAMELEN   256
57 
58 /*
59  * Length of 1 byte, 2 bytes, 4 bytes, 8 bytes and largest integral
60  * type (uintmax_t) in ascii, including the null terminator '\0'
61  *
62  * From stdint.h, we have:
63  * # define UINT8_MAX	(255)
64  * # define UINT16_MAX	(65535)
65  * # define UINT32_MAX	(4294967295U)
66  * # define UINT64_MAX	(__UINT64_C(18446744073709551615))
67  */
68 #define NC_UINT8_MAXLEN     (3 + 1)
69 #define NC_UINT16_MAXLEN    (5 + 1)
70 #define NC_UINT32_MAXLEN    (10 + 1)
71 #define NC_UINT64_MAXLEN    (20 + 1)
72 #define NC_UINTMAX_MAXLEN   NC_UINT64_MAXLEN
73 
74 /*
75  * Make data 'd' or pointer 'p', n-byte aligned, where n is a power of 2
76  * of 2.
77  */
78 #define NC_ALIGNMENT        sizeof(unsigned long) /* platform word */
79 #define NC_ALIGN(d, n)      (((d) + (n - 1)) & ~(n - 1))
80 #define NC_ALIGN_PTR(p, n)  \
81     (void *) (((uintptr_t) (p) + ((uintptr_t) n - 1)) & ~((uintptr_t) n - 1))
82 
83 /*
84  * Wrapper to workaround well known, safe, implicit type conversion when
85  * invoking system calls.
86  */
87 #define nc_gethostname(_name, _len) \
88     gethostname((char *)_name, (size_t)_len)
89 
90 #define nc_atoi(_line, _n)          \
91     _nc_atoi((uint8_t *)_line, (size_t)_n)
92 
93 int nc_set_blocking(int sd);
94 int nc_set_nonblocking(int sd);
95 int nc_set_reuseaddr(int sd);
96 int nc_set_tcpnodelay(int sd);
97 int nc_set_linger(int sd, int timeout);
98 int nc_set_sndbuf(int sd, int size);
99 int nc_set_rcvbuf(int sd, int size);
100 int nc_set_tcpkeepalive(int sd);
101 int nc_get_soerror(int sd);
102 int nc_get_sndbuf(int sd);
103 int nc_get_rcvbuf(int sd);
104 
105 int _nc_atoi(const uint8_t *line, size_t n);
106 bool nc_valid_port(int n);
107 
108 /*
109  * Memory allocation and free wrappers.
110  *
111  * These wrappers enables us to loosely detect double free, dangling
112  * pointer access and zero-byte alloc.
113  */
114 #define nc_alloc(_s)                    \
115     _nc_alloc((size_t)(_s), __FILE__, __LINE__)
116 
117 #define nc_zalloc(_s)                   \
118     _nc_zalloc((size_t)(_s), __FILE__, __LINE__)
119 
120 #define nc_calloc(_n, _s)               \
121     _nc_calloc((size_t)(_n), (size_t)(_s), __FILE__, __LINE__)
122 
123 #define nc_realloc(_p, _s)              \
124     _nc_realloc(_p, (size_t)(_s), __FILE__, __LINE__)
125 
126 #define nc_free(_p) do {                \
127     _nc_free(_p, __FILE__, __LINE__);   \
128     (_p) = NULL;                        \
129 } while (0)
130 
131 void *_nc_alloc(size_t size, const char *name, int line);
132 void *_nc_zalloc(size_t size, const char *name, int line);
133 void *_nc_calloc(size_t nmemb, size_t size, const char *name, int line);
134 void *_nc_realloc(void *ptr, size_t size, const char *name, int line);
135 void _nc_free(void *ptr, const char *name, int line);
136 
137 /*
138  * Wrappers to send or receive n byte message on a blocking
139  * socket descriptor.
140  */
141 #define nc_sendn(_s, _b, _n)    \
142     _nc_sendn(_s, _b, (size_t)(_n))
143 
144 #define nc_recvn(_s, _b, _n)    \
145     _nc_recvn(_s, _b, (size_t)(_n))
146 
147 /*
148  * Wrappers to read or write data to/from (multiple) buffers
149  * to a file or socket descriptor.
150  */
151 #define nc_read(_d, _b, _n)     \
152     read(_d, _b, (size_t)(_n))
153 
154 #define nc_readv(_d, _b, _n)    \
155     readv(_d, _b, (int)(_n))
156 
157 #define nc_write(_d, _b, _n)    \
158     write(_d, _b, (size_t)(_n))
159 
160 #define nc_writev(_d, _b, _n)   \
161     writev(_d, _b, (int)(_n))
162 
163 ssize_t _nc_sendn(int sd, const void *vptr, size_t n);
164 ssize_t _nc_recvn(int sd, void *vptr, size_t n);
165 
166 /*
167  * Wrappers for defining custom assert based on whether macro
168  * NC_ASSERT_PANIC or NC_ASSERT_LOG was defined at the moment
169  * ASSERT was called.
170  */
171 #ifdef NC_ASSERT_PANIC
172 
173 #define ASSERT(_x) do {                         \
174     if (!(_x)) {                                \
175         nc_assert(#_x, __FILE__, __LINE__, 1);  \
176     }                                           \
177 } while (0)
178 
179 #define NOT_REACHED() ASSERT(0)
180 
181 #elif NC_ASSERT_LOG
182 
183 #define ASSERT(_x) do {                         \
184     if (!(_x)) {                                \
185         nc_assert(#_x, __FILE__, __LINE__, 0);  \
186     }                                           \
187 } while (0)
188 
189 #define NOT_REACHED() ASSERT(0)
190 
191 #else
192 
193 #define ASSERT(_x)
194 
195 #define NOT_REACHED()
196 
197 #endif
198 
199 void nc_assert(const char *cond, const char *file, int line, int panic);
200 void nc_stacktrace(int skip_count);
201 void nc_stacktrace_fd(int fd);
202 
203 int _scnprintf(char *buf, size_t size, const char *fmt, ...) NC_ATTRIBUTE_FORMAT(printf, 3, 4);
204 int _vscnprintf(char *buf, size_t size, const char *fmt, va_list args);
205 int64_t nc_usec_now(void);
206 int64_t nc_msec_now(void);
207 
208 /*
209  * Address resolution for internet (ipv4 and ipv6) and unix domain
210  * socket address.
211  */
212 
213 struct sockinfo {
214     int       family;              /* socket address family */
215     socklen_t addrlen;             /* socket address length */
216     union {
217         struct sockaddr_in  in;    /* ipv4 socket address */
218         struct sockaddr_in6 in6;   /* ipv6 socket address */
219         struct sockaddr_un  un;    /* unix domain address */
220     } addr;
221 };
222 
223 int nc_resolve(const struct string *name, int port, struct sockinfo *si);
224 const char *nc_unresolve_addr(struct sockaddr *addr, socklen_t addrlen);
225 const char *nc_unresolve_peer_desc(int sd);
226 const char *nc_unresolve_desc(int sd);
227 
228 #endif
229