In the following code, some struct types are unclear, such as THD, st_vio, and pollfd. However, we can see that MySQL uses the Select model to receive client connections. It is also found on the internet that unix_sock refers to the communication between different processes on the same machine, such as named pipes. Ip_sock refers to the communication between different hosts.
Void handle_connections_sockets ()
{
My_socket UNINIT_VAR (sock), UNINIT_VAR (new_sock );
Uint error_count = 0;
THD * thd;
Struct sockaddr_storage cAddr;
Int ip_flags = 0, socket_flags = 0, flags = 0, retval;
St_vio * vi_tmp;
# Ifdef HAVE_POLL
Int socket_count = 0;
Struct pollfd fds [2]; // for ip_sock and unix_sock
# Else
Fd_set readFDs, clientFDs;
Uint max_used_connection = (uint) (max (ip_sock, unix_sock) + 1 );
# Endif
DBUG_ENTER ("handle_connections_sockets ");
# Ifndef HAVE_POLL
FD_ZERO (& clientFDs );
# Endif
If (ip_sock! = INVALID_SOCKET)
{
# Ifdef HAVE_POLL
Fds [socket_count]. fd = ip_sock;
Fds [socket_count]. events = POLLIN;
Socket_count ++;
# Else
FD_SET (ip_sock, & clientFDs );
# Endif
# Ifdef HAVE_FCNTL
Ip_flags = fcntl (ip_sock, F_GETFL, 0 );
# Endif
}
# Ifdef HAVE_SYS_UN_H
# Ifdef HAVE_POLL
Fds [socket_count]. fd = unix_sock;
Fds [socket_count]. events = POLLIN;
Socket_count ++;
# Else
FD_SET (unix_sock, & clientFDs );
# Endif
# Ifdef HAVE_FCNTL
Socket_flags = fcntl (unix_sock, F_GETFL, 0 );
# Endif
# Endif
DBUG_PRINT ("general", ("Waiting for connections ."));
MAYBE_BROKEN_SYSCALL;
While (! Abort_loop)
{
# Ifdef HAVE_POLL
Retval = poll (fds, socket_count,-1 );
# Else
ReadFDs = clientFDs;
Retval = select (int) max_used_connection, & readFDs, 0); // wait for the client to connect, return an error or connection
# Endif
If (retval <0)
{
If (socket_errno! = SOCKET_EINTR)
{
If (! Select_errors ++ &&! Abort_loop)/* purecov: inspected */
SQL _print_error ("mysqld: Got error % d from select", socket_errno);/* purecov: inspected */
}
MAYBE_BROKEN_SYSCALL
Continue;
}
If (abort_loop)
{
MAYBE_BROKEN_SYSCALL;
Break;
}
/* Is this a new connection request? */
# Ifdef HAVE_POLL
For (int I = 0; I <socket_count; ++ I)
{
If (fds [I]. revents & POLLIN) // read the Event Type
{
Sock = fds [I]. fd;
# Ifdef HAVE_FCNTL
Flags = fcntl (sock, F_GETFL, 0 );
# Else
Flags = 0;
# Endif // HAVE_FCNTL
Break;
}
}
# Else // HAVE_POLL
# Ifdef HAVE_SYS_UN_H
If (FD_ISSET (unix_sock, & readFDs ))
{
Sock = unix_sock;
Flags = socket_flags;
}
Else
# Endif // HAVE_SYS_UN_H
{
Sock = ip_sock;
Flags = ip_flags;
}
# Endif // HAVE_POLL
# If! Defined (NO_FCNTL_NONBLOCK)
If (! (Test_flags & TEST_BLOCKING ))
{
# If defined (O_NONBLOCK)
Fcntl (sock, F_SETFL, flags | O_NONBLOCK); // sets the non-blocking mode.
# Elif defined (O_NDELAY)
Fcntl (sock, F_SETFL, flags | O_NDELAY );
# Endif
}
# Endif/* NO_FCNTL_NONBLOCK */
For (uint retry = 0; retry <MAX_ACCEPT_RETRY; retry ++)
{
Size_socket length = sizeof (struct sockaddr_storage );
New_sock = accept (sock, (struct sockaddr *) (& cAddr), // accept the connection, and use the blocking method for the connection
& Length );
If (new_sock! = INVALID_SOCKET |
(Socket_errno! = SOCKET_EINTR & socket_errno! = SOCKET_EAGAIN ))
Break;
MAYBE_BROKEN_SYSCALL;
# If! Defined (NO_FCNTL_NONBLOCK)
If (! (Test_flags & TEST_BLOCKING ))
{
If (retry = MAX_ACCEPT_RETRY-1)
Fcntl (sock, F_SETFL, flags); // Try without O_NONBLOCK
}
# Endif
}
# If! Defined (NO_FCNTL_NONBLOCK)
If (! (Test_flags & TEST_BLOCKING ))
Fcntl (sock, F_SETFL, flags );
# Endif
If (new_sock = INVALID_SOCKET)
{
If (error_count ++ & 255) = 0) // This can happen often
SQL _perror ("Error in accept ");
MAYBE_BROKEN_SYSCALL;
If (socket_errno = SOCKET_ENFILE | socket_errno = SOCKET_EMFILE)
Sleep (1); // Give other threads some time
Continue;
}
# Ifdef HAVE_LIBWRAP
{
If (sock = ip_sock)
{
Struct request_info req;
Signal (SIGCHLD, SIG_DFL );
Request_init (& req, RQ_DAEMON, libwrapName, RQ_FILE, new_sock, NULL );
My_fromhost (& req );
If (! My_hosts_access (& req) // checks whether the host has access permissions.
{// Connection denied if the host is not granted the permission
/*
This may be stupid but refuse () already des an exit (0)
Which we surely don't want...
Clean_exit ()-same stupid thing...
*/
Syslog (deny_severity, "refused connect from % s ",
My_eval_client (& req ));
/*
C ++ sucks (the gibberish in front just translates the supplied
Sink function pointer in the req structure from a void (* sink )();
To a void (* sink) (int) if you omit the cast, the C ++ compiler
Will cry...
*/
If (req. sink)
(Void (*) (int) req. sink) (req. fd );
(Void) shutdown (new_sock, SHUT_RDWR); // close the connection
(Void) closesocket (new_sock );
Continue;
}
}
}
# Endif/* HAVE_LIBWRAP */
{
Size_socket dummyLen;
Struct sockaddr_storage dummy;
DummyLen = sizeof (dummy );
If (getsockname (new_sock, (struct sockaddr *) & dummy,
(SOCKET_SIZE_TYPE *) & dummyLen) <0)
{
SQL _perror ("Error on new connection socket ");
(Void) shutdown (new_sock, SHUT_RDWR );
(Void) closesocket (new_sock );
Continue;
}
}
/*
** Don't allow too restart connections
*/
If (! (Thd = new THD) // allocate a processing structure for the connection, which will be used for the thread later
{
(Void) shutdown (new_sock, SHUT_RDWR );
(Void) closesocket (new_sock );
Continue;
}
If (! (Viow_tmp = viow_new (new_sock,
Sock = unix_sock? Via_type_socket:
Via_type_tcpip,
Sock = unix_sock? VIO_LOCALHOST: 0) |
My_net_init (& thd-> net, vio_tmp) // initialize the network
{
/*
Only delete the temporary vio if we didn't already attach it to
NET object. The destructor in THD will delete any initialized net
Structure.
*/
If (vi_tmp & thd-> net. vio! = Vio_tmp)
Viow_delete (viow_tmp );
Else
{
(Void) shutdown (new_sock, SHUT_RDWR );
(Void) closesocket (new_sock );
}
Delete thd;
Continue;
}
If (sock = unix_sock)
Thd-> security_ctx-> host = (char *) my_localhost;
Create_new_thread (thd); // prepare to allocate a thread for the connection
}
DBUG_VOID_RETURN;
}