1 | |
2 | // vim:sw=2:ai |
3 | |
4 | /* |
5 | * Copyright (C) 2010-2011 DeNA Co.,Ltd.. All rights reserved. |
6 | * Copyright (C) 2011-2017 Kentoku SHIBA |
7 | * See COPYRIGHT.txt for details. |
8 | */ |
9 | |
10 | #include <my_global.h> |
11 | #include <my_config.h> |
12 | #ifndef __WIN__ |
13 | #include <sys/types.h> |
14 | #include <sys/un.h> |
15 | #endif |
16 | |
17 | #include "mysql_version.h" |
18 | #include "hs_compat.h" |
19 | #if MYSQL_VERSION_ID < 50500 |
20 | #include "mysql_priv.h" |
21 | #include <mysql/plugin.h> |
22 | #else |
23 | #if defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 100000 |
24 | #include <my_global.h> |
25 | #endif |
26 | #include "sql_priv.h" |
27 | #include "probes_mysql.h" |
28 | #endif |
29 | |
30 | #include "socket.hpp" |
31 | #include "string_util.hpp" |
32 | #include "fatal.hpp" |
33 | |
34 | /* |
35 | struct sockaddr_un { |
36 | short sun_family; |
37 | char sun_path[108]; |
38 | }; |
39 | */ |
40 | |
41 | namespace dena { |
42 | |
43 | void |
44 | ignore_sigpipe() |
45 | { |
46 | #if defined(SIGPIPE) && !defined(__WIN__) |
47 | if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { |
48 | fatal_abort("SIGPIPE SIG_IGN" ); |
49 | } |
50 | #endif |
51 | } |
52 | |
53 | void |
54 | socket_args::set(const config& conf) |
55 | { |
56 | timeout = (int) conf.get_int("timeout" , 600); |
57 | listen_backlog = (int) conf.get_int("listen_backlog" , 256); |
58 | String node = conf.get_str("host" , "" ); |
59 | String port = conf.get_str("port" , "" ); |
60 | if (node.length() || port.length()) { |
61 | if (family == AF_UNIX || !strcmp(node.c_ptr(), "/" )) { |
62 | set_unix_domain(port.c_ptr()); |
63 | } else { |
64 | const char *nd = !node.length() ? 0 : node.c_ptr(); |
65 | if (resolve(nd, port.c_ptr()) != 0) { |
66 | String message("getaddrinfo failed: " , &my_charset_bin); |
67 | message.reserve(node.length() + sizeof(":" ) - 1 + port.length()); |
68 | message.append(node); |
69 | message.q_append(":" , sizeof(":" ) - 1); |
70 | message.append(port); |
71 | fatal_abort(message); |
72 | } |
73 | } |
74 | } |
75 | sndbuf = (int) conf.get_int("sndbuf" , 0); |
76 | rcvbuf = (int) conf.get_int("rcvbuf" , 0); |
77 | } |
78 | |
79 | void |
80 | socket_args::set_unix_domain(const char *path) |
81 | { |
82 | #ifndef __WIN__ |
83 | family = AF_UNIX; |
84 | addr = sockaddr_storage(); |
85 | addrlen = sizeof(sockaddr_un); |
86 | sockaddr_un *const ap = reinterpret_cast<sockaddr_un *>(&addr); |
87 | ap->sun_family = AF_UNIX; |
88 | strncpy(ap->sun_path, path, sizeof(ap->sun_path) - 1); |
89 | #endif |
90 | } |
91 | |
92 | int |
93 | socket_args::resolve(const char *node, const char *service) |
94 | { |
95 | const int flags = (node == 0) ? AI_PASSIVE : 0; |
96 | auto_addrinfo ai; |
97 | addr = sockaddr_storage(); |
98 | addrlen = 0; |
99 | const int r = ai.resolve(node, service, flags, family, socktype, protocol); |
100 | if (r != 0) { |
101 | return r; |
102 | } |
103 | memcpy(&addr, ai.get()->ai_addr, ai.get()->ai_addrlen); |
104 | addrlen = ai.get()->ai_addrlen; |
105 | return 0; |
106 | } |
107 | |
108 | int |
109 | socket_set_timeout(auto_file& fd, const socket_args& args, String& err_r) |
110 | { |
111 | if (!args.nonblocking) { |
112 | #if defined(SO_SNDTIMEO) && defined(SO_RCVTIMEO) |
113 | if (args.recv_timeout != 0) { |
114 | #ifndef __WIN__ |
115 | struct timeval tv; |
116 | tv.tv_sec = args.recv_timeout; |
117 | tv.tv_usec = 0; |
118 | #else |
119 | int tv = args.recv_timeout * 1000; |
120 | #endif |
121 | if (setsockopt(fd.get(), SOL_SOCKET, SO_RCVTIMEO, |
122 | #ifndef __WIN__ |
123 | (const void *) &tv, |
124 | #else |
125 | (const char *) &tv, |
126 | #endif |
127 | sizeof(tv)) != 0) { |
128 | return errno_string("setsockopt SO_RCVTIMEO" , errno, err_r); |
129 | } |
130 | } |
131 | if (args.send_timeout != 0) { |
132 | #ifndef __WIN__ |
133 | struct timeval tv; |
134 | tv.tv_sec = args.send_timeout; |
135 | tv.tv_usec = 0; |
136 | #else |
137 | int tv = args.send_timeout * 1000; |
138 | #endif |
139 | if (setsockopt(fd.get(), SOL_SOCKET, SO_SNDTIMEO, |
140 | #ifndef __WIN__ |
141 | (const void *) &tv, |
142 | #else |
143 | (const char *) &tv, |
144 | #endif |
145 | sizeof(tv)) != 0) { |
146 | return errno_string("setsockopt SO_SNDTIMEO" , errno, err_r); |
147 | } |
148 | } |
149 | #endif |
150 | } |
151 | return 0; |
152 | } |
153 | |
154 | int |
155 | socket_set_options(auto_file& fd, const socket_args& args, String& err_r) |
156 | { |
157 | if (args.timeout != 0 && !args.nonblocking) { |
158 | #if defined(SO_SNDTIMEO) && defined(SO_RCVTIMEO) |
159 | #ifndef __WIN__ |
160 | struct timeval tv; |
161 | tv.tv_sec = args.timeout; |
162 | tv.tv_usec = 0; |
163 | #else |
164 | int tv = args.timeout * 1000; |
165 | #endif |
166 | if (setsockopt(fd.get(), SOL_SOCKET, SO_RCVTIMEO, |
167 | #ifndef __WIN__ |
168 | (const void *) &tv, |
169 | #else |
170 | (const char *) &tv, |
171 | #endif |
172 | sizeof(tv)) != 0) { |
173 | return errno_string("setsockopt SO_RCVTIMEO" , errno, err_r); |
174 | } |
175 | #ifndef __WIN__ |
176 | tv.tv_sec = args.timeout; |
177 | tv.tv_usec = 0; |
178 | #else |
179 | tv = args.timeout * 1000; |
180 | #endif |
181 | if (setsockopt(fd.get(), SOL_SOCKET, SO_SNDTIMEO, |
182 | #ifndef __WIN__ |
183 | (const void *) &tv, |
184 | #else |
185 | (const char *) &tv, |
186 | #endif |
187 | sizeof(tv)) != 0) { |
188 | return errno_string("setsockopt SO_RCVTIMEO" , errno, err_r); |
189 | } |
190 | #endif |
191 | } |
192 | #ifndef __WIN__ |
193 | if (args.nonblocking && fcntl(fd.get(), F_SETFL, O_NONBLOCK) != 0) { |
194 | return errno_string("fcntl O_NONBLOCK" , errno, err_r); |
195 | } |
196 | #endif |
197 | if (args.sndbuf != 0) { |
198 | const int v = args.sndbuf; |
199 | if (setsockopt(fd.get(), SOL_SOCKET, SO_SNDBUF, |
200 | #ifndef __WIN__ |
201 | (const void *) &v, |
202 | #else |
203 | (const char *) &v, |
204 | #endif |
205 | sizeof(v)) != 0) { |
206 | return errno_string("setsockopt SO_SNDBUF" , errno, err_r); |
207 | } |
208 | } |
209 | if (args.rcvbuf != 0) { |
210 | const int v = args.rcvbuf; |
211 | if (setsockopt(fd.get(), SOL_SOCKET, SO_RCVBUF, |
212 | #ifndef __WIN__ |
213 | (const void *) &v, |
214 | #else |
215 | (const char *) &v, |
216 | #endif |
217 | sizeof(v)) != 0) { |
218 | return errno_string("setsockopt SO_RCVBUF" , errno, err_r); |
219 | } |
220 | } |
221 | return 0; |
222 | } |
223 | |
224 | int |
225 | socket_open(auto_file& fd, const socket_args& args, String& err_r) |
226 | { |
227 | fd.reset((int) socket(args.family, args.socktype, args.protocol)); |
228 | if (fd.get() < 0) { |
229 | return errno_string("socket" , errno, err_r); |
230 | } |
231 | return socket_set_options(fd, args, err_r); |
232 | } |
233 | |
234 | int |
235 | socket_connect(auto_file& fd, const socket_args& args, String& err_r) |
236 | { |
237 | int r = 0; |
238 | if ((r = socket_open(fd, args, err_r)) != 0) { |
239 | return r; |
240 | } |
241 | if (connect(fd.get(), reinterpret_cast<const sockaddr *>(&args.addr), |
242 | args.addrlen) != 0) { |
243 | if (!args.nonblocking |
244 | #ifndef __WIN__ |
245 | || errno != EINPROGRESS |
246 | #endif |
247 | ) { |
248 | return errno_string("connect" , errno, err_r); |
249 | } |
250 | } |
251 | return 0; |
252 | } |
253 | |
254 | int |
255 | socket_bind(auto_file& fd, const socket_args& args, String& err_r) |
256 | { |
257 | fd.reset((int) socket(args.family, args.socktype, args.protocol)); |
258 | if (fd.get() < 0) { |
259 | return errno_string("socket" , errno, err_r); |
260 | } |
261 | if (args.reuseaddr) { |
262 | #ifndef __WIN__ |
263 | if (args.family == AF_UNIX) { |
264 | const sockaddr_un *const ap = |
265 | reinterpret_cast<const sockaddr_un *>(&args.addr); |
266 | if (unlink(ap->sun_path) != 0 && errno != ENOENT) { |
267 | return errno_string("unlink uds" , errno, err_r); |
268 | } |
269 | } else { |
270 | #endif |
271 | int v = 1; |
272 | if (setsockopt(fd.get(), SOL_SOCKET, SO_REUSEADDR, |
273 | #ifndef __WIN__ |
274 | (const void *) &v, |
275 | #else |
276 | (const char *) &v, |
277 | #endif |
278 | sizeof(v)) != 0) { |
279 | return errno_string("setsockopt SO_REUSEADDR" , errno, err_r); |
280 | } |
281 | #ifndef __WIN__ |
282 | } |
283 | #endif |
284 | } |
285 | if (bind(fd.get(), reinterpret_cast<const sockaddr *>(&args.addr), |
286 | args.addrlen) != 0) { |
287 | return errno_string("bind" , errno, err_r); |
288 | } |
289 | if (listen(fd.get(), args.listen_backlog) != 0) { |
290 | return errno_string("listen" , errno, err_r); |
291 | } |
292 | #ifndef __WIN__ |
293 | if (args.nonblocking && fcntl(fd.get(), F_SETFL, O_NONBLOCK) != 0) { |
294 | return errno_string("fcntl O_NONBLOCK" , errno, err_r); |
295 | } |
296 | #endif |
297 | return 0; |
298 | } |
299 | |
300 | int |
301 | socket_accept(int listen_fd, auto_file& fd, const socket_args& args, |
302 | sockaddr_storage& addr_r, socklen_t& addrlen_r, String& err_r) |
303 | { |
304 | fd.reset((int) accept(listen_fd, reinterpret_cast<sockaddr *>(&addr_r), |
305 | &addrlen_r)); |
306 | if (fd.get() < 0) { |
307 | return errno_string("accept" , errno, err_r); |
308 | } |
309 | return socket_set_options(fd, args, err_r); |
310 | } |
311 | |
312 | }; |
313 | |
314 | |