📄 network-mysqld.c
字号:
network_queue_append_chunk(send_sock->send_queue, packet); recv_sock->packet_len = PACKET_LEN_UNSET; g_queue_delete_link(recv_sock->recv_queue->chunks, chunk); /** * send it out to the client */ con->state = CON_STATE_SEND_AUTH_OLD_PASSWORD; break; } case CON_STATE_SEND_AUTH_OLD_PASSWORD: /** * data is at the server, read the response next */ con->state = CON_STATE_READ_AUTH_RESULT; break; case CON_STATE_READ_QUERY: func = con->plugins.con_read_query; break; case CON_STATE_READ_QUERY_RESULT: func = con->plugins.con_read_query_result; break; case CON_STATE_SEND_QUERY_RESULT: func = con->plugins.con_send_query_result; if (!func) { /* default implementation */ con->state = CON_STATE_READ_QUERY; } break; default: g_error("%s.%d: unhandled state: %d", __FILE__, __LINE__, state); } if (!func) return RET_SUCCESS; return (*func)(srv, con);}/** * handle the different states of the MySQL protocol * * @param event_fd fd on which the event was fired * @param events the event that was fired * @param user_data the connection handle */void network_mysqld_con_handle(int event_fd, short events, void *user_data) { guint ostate; network_mysqld_con *con = user_data; network_mysqld *srv = con->srv; g_assert(srv); g_assert(con); if (events == EV_READ) { int b = -1; if (ioctl(event_fd, FIONREAD, &b)) { g_critical("ioctl(%d, FIONREAD, ...) failed: %s", event_fd, strerror(errno)); con->state = CON_STATE_ERROR; } else if (b != 0) { if (con->client && event_fd == con->client->fd) { con->client->to_read = b; } else if (con->server && event_fd == con->server->fd) { con->server->to_read = b; } else { g_error("%s.%d: neither nor", __FILE__, __LINE__); } } else { if (con->client && event_fd == con->client->fd) { /* the client closed the connection, let's keep the server side open */ con->state = CON_STATE_CLOSE_CLIENT; } else { /* server side closed on use, oops, close both sides */ con->state = CON_STATE_ERROR; } } }#define WAIT_FOR_EVENT(ev_struct, ev_type, timeout) \ event_set(&(ev_struct->event), ev_struct->fd, ev_type, network_mysqld_con_handle, user_data); \ event_base_set(srv->event_base, &(ev_struct->event));\ event_add(&(ev_struct->event), timeout); /** * loop on the same connection as long as we don't end up in a stable state */ do { ostate = con->state; switch (con->state) { case CON_STATE_ERROR: /* we can't go on, close the connection */ plugin_call_cleanup(srv, con); network_mysqld_con_free(con); con = NULL; return; case CON_STATE_CLOSE_CLIENT: /* the server connection is still fine, * let's keep it open for reuse */ plugin_call_cleanup(srv, con); network_mysqld_con_free(con); con = NULL; return; case CON_STATE_INIT: /* if we are a proxy ask the remote server for the hand-shake packet * if not, we generate one */ switch (plugin_call(srv, con, con->state)) { case RET_SUCCESS: break; default: /** * no luck, let's close the connection */ g_critical("%s.%d: plugin_call(CON_STATE_INIT) != RET_SUCCESS", __FILE__, __LINE__); con->state = CON_STATE_ERROR; break; } break; case CON_STATE_CONNECT_SERVER: switch (plugin_call(srv, con, con->state)) { case RET_SUCCESS: /** * hmm, if this is success and we have something in the clients send-queue * we just send it out ... who needs a server ? */ if (con->client->send_queue->chunks->length > 0 && con->server == NULL) { /* we want to send something to the client */ con->state = CON_STATE_SEND_HANDSHAKE; } else { g_assert(con->server); } break; case RET_ERROR_RETRY: if (con->server) { /** * we have a server connection waiting to begin writable */ WAIT_FOR_EVENT(con->server, EV_WRITE, NULL); return; } else { /* try to get a connection to another backend, * * setting ostate = CON_STATE_INIT is a hack to make sure * the loop is coming back to this function again */ ostate = CON_STATE_INIT; } break; case RET_ERROR: /** * connecting failed and no option to retry * * close the connection */ con->state = CON_STATE_SEND_ERROR; break; default: g_error("%s.%d: ...", __FILE__, __LINE__); break; } break; case CON_STATE_READ_HANDSHAKE: { /** * read auth data from the remote mysql-server */ network_socket *recv_sock; recv_sock = con->server; g_assert(events == 0 || event_fd == recv_sock->fd); switch (network_mysqld_read(srv, recv_sock)) { case RET_SUCCESS: break; case RET_WAIT_FOR_EVENT: /* call us again when you have a event */ WAIT_FOR_EVENT(con->server, EV_READ, NULL); return; case RET_ERROR_RETRY: case RET_ERROR: g_error("%s.%d: plugin_call(CON_STATE_CONNECT_SERVER) returned an error", __FILE__, __LINE__); break; } switch (plugin_call(srv, con, con->state)) { case RET_SUCCESS: break; case RET_ERROR: /** * we couldn't understand the pack from the server * * we have something in the queue and will send it to the client * and close the connection afterwards */ con->state = CON_STATE_SEND_ERROR; break; default: g_error("%s.%d: ...", __FILE__, __LINE__); break; } break; } case CON_STATE_SEND_HANDSHAKE: /* send the hand-shake to the client and wait for a response */ switch (network_mysqld_write(srv, con->client)) { case RET_SUCCESS: break; case RET_WAIT_FOR_EVENT: WAIT_FOR_EVENT(con->client, EV_WRITE, NULL); return; case RET_ERROR_RETRY: case RET_ERROR: /** * writing failed, closing connection */ con->state = CON_STATE_ERROR; break; } switch (plugin_call(srv, con, con->state)) { case RET_SUCCESS: break; default: g_error("%s.%d: plugin_call(CON_STATE_SEND_HANDSHAKE) != RET_SUCCESS", __FILE__, __LINE__); break; } break; case CON_STATE_READ_AUTH: { /* read auth from client */ network_socket *recv_sock; recv_sock = con->client; g_assert(events == 0 || event_fd == recv_sock->fd); switch (network_mysqld_read(srv, recv_sock)) { case RET_SUCCESS: break; case RET_WAIT_FOR_EVENT: WAIT_FOR_EVENT(con->client, EV_READ, NULL); return; case RET_ERROR_RETRY: case RET_ERROR: g_error("%s.%d: network_mysqld_read(CON_STATE_READ_AUTH) returned an error", __FILE__, __LINE__); return; } switch (plugin_call(srv, con, con->state)) { case RET_SUCCESS: break; default: g_error("%s.%d: plugin_call(CON_STATE_READ_AUTH) != RET_SUCCESS", __FILE__, __LINE__); break; } break; } case CON_STATE_SEND_AUTH: /* send the auth-response to the server */ switch (network_mysqld_write(srv, con->server)) { case RET_SUCCESS: break; case RET_WAIT_FOR_EVENT: WAIT_FOR_EVENT(con->server, EV_WRITE, NULL); return; case RET_ERROR_RETRY: case RET_ERROR: /* might be a connection close, we should just close the connection and be happy */ con->state = CON_STATE_ERROR; break; } switch (plugin_call(srv, con, con->state)) { case RET_SUCCESS: break; default: g_error("%s.%d: plugin_call(CON_STATE_SEND_AUTH) != RET_SUCCESS", __FILE__, __LINE__); break; } break; case CON_STATE_READ_AUTH_RESULT: { /* read the auth result from the server */ network_socket *recv_sock; GList *chunk; GString *packet; recv_sock = con->server; g_assert(events == 0 || event_fd == recv_sock->fd); switch (network_mysqld_read(srv, recv_sock)) { case RET_SUCCESS: break; case RET_WAIT_FOR_EVENT: WAIT_FOR_EVENT(con->server, EV_READ, NULL); return; case RET_ERROR_RETRY: case RET_ERROR: g_error("%s.%d: network_mysqld_read(CON_STATE_READ_AUTH_RESULT) returned an error", __FILE__, __LINE__); return; } /** * depending on the result-set we have different exit-points * - OK -> READ_QUERY * - EOF -> (read old password hash) * - ERR -> ERROR */ chunk = recv_sock->recv_queue->chunks->head; packet = chunk->data; g_assert(packet); g_assert(packet->len > NET_HEADER_SIZE); con->parse.state.auth_result.state = packet->str[NET_HEADER_SIZE]; switch (plugin_call(srv, con, con->state)) { case RET_SUCCESS: break; default: g_critical("%s.%d: plugin_call(CON_STATE_READ_AUTH_RESULT) != RET_SUCCESS", __FILE__, __LINE__); con->state = CON_STATE_ERROR; break; } break; } case CON_STATE_SEND_AUTH_RESULT: { /* send the hand-shake to the client and wait for a response */ switch (network_mysqld_write(srv, con->client)) { case RET_SUCCESS: break; case RET_WAIT_FOR_EVENT: WAIT_FOR_EVENT(con->client, EV_WRITE, NULL); return; case RET_ERROR_RETRY: case RET_ERROR: g_debug("%s.%d: network_mysqld_write(CON_STATE_SEND_AUTH_RESULT) returned an error", __FILE__, __LINE__); con->state = CON_STATE_ERROR; break; } switch (plugin_call(srv, con, con->state)) { case RET_SUCCESS: break; default: g_error("%s.%d: ...", __FILE__, __LINE__); break; } break; } case CON_STATE_READ_AUTH_OLD_PASSWORD: /* read auth from client */ switch (network_mysqld_read(srv, con->client)) { case RET_SUCCESS: break; case RET_WAIT_FOR_EVENT: WAIT_FOR_EVENT(con->client, EV_READ, NULL); return; case RET_ERROR_RETRY: case RET_ERROR: g_error("%s.%d: network_mysqld_read(CON_STATE_READ_AUTH_OLD_PASSWORD) returned an error", __FILE__, __LINE__); return; } switch (plugin_call(srv, con, con->state)) { case RET_SUCCESS: break; default: g_error("%s.%d: plugin_call(CON_STATE_READ_AUTH_OLD_PASSWORD) != RET_SUCCESS", __FILE__, __LINE__); break; } break; case CON_STATE_SEND_AUTH_OLD_PASSWORD: /* send the auth-response to the server */ switch (network_mysqld_write(srv, con->server)) { case RET_SUCCESS: break; case RET_WAIT_FOR_EVENT: WAIT_FOR_EVENT(con->server, EV_WRITE, NULL); return; case RET_ERROR_RETRY: case RET_ERROR: /* might be a connection close, we should just close the connection and be happy */ g_debug("%s.%d: network_mysqld_write(CON_STATE_SEND_AUTH_OLD_PASSWORD) returned an error", __FILE__, __LINE__); con->state = CON_STATE_ERROR; break; } switch (plugin_call(srv, con, con->state)) { case RET_SUCCESS: break; default: g_error("%s.%d: plugin_call(CON_STATE_SEND_AUTH_OLD_PASSWORD) != RET_SUCCESS", __FILE__, __LINE__); break; } break; case CON_STATE_READ_QUERY: { network_socket *recv_sock; recv_sock = con->client; g_assert(events == 0 || event_fd == recv_sock->fd); switch (network_mysqld_read(srv, recv_sock)) { case RET_SUCCESS: break; case RET_WAIT_FOR_EVENT: WAIT_FOR_EVENT(con->client, EV_READ, NULL); return; case RET_ERROR_RETRY: case RET_ERROR: g_error("%s.%d: network_mysqld_read(CON_STATE_READ_QUERY) returned an error", __FILE__, __LINE__); return; } switch (plugin_call(srv, con, con->state)) { case RET_SUCCESS: break; default: g_critical("%s.%d: plugin_call(CON_STATE_READ_QUERY) failed", __FILE__, __LINE__); con->state = CON_STATE_ERROR; break; } break; } case CON_STATE_SEND_QUERY: /* send the query to the server */ if (con->server->send_queue->offset == 0) { /* only parse the packets once */ GString *s; GList *chunk; chunk = con->server->send_queue->chunks->head; s = chunk->data; /* only parse once and don't care about the blocking read */ if (con->parse.command == COM_QUERY && con->parse.state.query == PARSE_COM_QUERY_LOAD_DATA) { /* is this a LOAD DATA INFILE ... extra round ? */ /* this isn't a command packet, but a LOAD DATA INFILE data-packet */ if (s->str[0] == 0 && s->str[1] == 0 && s->str[2] == 0) { con->parse.state.query = PARSE_COM_QUERY_LOAD_DATA_END_DATA; } } else if (con->is_overlong_packet) { /* the last packet was a over-long packet * this is the same command, just more data */ if (con->parse.len != PACKET_LEN_MAX) { con->is_overlong_packet = 0; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -