1 /* Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
2    Copyright (c) 2017, MariaDB Corporation.
3 
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7 
8 This program is also distributed with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation.  The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have included with MySQL.
14 
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 GNU General Public License, version 2.0, for more details.
19 
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23 02110-1335  USA
24 */
25 
26 #ifndef MYSQL_SOCKET_H
27 #define MYSQL_SOCKET_H
28 
29 /* For MY_STAT */
30 #include <my_dir.h>
31 /* For my_chsize */
32 #include <my_sys.h>
33 /* For socket api */
34 #ifdef __WIN__
35   #include <ws2def.h>
36   #include <winsock2.h>
37   #include <MSWSock.h>
38   #define SOCKBUF_T char
39 #else
40   #include <netinet/in.h>
41   #define SOCKBUF_T void
42 #endif
43 /**
44   @file mysql/psi/mysql_socket.h
45 [...]
46 */
47 
48 #include "mysql/psi/psi.h"
49 
50 /**
51   @defgroup Socket_instrumentation Socket Instrumentation
52   @ingroup Instrumentation_interface
53   @{
54 */
55 
56 /**
57   @def mysql_socket_register(P1, P2, P3)
58   Socket registration.
59 */
60 #ifdef HAVE_PSI_SOCKET_INTERFACE
61   #define mysql_socket_register(P1, P2, P3) \
62     inline_mysql_socket_register(P1, P2, P3)
63 #else
64   #define mysql_socket_register(P1, P2, P3) \
65     do {} while (0)
66 #endif
67 
68 struct st_mysql_socket
69 {
70   /** The real socket descriptor. */
71   my_socket fd;
72 
73   /**
74     The instrumentation hook.
75     Note that this hook is not conditionally defined,
76     for binary compatibility of the @c MYSQL_SOCKET interface.
77   */
78   struct PSI_socket *m_psi;
79 };
80 
81 /**
82   An instrumented socket.
83   @c MYSQL_SOCKET is a replacement for @c my_socket.
84 */
85 typedef struct st_mysql_socket MYSQL_SOCKET;
86 
87 
88 /**
89   @def MYSQL_INVALID_SOCKET
90   MYSQL_SOCKET initial value.
91 */
92 //MYSQL_SOCKET MYSQL_INVALID_SOCKET= {INVALID_SOCKET, NULL};
93 #define MYSQL_INVALID_SOCKET mysql_socket_invalid()
94 
95 /**
96   MYSQL_SOCKET helper. Initialize instrumented socket.
97   @sa mysql_socket_getfd
98   @sa mysql_socket_setfd
99 */
100 static inline MYSQL_SOCKET
mysql_socket_invalid()101 mysql_socket_invalid()
102 {
103   MYSQL_SOCKET mysql_socket= {INVALID_SOCKET, NULL};
104   return mysql_socket;
105 }
106 
107 /**
108   Set socket descriptor and address.
109   @param socket nstrumented socket
110   @param fd socket descriptor
111   @param addr unformatted socket address
112   @param adr_len length of socket address
113 */
114 
115 static inline void
mysql_socket_set_address(MYSQL_SOCKET socket,const struct sockaddr * addr,socklen_t addr_len)116 mysql_socket_set_address(
117 #ifdef HAVE_PSI_SOCKET_INTERFACE
118   MYSQL_SOCKET socket,
119   const struct sockaddr *addr,
120   socklen_t addr_len
121 #else
122   MYSQL_SOCKET socket __attribute__ ((unused)),
123   const struct sockaddr *addr __attribute__ ((unused)),
124   socklen_t addr_len __attribute__ ((unused))
125 #endif
126 )
127 {
128 #ifdef HAVE_PSI_SOCKET_INTERFACE
129   if (socket.m_psi != NULL)
130     PSI_SOCKET_CALL(set_socket_info)(socket.m_psi, NULL, addr, addr_len);
131 #endif
132 }
133 
134 /**
135   Set socket descriptor and address.
136   @param socket instrumented socket
137   @param thread instrumented owning thread
138 */
139 static inline void
mysql_socket_set_thread_owner(MYSQL_SOCKET socket)140 mysql_socket_set_thread_owner(
141 #ifdef HAVE_PSI_SOCKET_INTERFACE
142 MYSQL_SOCKET socket
143 #else
144 MYSQL_SOCKET socket __attribute__ ((unused))
145 #endif
146 )
147 {
148 #ifdef HAVE_PSI_SOCKET_INTERFACE
149   if (socket.m_psi != NULL)
150     PSI_SOCKET_CALL(set_socket_thread_owner)(socket.m_psi);
151 #endif
152 }
153 
154 /**
155   MYSQL_SOCKET helper. Get socket descriptor.
156   @param mysql_socket Instrumented socket
157   @sa mysql_socket_getfd
158 */
159 static inline my_socket
mysql_socket_getfd(MYSQL_SOCKET mysql_socket)160 mysql_socket_getfd(MYSQL_SOCKET mysql_socket)
161 {
162   return mysql_socket.fd;
163 }
164 
165 /**
166   MYSQL_SOCKET helper. Set socket descriptor.
167   @param mysql_socket Instrumented socket
168   @param fd Socket descriptor
169   @sa mysql_socket_setfd
170 */
171 static inline void
mysql_socket_setfd(MYSQL_SOCKET * mysql_socket,my_socket fd)172 mysql_socket_setfd(MYSQL_SOCKET *mysql_socket, my_socket fd)
173 {
174   if (likely(mysql_socket != NULL))
175     mysql_socket->fd= fd;
176 }
177 
178 /**
179   @def MYSQL_SOCKET_WAIT_VARIABLES
180   Instrumentation helper for socket waits.
181   This instrumentation declares local variables.
182   Do not use a ';' after this macro
183   @param LOCKER locker
184   @param STATE locker state
185   @sa MYSQL_START_SOCKET_WAIT.
186   @sa MYSQL_END_SOCKET_WAIT.
187 */
188 #ifdef HAVE_PSI_SOCKET_INTERFACE
189   #define MYSQL_SOCKET_WAIT_VARIABLES(LOCKER, STATE) \
190     struct PSI_socket_locker* LOCKER; \
191     PSI_socket_locker_state STATE;
192 #else
193   #define MYSQL_SOCKET_WAIT_VARIABLES(LOCKER, STATE)
194 #endif
195 
196 /**
197   @def MYSQL_START_SOCKET_WAIT
198   Instrumentation helper for socket waits.
199   This instrumentation marks the start of a wait event.
200   @param LOCKER locker
201   @param STATE locker state
202   @param SOCKET instrumented socket
203   @param OP The socket operation to be performed
204   @param FLAGS per-socket operation flags.
205   @param COUNT bytes to be written/read
206   @sa MYSQL_END_SOCKET_WAIT.
207 */
208 #ifdef HAVE_PSI_SOCKET_INTERFACE
209   #define MYSQL_START_SOCKET_WAIT(LOCKER, STATE, SOCKET, OP, COUNT) \
210     LOCKER= inline_mysql_start_socket_wait(STATE, SOCKET, OP, COUNT,\
211                                            __FILE__, __LINE__)
212 #else
213   #define MYSQL_START_SOCKET_WAIT(LOCKER, STATE, SOCKET, OP, COUNT) \
214     do {} while (0)
215 #endif
216 
217 /**
218   @def MYSQL_END_SOCKET_WAIT
219   Instrumentation helper for socket waits.
220   This instrumentation marks the end of a wait event.
221   @param LOCKER locker
222   @param COUNT actual bytes written/read, or -1
223   @sa MYSQL_START_SOCKET_WAIT.
224 */
225 #ifdef HAVE_PSI_SOCKET_INTERFACE
226   #define MYSQL_END_SOCKET_WAIT(LOCKER, COUNT) \
227     inline_mysql_end_socket_wait(LOCKER, COUNT)
228 #else
229   #define MYSQL_END_SOCKET_WAIT(LOCKER, COUNT) \
230     do {} while (0)
231 #endif
232 
233 #ifdef HAVE_PSI_SOCKET_INTERFACE
234   #define MYSQL_SOCKET_SET_STATE(SOCKET, STATE) \
235     inline_mysql_socket_set_state(SOCKET, STATE)
236 #else
237   #define MYSQL_SOCKET_SET_STATE(SOCKET, STATE) \
238     do {} while (0)
239 #endif
240 
241 #ifdef HAVE_PSI_SOCKET_INTERFACE
242 /**
243   Instrumentation calls for MYSQL_START_SOCKET_WAIT.
244   @sa MYSQL_START_SOCKET_WAIT.
245 */
246 static inline struct PSI_socket_locker*
inline_mysql_start_socket_wait(PSI_socket_locker_state * state,MYSQL_SOCKET mysql_socket,enum PSI_socket_operation op,size_t byte_count,const char * src_file,uint src_line)247 inline_mysql_start_socket_wait(PSI_socket_locker_state *state,
248                                MYSQL_SOCKET mysql_socket,
249                                enum PSI_socket_operation op,
250                                size_t byte_count,
251                                const char *src_file, uint src_line)
252 {
253   struct PSI_socket_locker *locker;
254   if (psi_likely(mysql_socket.m_psi != NULL))
255   {
256     locker= PSI_SOCKET_CALL(start_socket_wait)
257       (state, mysql_socket.m_psi, op, byte_count, src_file, src_line);
258   }
259   else
260     locker= NULL;
261   return locker;
262 }
263 
264 /**
265   Instrumentation calls for MYSQL_END_SOCKET_WAIT.
266   @sa MYSQL_END_SOCKET_WAIT.
267 */
268 static inline void
inline_mysql_end_socket_wait(struct PSI_socket_locker * locker,size_t byte_count)269 inline_mysql_end_socket_wait(struct PSI_socket_locker *locker, size_t byte_count)
270 {
271   if (psi_likely(locker != NULL))
272     PSI_SOCKET_CALL(end_socket_wait)(locker, byte_count);
273 }
274 
275 /**
276   Set the state (IDLE, ACTIVE) of an instrumented socket.
277   @param socket the instrumented socket
278   @param state the new state
279   @sa PSI_socket_state
280 */
281 static inline void
inline_mysql_socket_set_state(MYSQL_SOCKET socket,enum PSI_socket_state state)282 inline_mysql_socket_set_state(MYSQL_SOCKET socket, enum PSI_socket_state state)
283 {
284   if (socket.m_psi != NULL)
285     PSI_SOCKET_CALL(set_socket_state)(socket.m_psi, state);
286 }
287 #endif /* HAVE_PSI_SOCKET_INTERFACE */
288 
289 /**
290   @def mysql_socket_socket(K, D, T, P)
291   Create a socket.
292   @c mysql_socket_socket is a replacement for @c socket.
293   @param K PSI_socket_key for this instrumented socket
294   @param D Socket domain
295   @param T Protocol type
296   @param P Transport protocol
297 */
298 
299 #ifdef HAVE_PSI_SOCKET_INTERFACE
300   #define mysql_socket_socket(K, D, T, P) \
301     inline_mysql_socket_socket(K, D, T, P)
302 #else
303   #define mysql_socket_socket(K, D, T, P) \
304     inline_mysql_socket_socket(D, T, P)
305 #endif
306 
307 /**
308   @def mysql_socket_bind(FD, AP, L)
309   Bind a socket to a local port number and IP address
310   @c mysql_socket_bind is a replacement for @c bind.
311   @param FD Instrumented socket descriptor returned by socket()
312   @param AP Pointer to local port number and IP address in sockaddr structure
313   @param L  Length of sockaddr structure
314 */
315 #ifdef HAVE_PSI_SOCKET_INTERFACE
316   #define mysql_socket_bind(FD, AP, L) \
317     inline_mysql_socket_bind(__FILE__, __LINE__, FD, AP, L)
318 #else
319   #define mysql_socket_bind(FD, AP, L) \
320     inline_mysql_socket_bind(FD, AP, L)
321 #endif
322 
323 /**
324   @def mysql_socket_getsockname(FD, AP, LP)
325   Return port number and IP address of the local host
326   @c mysql_socket_getsockname is a replacement for @c getsockname.
327   @param FD Instrumented socket descriptor returned by socket()
328   @param A  Pointer to returned address of local host in sockaddr structure
329   @param L  Pointer to length of sockaddr structure
330 */
331 #ifdef HAVE_PSI_SOCKET_INTERFACE
332   #define mysql_socket_getsockname(FD, AP, LP) \
333     inline_mysql_socket_getsockname(__FILE__, __LINE__, FD, AP, LP)
334 #else
335   #define mysql_socket_getsockname(FD, AP, LP) \
336     inline_mysql_socket_getsockname(FD, AP, LP)
337 #endif
338 
339 /**
340   @def mysql_socket_connect(FD, AP, L)
341   Establish a connection to a remote host.
342   @c mysql_socket_connect is a replacement for @c connect.
343   @param FD Instrumented socket descriptor returned by socket()
344   @param AP Pointer to target address in sockaddr structure
345   @param L  Length of sockaddr structure
346 */
347 #ifdef HAVE_PSI_SOCKET_INTERFACE
348   #define mysql_socket_connect(FD, AP, L) \
349     inline_mysql_socket_connect(__FILE__, __LINE__, FD, AP, L)
350 #else
351   #define mysql_socket_connect(FD, AP, L) \
352     inline_mysql_socket_connect(FD, AP, L)
353 #endif
354 
355 /**
356   @def mysql_socket_getpeername(FD, AP, LP)
357   Get port number and IP address of remote host that a socket is connected to.
358   @c mysql_socket_getpeername is a replacement for @c getpeername.
359   @param FD Instrumented socket descriptor returned by socket() or accept()
360   @param AP Pointer to returned address of remote host in sockaddr structure
361   @param LP Pointer to length of sockaddr structure
362 */
363 #ifdef HAVE_PSI_SOCKET_INTERFACE
364   #define mysql_socket_getpeername(FD, AP, LP) \
365     inline_mysql_socket_getpeername(__FILE__, __LINE__, FD, AP, LP)
366 #else
367   #define mysql_socket_getpeername(FD, AP, LP) \
368     inline_mysql_socket_getpeername(FD, AP, LP)
369 #endif
370 
371 /**
372   @def mysql_socket_send(FD, B, N, FL)
373   Send data from the buffer, B, to a connected socket.
374   @c mysql_socket_send is a replacement for @c send.
375   @param FD Instrumented socket descriptor returned by socket() or accept()
376   @param B  Buffer to send
377   @param N  Number of bytes to send
378   @param FL Control flags
379 */
380 #ifdef HAVE_PSI_SOCKET_INTERFACE
381   #define mysql_socket_send(FD, B, N, FL) \
382     inline_mysql_socket_send(__FILE__, __LINE__, FD, B, N, FL)
383 #else
384   #define mysql_socket_send(FD, B, N, FL) \
385     inline_mysql_socket_send(FD, B, N, FL)
386 #endif
387 
388 /**
389   @def mysql_socket_recv(FD, B, N, FL)
390   Receive data from a connected socket.
391   @c mysql_socket_recv is a replacement for @c recv.
392   @param FD Instrumented socket descriptor returned by socket() or accept()
393   @param B  Buffer to receive to
394   @param N  Maximum bytes to receive
395   @param FL Control flags
396 */
397 #ifdef HAVE_PSI_SOCKET_INTERFACE
398   #define mysql_socket_recv(FD, B, N, FL) \
399     inline_mysql_socket_recv(__FILE__, __LINE__, FD, B, N, FL)
400 #else
401   #define mysql_socket_recv(FD, B, N, FL) \
402     inline_mysql_socket_recv(FD, B, N, FL)
403 #endif
404 
405 /**
406   @def mysql_socket_sendto(FD, B, N, FL, AP, L)
407   Send data to a socket at the specified address.
408   @c mysql_socket_sendto is a replacement for @c sendto.
409   @param FD Instrumented socket descriptor returned by socket()
410   @param B  Buffer to send
411   @param N  Number of bytes to send
412   @param FL Control flags
413   @param AP Pointer to destination sockaddr structure
414   @param L  Size of sockaddr structure
415 */
416 #ifdef HAVE_PSI_SOCKET_INTERFACE
417   #define mysql_socket_sendto(FD, B, N, FL, AP, L) \
418     inline_mysql_socket_sendto(__FILE__, __LINE__, FD, B, N, FL, AP, L)
419 #else
420   #define mysql_socket_sendto(FD, B, N, FL, AP, L) \
421     inline_mysql_socket_sendto(FD, B, N, FL, AP, L)
422 #endif
423 
424 /**
425   @def mysql_socket_recvfrom(FD, B, N, FL, AP, L)
426   Receive data from a socket and return source address information
427   @c mysql_socket_recvfrom is a replacement for @c recvfrom.
428   @param FD Instrumented socket descriptor returned by socket()
429   @param B  Buffer to receive to
430   @param N  Maximum bytes to receive
431   @param FL Control flags
432   @param AP Pointer to source address in sockaddr_storage structure
433   @param L  Size of sockaddr_storage structure
434 */
435 #ifdef HAVE_PSI_SOCKET_INTERFACE
436   #define mysql_socket_recvfrom(FD, B, N, FL, AP, LP) \
437     inline_mysql_socket_recvfrom(__FILE__, __LINE__, FD, B, N, FL, AP, LP)
438 #else
439   #define mysql_socket_recvfrom(FD, B, N, FL, AP, LP) \
440     inline_mysql_socket_recvfrom(FD, B, N, FL, AP, LP)
441 #endif
442 
443 /**
444   @def mysql_socket_getsockopt(FD, LV, ON, OP, OL)
445   Get a socket option for the specified socket.
446   @c mysql_socket_getsockopt is a replacement for @c getsockopt.
447   @param FD Instrumented socket descriptor returned by socket()
448   @param LV Protocol level
449   @param ON Option to query
450   @param OP Buffer which will contain the value for the requested option
451   @param OL Pointer to length of OP
452 */
453 #ifdef HAVE_PSI_SOCKET_INTERFACE
454   #define mysql_socket_getsockopt(FD, LV, ON, OP, OL) \
455     inline_mysql_socket_getsockopt(__FILE__, __LINE__, FD, LV, ON, OP, OL)
456 #else
457   #define mysql_socket_getsockopt(FD, LV, ON, OP, OL) \
458     inline_mysql_socket_getsockopt(FD, LV, ON, OP, OL)
459 #endif
460 
461 /**
462   @def mysql_socket_setsockopt(FD, LV, ON, OP, OL)
463   Set a socket option for the specified socket.
464   @c mysql_socket_setsockopt is a replacement for @c setsockopt.
465   @param FD Instrumented socket descriptor returned by socket()
466   @param LV Protocol level
467   @param ON Option to modify
468   @param OP Buffer containing the value for the specified option
469   @param OL Pointer to length of OP
470 */
471 #ifdef HAVE_PSI_SOCKET_INTERFACE
472   #define mysql_socket_setsockopt(FD, LV, ON, OP, OL) \
473     inline_mysql_socket_setsockopt(__FILE__, __LINE__, FD, LV, ON, OP, OL)
474 #else
475   #define mysql_socket_setsockopt(FD, LV, ON, OP, OL) \
476     inline_mysql_socket_setsockopt(FD, LV, ON, OP, OL)
477 #endif
478 
479 /**
480   @def mysql_socket_listen(FD, N)
481   Set socket state to listen for an incoming connection.
482   @c mysql_socket_listen is a replacement for @c listen.
483   @param FD Instrumented socket descriptor, bound and connected
484   @param N  Maximum number of pending connections allowed.
485 */
486 #ifdef HAVE_PSI_SOCKET_INTERFACE
487   #define mysql_socket_listen(FD, N) \
488     inline_mysql_socket_listen(__FILE__, __LINE__, FD, N)
489 #else
490   #define mysql_socket_listen(FD, N) \
491     inline_mysql_socket_listen(FD, N)
492 #endif
493 
494 /**
495   @def mysql_socket_accept(K, FD, AP, LP)
496   Accept a connection from any remote host; TCP only.
497   @c mysql_socket_accept is a replacement for @c accept.
498   @param K PSI_socket_key for this instrumented socket
499   @param FD Instrumented socket descriptor, bound and placed in a listen state
500   @param AP Pointer to sockaddr structure with returned IP address and port of connected host
501   @param LP Pointer to length of valid information in AP
502 */
503 #ifdef HAVE_PSI_SOCKET_INTERFACE
504   #define mysql_socket_accept(K, FD, AP, LP) \
505     inline_mysql_socket_accept(__FILE__, __LINE__, K, FD, AP, LP)
506 #else
507   #define mysql_socket_accept(K, FD, AP, LP) \
508     inline_mysql_socket_accept(FD, AP, LP)
509 #endif
510 
511 /**
512   @def mysql_socket_close(FD)
513   Close a socket and sever any connections.
514   @c mysql_socket_close is a replacement for @c close.
515   @param FD Instrumented socket descriptor returned by socket() or accept()
516 */
517 #ifdef HAVE_PSI_SOCKET_INTERFACE
518   #define mysql_socket_close(FD) \
519     inline_mysql_socket_close(__FILE__, __LINE__, FD)
520 #else
521   #define mysql_socket_close(FD) \
522     inline_mysql_socket_close(FD)
523 #endif
524 
525 /**
526   @def mysql_socket_shutdown(FD, H)
527   Disable receives and/or sends on a socket.
528   @c mysql_socket_shutdown is a replacement for @c shutdown.
529   @param FD Instrumented socket descriptor returned by socket() or accept()
530   @param H  Specifies which operations to shutdown
531 */
532 #ifdef HAVE_PSI_SOCKET_INTERFACE
533   #define mysql_socket_shutdown(FD, H) \
534     inline_mysql_socket_shutdown(__FILE__, __LINE__, FD, H)
535 #else
536   #define mysql_socket_shutdown(FD, H) \
537     inline_mysql_socket_shutdown(FD, H)
538 #endif
539 
540 #ifdef HAVE_PSI_SOCKET_INTERFACE
inline_mysql_socket_register(const char * category,PSI_socket_info * info,int count)541 static inline void inline_mysql_socket_register(
542   const char *category,
543   PSI_socket_info *info,
544   int count)
545 {
546   PSI_SOCKET_CALL(register_socket)(category, info, count);
547 }
548 #endif
549 
550 /** mysql_socket_socket */
551 
552 static inline MYSQL_SOCKET
inline_mysql_socket_socket(PSI_socket_key key,int domain,int type,int protocol)553 inline_mysql_socket_socket
554 (
555 #ifdef HAVE_PSI_SOCKET_INTERFACE
556   PSI_socket_key key,
557 #endif
558   int domain, int type, int protocol)
559 {
560   MYSQL_SOCKET mysql_socket= MYSQL_INVALID_SOCKET;
561   mysql_socket.fd= socket(domain, type | SOCK_CLOEXEC, protocol);
562 
563 #ifdef HAVE_PSI_SOCKET_INTERFACE
564   if (likely(mysql_socket.fd != INVALID_SOCKET))
565   {
566     mysql_socket.m_psi= PSI_SOCKET_CALL(init_socket)
567       (key, (const my_socket*)&mysql_socket.fd, NULL, 0);
568   }
569 #endif
570 
571   /* SOCK_CLOEXEC isn't always a number - can't preprocessor compare */
572 #if defined(HAVE_FCNTL) && defined(FD_CLOEXEC) && !defined(HAVE_SOCK_CLOEXEC)
573   (void) fcntl(mysql_socket.fd, F_SETFD, FD_CLOEXEC);
574 #endif
575 
576   return mysql_socket;
577 }
578 
579 /** mysql_socket_bind */
580 
581 static inline int
inline_mysql_socket_bind(const char * src_file,uint src_line,MYSQL_SOCKET mysql_socket,const struct sockaddr * addr,size_t len)582 inline_mysql_socket_bind
583 (
584 #ifdef HAVE_PSI_SOCKET_INTERFACE
585   const char *src_file, uint src_line,
586 #endif
587   MYSQL_SOCKET mysql_socket, const struct sockaddr *addr, size_t len)
588 {
589   int result;
590 
591 #ifdef HAVE_PSI_SOCKET_INTERFACE
592   if (psi_likely(mysql_socket.m_psi != NULL))
593   {
594     /* Instrumentation start */
595     PSI_socket_locker_state state;
596     PSI_socket_locker *locker;
597     locker= PSI_SOCKET_CALL(start_socket_wait)
598       (&state, mysql_socket.m_psi, PSI_SOCKET_BIND, (size_t)0, src_file, src_line);
599 
600     /* Instrumented code */
601     result= bind(mysql_socket.fd, addr, (int)len);
602 
603     /* Instrumentation end */
604     if (result == 0)
605       PSI_SOCKET_CALL(set_socket_info)(mysql_socket.m_psi, NULL, addr, (socklen_t)len);
606 
607     if (locker != NULL)
608       PSI_SOCKET_CALL(end_socket_wait)(locker, (size_t)0);
609 
610     return result;
611   }
612 #endif
613 
614   /* Non instrumented code */
615   result= bind(mysql_socket.fd, addr, (int)len);
616   return result;
617 }
618 
619 /** mysql_socket_getsockname */
620 
621 static inline int
inline_mysql_socket_getsockname(const char * src_file,uint src_line,MYSQL_SOCKET mysql_socket,struct sockaddr * addr,socklen_t * len)622 inline_mysql_socket_getsockname
623 (
624 #ifdef HAVE_PSI_SOCKET_INTERFACE
625   const char *src_file, uint src_line,
626 #endif
627  MYSQL_SOCKET mysql_socket, struct sockaddr *addr, socklen_t *len)
628 {
629   int result;
630 
631 #ifdef HAVE_PSI_SOCKET_INTERFACE
632   if (psi_likely(mysql_socket.m_psi != NULL))
633   {
634     /* Instrumentation start */
635     PSI_socket_locker *locker;
636     PSI_socket_locker_state state;
637     locker= PSI_SOCKET_CALL(start_socket_wait)
638       (&state, mysql_socket.m_psi, PSI_SOCKET_BIND, (size_t)0, src_file, src_line);
639 
640     /* Instrumented code */
641     result= getsockname(mysql_socket.fd, addr, len);
642 
643     /* Instrumentation end */
644     if (locker != NULL)
645       PSI_SOCKET_CALL(end_socket_wait)(locker, (size_t)0);
646 
647     return result;
648   }
649 #endif
650 
651   /* Non instrumented code */
652   result= getsockname(mysql_socket.fd, addr, len);
653 
654   return result;
655 }
656 
657 /** mysql_socket_connect */
658 
659 static inline int
inline_mysql_socket_connect(const char * src_file,uint src_line,MYSQL_SOCKET mysql_socket,const struct sockaddr * addr,socklen_t len)660 inline_mysql_socket_connect
661 (
662 #ifdef HAVE_PSI_SOCKET_INTERFACE
663   const char *src_file, uint src_line,
664 #endif
665  MYSQL_SOCKET mysql_socket, const struct sockaddr *addr, socklen_t len)
666 {
667   int result;
668 
669 #ifdef HAVE_PSI_SOCKET_INTERFACE
670   if (psi_likely(mysql_socket.m_psi != NULL))
671   {
672     /* Instrumentation start */
673     PSI_socket_locker *locker;
674     PSI_socket_locker_state state;
675     locker= PSI_SOCKET_CALL(start_socket_wait)
676       (&state, mysql_socket.m_psi, PSI_SOCKET_CONNECT, (size_t)0, src_file, src_line);
677 
678     /* Instrumented code */
679     result= connect(mysql_socket.fd, addr, len);
680 
681     /* Instrumentation end */
682     if (locker != NULL)
683       PSI_SOCKET_CALL(end_socket_wait)(locker, (size_t)0);
684 
685     return result;
686   }
687 #endif
688 
689   /* Non instrumented code */
690   result= connect(mysql_socket.fd, addr, len);
691 
692   return result;
693 }
694 
695 /** mysql_socket_getpeername */
696 
697 static inline int
inline_mysql_socket_getpeername(const char * src_file,uint src_line,MYSQL_SOCKET mysql_socket,struct sockaddr * addr,socklen_t * len)698 inline_mysql_socket_getpeername
699 (
700 #ifdef HAVE_PSI_SOCKET_INTERFACE
701   const char *src_file, uint src_line,
702 #endif
703  MYSQL_SOCKET mysql_socket, struct sockaddr *addr, socklen_t *len)
704 {
705   int result;
706 
707 #ifdef HAVE_PSI_SOCKET_INTERFACE
708   if (psi_likely(mysql_socket.m_psi != NULL))
709   {
710     /* Instrumentation start */
711     PSI_socket_locker *locker;
712     PSI_socket_locker_state state;
713     locker= PSI_SOCKET_CALL(start_socket_wait)
714       (&state, mysql_socket.m_psi, PSI_SOCKET_BIND, (size_t)0, src_file, src_line);
715 
716     /* Instrumented code */
717     result= getpeername(mysql_socket.fd, addr, len);
718 
719     /* Instrumentation end */
720     if (locker != NULL)
721       PSI_SOCKET_CALL(end_socket_wait)(locker, (size_t)0);
722 
723     return result;
724   }
725 #endif
726 
727   /* Non instrumented code */
728   result= getpeername(mysql_socket.fd, addr, len);
729 
730   return result;
731 }
732 
733 /** mysql_socket_send */
734 
735 static inline ssize_t
inline_mysql_socket_send(const char * src_file,uint src_line,MYSQL_SOCKET mysql_socket,const SOCKBUF_T * buf,size_t n,int flags)736 inline_mysql_socket_send
737 (
738 #ifdef HAVE_PSI_SOCKET_INTERFACE
739   const char *src_file, uint src_line,
740 #endif
741  MYSQL_SOCKET mysql_socket, const SOCKBUF_T *buf, size_t n, int flags)
742 {
743   ssize_t result;
744   DBUG_ASSERT(mysql_socket.fd != INVALID_SOCKET);
745 #ifdef HAVE_PSI_SOCKET_INTERFACE
746   if (psi_likely(mysql_socket.m_psi != NULL))
747   {
748     /* Instrumentation start */
749     PSI_socket_locker *locker;
750     PSI_socket_locker_state state;
751     locker= PSI_SOCKET_CALL(start_socket_wait)
752       (&state, mysql_socket.m_psi, PSI_SOCKET_SEND, n, src_file, src_line);
753 
754     /* Instrumented code */
755     result= send(mysql_socket.fd, buf, IF_WIN((int),) n, flags);
756 
757     /* Instrumentation end */
758     if (locker != NULL)
759     {
760       size_t bytes_written= (result > 0) ? (size_t) result : 0;
761       PSI_SOCKET_CALL(end_socket_wait)(locker, bytes_written);
762     }
763 
764     return result;
765   }
766 #endif
767 
768   /* Non instrumented code */
769   result= send(mysql_socket.fd, buf, IF_WIN((int),) n, flags);
770 
771   return result;
772 }
773 
774 /** mysql_socket_recv */
775 
776 static inline ssize_t
inline_mysql_socket_recv(const char * src_file,uint src_line,MYSQL_SOCKET mysql_socket,SOCKBUF_T * buf,size_t n,int flags)777 inline_mysql_socket_recv
778 (
779 #ifdef HAVE_PSI_SOCKET_INTERFACE
780   const char *src_file, uint src_line,
781 #endif
782  MYSQL_SOCKET mysql_socket,  SOCKBUF_T *buf, size_t n, int flags)
783 {
784   ssize_t result;
785   DBUG_ASSERT(mysql_socket.fd != INVALID_SOCKET);
786 #ifdef HAVE_PSI_SOCKET_INTERFACE
787   if (psi_likely(mysql_socket.m_psi != NULL))
788   {
789     /* Instrumentation start */
790     PSI_socket_locker *locker;
791     PSI_socket_locker_state state;
792     locker= PSI_SOCKET_CALL(start_socket_wait)
793       (&state, mysql_socket.m_psi, PSI_SOCKET_RECV, (size_t)0, src_file, src_line);
794 
795     /* Instrumented code */
796     result= recv(mysql_socket.fd, buf, IF_WIN((int),) n, flags);
797 
798     /* Instrumentation end */
799     if (locker != NULL)
800     {
801       size_t bytes_read= (result > 0) ? (size_t) result : 0;
802       PSI_SOCKET_CALL(end_socket_wait)(locker, bytes_read);
803     }
804 
805     return result;
806   }
807 #endif
808 
809   /* Non instrumented code */
810   result= recv(mysql_socket.fd, buf, IF_WIN((int),) n, flags);
811 
812   return result;
813 }
814 
815 /** mysql_socket_sendto */
816 
817 static inline ssize_t
inline_mysql_socket_sendto(const char * src_file,uint src_line,MYSQL_SOCKET mysql_socket,const SOCKBUF_T * buf,size_t n,int flags,const struct sockaddr * addr,socklen_t addr_len)818 inline_mysql_socket_sendto
819 (
820 #ifdef HAVE_PSI_SOCKET_INTERFACE
821   const char *src_file, uint src_line,
822 #endif
823  MYSQL_SOCKET mysql_socket, const SOCKBUF_T *buf, size_t n, int flags, const struct sockaddr *addr, socklen_t addr_len)
824 {
825   ssize_t result;
826 
827 #ifdef HAVE_PSI_SOCKET_INTERFACE
828   if (psi_likely(mysql_socket.m_psi != NULL))
829   {
830     /* Instrumentation start */
831     PSI_socket_locker *locker;
832     PSI_socket_locker_state state;
833     locker= PSI_SOCKET_CALL(start_socket_wait)
834       (&state, mysql_socket.m_psi, PSI_SOCKET_SEND, n, src_file, src_line);
835 
836     /* Instrumented code */
837     result= sendto(mysql_socket.fd, buf, IF_WIN((int),) n, flags, addr, addr_len);
838 
839     /* Instrumentation end */
840     if (locker != NULL)
841     {
842       size_t bytes_written = (result > 0) ? (size_t) result : 0;
843       PSI_SOCKET_CALL(end_socket_wait)(locker, bytes_written);
844     }
845 
846     return result;
847   }
848 #endif
849 
850   /* Non instrumented code */
851   result= sendto(mysql_socket.fd, buf, IF_WIN((int),) n, flags, addr, addr_len);
852 
853   return result;
854 }
855 
856 /** mysql_socket_recvfrom */
857 
858 static inline ssize_t
inline_mysql_socket_recvfrom(const char * src_file,uint src_line,MYSQL_SOCKET mysql_socket,SOCKBUF_T * buf,size_t n,int flags,struct sockaddr * addr,socklen_t * addr_len)859 inline_mysql_socket_recvfrom
860 (
861 #ifdef HAVE_PSI_SOCKET_INTERFACE
862   const char *src_file, uint src_line,
863 #endif
864  MYSQL_SOCKET mysql_socket, SOCKBUF_T *buf, size_t n, int flags,
865  struct sockaddr *addr, socklen_t *addr_len)
866 {
867   ssize_t result;
868 
869 #ifdef HAVE_PSI_SOCKET_INTERFACE
870   if (psi_likely(mysql_socket.m_psi != NULL))
871   {
872     /* Instrumentation start */
873     PSI_socket_locker *locker;
874     PSI_socket_locker_state state;
875     locker= PSI_SOCKET_CALL(start_socket_wait)
876       (&state, mysql_socket.m_psi, PSI_SOCKET_RECV, (size_t)0, src_file, src_line);
877 
878     /* Instrumented code */
879     result= recvfrom(mysql_socket.fd, buf, IF_WIN((int),) n, flags, addr, addr_len);
880 
881     /* Instrumentation end */
882     if (locker != NULL)
883     {
884       size_t bytes_read= (result > 0) ? (size_t) result : 0;
885       PSI_SOCKET_CALL(end_socket_wait)(locker, bytes_read);
886     }
887 
888     return result;
889   }
890 #endif
891 
892   /* Non instrumented code */
893   result= recvfrom(mysql_socket.fd, buf, IF_WIN((int),) n, flags, addr, addr_len);
894 
895   return result;
896 }
897 
898 /** mysql_socket_getsockopt */
899 
900 static inline int
inline_mysql_socket_getsockopt(const char * src_file,uint src_line,MYSQL_SOCKET mysql_socket,int level,int optname,SOCKBUF_T * optval,socklen_t * optlen)901 inline_mysql_socket_getsockopt
902 (
903 #ifdef HAVE_PSI_SOCKET_INTERFACE
904   const char *src_file, uint src_line,
905 #endif
906  MYSQL_SOCKET mysql_socket, int level, int optname, SOCKBUF_T *optval, socklen_t *optlen)
907 {
908   int result;
909 
910 #ifdef HAVE_PSI_SOCKET_INTERFACE
911   if (psi_likely(mysql_socket.m_psi != NULL))
912   {
913     /* Instrumentation start */
914     PSI_socket_locker *locker;
915     PSI_socket_locker_state state;
916     locker= PSI_SOCKET_CALL(start_socket_wait)
917       (&state, mysql_socket.m_psi, PSI_SOCKET_OPT, (size_t)0, src_file, src_line);
918 
919     /* Instrumented code */
920     result= getsockopt(mysql_socket.fd, level, optname, optval, optlen);
921 
922     /* Instrumentation end */
923     if (locker != NULL)
924       PSI_SOCKET_CALL(end_socket_wait)(locker, (size_t)0);
925 
926     return result;
927   }
928 #endif
929 
930   /* Non instrumented code */
931   result= getsockopt(mysql_socket.fd, level, optname, optval, optlen);
932 
933   return result;
934 }
935 
936 /** mysql_socket_setsockopt */
937 
938 static inline int
inline_mysql_socket_setsockopt(const char * src_file,uint src_line,MYSQL_SOCKET mysql_socket,int level,int optname,const SOCKBUF_T * optval,socklen_t optlen)939 inline_mysql_socket_setsockopt
940 (
941 #ifdef HAVE_PSI_SOCKET_INTERFACE
942   const char *src_file, uint src_line,
943 #endif
944  MYSQL_SOCKET mysql_socket, int level, int optname, const SOCKBUF_T *optval,
945  socklen_t optlen)
946 {
947   int result;
948 
949 #ifdef HAVE_PSI_SOCKET_INTERFACE
950   if (psi_likely(mysql_socket.m_psi))
951   {
952     /* Instrumentation start */
953     PSI_socket_locker *locker;
954     PSI_socket_locker_state state;
955     locker= PSI_SOCKET_CALL(start_socket_wait)
956       (&state, mysql_socket.m_psi, PSI_SOCKET_OPT, (size_t)0, src_file, src_line);
957 
958     /* Instrumented code */
959     result= setsockopt(mysql_socket.fd, level, optname, optval, optlen);
960 
961     /* Instrumentation end */
962     if (locker != NULL)
963       PSI_SOCKET_CALL(end_socket_wait)(locker, (size_t)0);
964 
965     return result;
966   }
967 #endif
968 
969   /* Non instrumented code */
970   result= setsockopt(mysql_socket.fd, level, optname, optval, optlen);
971 
972   return result;
973 }
974 
975 /** mysql_socket_listen */
976 
977 static inline int
inline_mysql_socket_listen(const char * src_file,uint src_line,MYSQL_SOCKET mysql_socket,int backlog)978 inline_mysql_socket_listen
979 (
980 #ifdef HAVE_PSI_SOCKET_INTERFACE
981   const char *src_file, uint src_line,
982 #endif
983  MYSQL_SOCKET mysql_socket, int backlog)
984 {
985   int result;
986 
987 #ifdef HAVE_PSI_SOCKET_INTERFACE
988   if (psi_likely(mysql_socket.m_psi != NULL))
989   {
990     /* Instrumentation start */
991     PSI_socket_locker *locker;
992     PSI_socket_locker_state state;
993     locker= PSI_SOCKET_CALL(start_socket_wait)
994       (&state, mysql_socket.m_psi, PSI_SOCKET_CONNECT, (size_t)0, src_file, src_line);
995 
996     /* Instrumented code */
997     result= listen(mysql_socket.fd, backlog);
998 
999     /* Instrumentation end */
1000     if (locker != NULL)
1001       PSI_SOCKET_CALL(end_socket_wait)(locker, (size_t)0);
1002 
1003     return result;
1004   }
1005 #endif
1006 
1007   /* Non instrumented code */
1008   result= listen(mysql_socket.fd, backlog);
1009 
1010   return result;
1011 }
1012 
1013 /** mysql_socket_accept */
1014 
1015 static inline MYSQL_SOCKET
inline_mysql_socket_accept(const char * src_file,uint src_line,PSI_socket_key key,MYSQL_SOCKET socket_listen,struct sockaddr * addr,socklen_t * addr_len)1016 inline_mysql_socket_accept
1017 (
1018 #ifdef HAVE_PSI_SOCKET_INTERFACE
1019   const char *src_file, uint src_line, PSI_socket_key key,
1020 #endif
1021   MYSQL_SOCKET socket_listen, struct sockaddr *addr, socklen_t *addr_len)
1022 {
1023 #ifdef FD_CLOEXEC
1024   int flags __attribute__ ((unused));
1025 #endif
1026 
1027   MYSQL_SOCKET socket_accept= MYSQL_INVALID_SOCKET;
1028   socklen_t addr_length= (addr_len != NULL) ? *addr_len : 0;
1029 
1030 #ifdef HAVE_PSI_SOCKET_INTERFACE
1031   if (socket_listen.m_psi != NULL)
1032   {
1033     /* Instrumentation start */
1034     PSI_socket_locker *locker;
1035     PSI_socket_locker_state state;
1036     locker= PSI_SOCKET_CALL(start_socket_wait)
1037       (&state, socket_listen.m_psi, PSI_SOCKET_CONNECT, (size_t)0, src_file, src_line);
1038 
1039     /* Instrumented code */
1040 #ifdef HAVE_ACCEPT4
1041     socket_accept.fd= accept4(socket_listen.fd, addr, &addr_length,
1042                               SOCK_CLOEXEC);
1043 #else
1044     socket_accept.fd= accept(socket_listen.fd, addr, &addr_length);
1045 #ifdef FD_CLOEXEC
1046     if (socket_accept.fd != INVALID_SOCKET)
1047     {
1048       flags= fcntl(socket_accept.fd, F_GETFD);
1049       if (flags != -1)
1050       {
1051         flags |= FD_CLOEXEC;
1052         fcntl(socket_accept.fd, F_SETFD, flags);
1053       }
1054     }
1055 #endif
1056 #endif
1057 
1058     /* Instrumentation end */
1059     if (locker != NULL)
1060       PSI_SOCKET_CALL(end_socket_wait)(locker, (size_t)0);
1061   }
1062   else
1063 #endif
1064   {
1065     /* Non instrumented code */
1066 #ifdef HAVE_ACCEPT4
1067     socket_accept.fd= accept4(socket_listen.fd, addr, &addr_length,
1068                               SOCK_CLOEXEC);
1069 #else
1070     socket_accept.fd= accept(socket_listen.fd, addr, &addr_length);
1071 #ifdef FD_CLOEXEC
1072     if (socket_accept.fd != INVALID_SOCKET)
1073     {
1074       flags= fcntl(socket_accept.fd, F_GETFD);
1075       if (flags != -1)
1076       {
1077         flags |= FD_CLOEXEC;
1078         fcntl(socket_accept.fd, F_SETFD, flags);
1079       }
1080     }
1081 #endif
1082 #endif
1083   }
1084 
1085 #ifdef HAVE_PSI_SOCKET_INTERFACE
1086   if (likely(socket_accept.fd != INVALID_SOCKET))
1087   {
1088     /* Initialize the instrument with the new socket descriptor and address */
1089     socket_accept.m_psi= PSI_SOCKET_CALL(init_socket)
1090       (key, (const my_socket*)&socket_accept.fd, addr, addr_length);
1091   }
1092 #endif
1093 
1094   return socket_accept;
1095 }
1096 
1097 /** mysql_socket_close */
1098 
1099 static inline int
inline_mysql_socket_close(const char * src_file,uint src_line,MYSQL_SOCKET mysql_socket)1100 inline_mysql_socket_close
1101 (
1102 #ifdef HAVE_PSI_SOCKET_INTERFACE
1103   const char *src_file, uint src_line,
1104 #endif
1105   MYSQL_SOCKET mysql_socket)
1106 {
1107   int result;
1108 
1109 #ifdef HAVE_PSI_SOCKET_INTERFACE
1110   if (psi_likely(mysql_socket.m_psi != NULL))
1111   {
1112     /* Instrumentation start */
1113     PSI_socket_locker *locker;
1114     PSI_socket_locker_state state;
1115     locker= PSI_SOCKET_CALL(start_socket_wait)
1116       (&state, mysql_socket.m_psi, PSI_SOCKET_CLOSE, (size_t)0, src_file, src_line);
1117 
1118     /* Instrumented code */
1119     result= closesocket(mysql_socket.fd);
1120 
1121     /* Instrumentation end */
1122     if (locker != NULL)
1123       PSI_SOCKET_CALL(end_socket_wait)(locker, (size_t)0);
1124     /* Remove the instrumentation for this socket. */
1125     if (mysql_socket.m_psi != NULL)
1126       PSI_SOCKET_CALL(destroy_socket)(mysql_socket.m_psi);
1127 
1128     return result;
1129   }
1130 #endif
1131 
1132   /* Non instrumented code */
1133   result= closesocket(mysql_socket.fd);
1134 
1135   return result;
1136 }
1137 
1138 /** mysql_socket_shutdown */
1139 
1140 static inline int
inline_mysql_socket_shutdown(const char * src_file,uint src_line,MYSQL_SOCKET mysql_socket,int how)1141 inline_mysql_socket_shutdown
1142 (
1143 #ifdef HAVE_PSI_SOCKET_INTERFACE
1144   const char *src_file, uint src_line,
1145 #endif
1146   MYSQL_SOCKET mysql_socket, int how)
1147 {
1148   int result;
1149 
1150 #ifdef __WIN__
1151   static LPFN_DISCONNECTEX DisconnectEx = NULL;
1152   if (DisconnectEx == NULL)
1153   {
1154     DWORD dwBytesReturned;
1155     GUID guidDisconnectEx = WSAID_DISCONNECTEX;
1156     WSAIoctl(mysql_socket.fd, SIO_GET_EXTENSION_FUNCTION_POINTER,
1157              &guidDisconnectEx, sizeof(GUID),
1158              &DisconnectEx, sizeof(DisconnectEx),
1159              &dwBytesReturned, NULL, NULL);
1160   }
1161 #endif
1162 
1163 /* Instrumentation start */
1164 #ifdef HAVE_PSI_SOCKET_INTERFACE
1165   if (psi_likely(mysql_socket.m_psi != NULL))
1166   {
1167     PSI_socket_locker *locker;
1168     PSI_socket_locker_state state;
1169     locker= PSI_SOCKET_CALL(start_socket_wait)
1170       (&state, mysql_socket.m_psi, PSI_SOCKET_SHUTDOWN, (size_t)0, src_file, src_line);
1171 
1172     /* Instrumented code */
1173 #ifdef __WIN__
1174     if (DisconnectEx)
1175       result= (DisconnectEx(mysql_socket.fd, (LPOVERLAPPED) NULL,
1176                             (DWORD) 0, (DWORD) 0) == TRUE) ? 0 : -1;
1177     else
1178 #endif
1179       result= shutdown(mysql_socket.fd, how);
1180 
1181     /* Instrumentation end */
1182     if (locker != NULL)
1183       PSI_SOCKET_CALL(end_socket_wait)(locker, (size_t)0);
1184 
1185     return result;
1186   }
1187 #endif
1188 
1189   /* Non instrumented code */
1190 #ifdef __WIN__
1191   if (DisconnectEx)
1192     result= (DisconnectEx(mysql_socket.fd, (LPOVERLAPPED) NULL,
1193                           (DWORD) 0, (DWORD) 0) == TRUE) ? 0 : -1;
1194   else
1195 #endif
1196     result= shutdown(mysql_socket.fd, how);
1197 
1198   return result;
1199 }
1200 
1201 /** @} (end of group Socket_instrumentation) */
1202 
1203 #endif
1204 
1205