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