Mercurial > hg > nginx-quic
view src/mysql/ngx_mysql.c @ 4943:1e2d5d3f9f6b
Core: removed GLOB_NOSORT glob option.
This will result in alphabetical sorting of included files if
the "include" directive with wildcards is used.
Note that the behaviour is now different from that on Windows, where
alphabetical sorting is not guaranteed for FindFirsFile()/FindNextFile()
(used to be alphabetical on NTFS, but not on FAT).
Approved by Igor Sysoev, prodded by many.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Thu, 29 Nov 2012 23:15:41 +0000 |
parents | d620f497c50f |
children |
line wrap: on
line source
/* * Copyright (C) Igor Sysoev * Copyright (C) Nginx, Inc. */ /* the library supports the subset of the MySQL 4.1+ protocol (version 10) */ #include <ngx_config.h> #include <ngx_core.h> #include <ngx_event.h> #include <ngx_event_connect.h> #include <ngx_mysql.h> #include <ngx_sha1.h> #define NGX_MYSQL_LONG_PASSWORD 0x0001 #define NGX_MYSQL_CONNECT_WITH_DB 0x0008 #define NGX_MYSQL_PROTOCOL_41 0x0200 #define NGX_MYSQL_SECURE_CONNECTION 0x8000 #define NGX_MYSQL_CMD_QUERY 3 typedef struct { u_char pktlen[3]; u_char pktn; u_char protocol; u_char version[1]; /* NULL-terminated string */ } ngx_mysql_greeting1_pkt_t; typedef struct { u_char thread[4]; u_char salt1[9]; u_char capacity[2]; u_char charset; u_char status[2]; u_char zero[13]; u_char salt2[13]; } ngx_mysql_greeting2_pkt_t; typedef struct { u_char pktlen[3]; u_char pktn; u_char capacity[4]; u_char max_packet[4]; u_char charset; u_char zero[23]; u_char login[1]; /* NULL-terminated string */ /* * u_char passwd_len; 0 if no password * u_char passwd[20]; * * u_char database[1]; NULL-terminated string */ } ngx_mysql_auth_pkt_t; typedef struct { u_char pktlen[3]; u_char pktn; u_char fields; } ngx_mysql_response_pkt_t; typedef struct { u_char pktlen[3]; u_char pktn; u_char err; u_char code[2]; u_char message[1]; /* string */ } ngx_mysql_error_pkt_t; typedef struct { u_char pktlen[3]; u_char pktn; u_char command; u_char arg[1]; /* string */ } ngx_mysql_command_pkt_t; static void ngx_mysql_read_server_greeting(ngx_event_t *rev); static void ngx_mysql_empty_handler(ngx_event_t *wev); static void ngx_mysql_read_auth_result(ngx_event_t *rev); static void ngx_mysql_read_query_result(ngx_event_t *rev); static void ngx_mysql_close(ngx_mysql_t *m, ngx_int_t rc); ngx_int_t ngx_mysql_connect(ngx_mysql_t *m) { ngx_int_t rc; #if 0 if (cached) { return NGX_OK; } #endif m->peer.log->action = "connecting to mysql server"; rc = ngx_event_connect_peer(&m->peer); if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) { return rc; } m->peer.connection->data = m; m->peer.connection->read->handler = ngx_mysql_read_server_greeting; m->peer.connection->write->handler = ngx_mysql_empty_handler; ngx_add_timer(m->peer.connection->read, /* STUB */ 5000); return NGX_OK; } static void ngx_mysql_read_server_greeting(ngx_event_t *rev) { size_t len; u_char *p; ssize_t n; ngx_uint_t i, capacity; ngx_mysql_t *m; ngx_connection_t *c; ngx_mysql_greeting1_pkt_t *gr1; ngx_mysql_greeting2_pkt_t *gr2; ngx_mysql_auth_pkt_t *auth; ngx_sha1_t sha; u_char hash1[20], hash2[20]; c = rev->data; m = c->data; if (rev->timedout) { ngx_log_error(NGX_LOG_ERR, rev->log, NGX_ETIMEDOUT, "mysql server %V timed out", m->peer.name); ngx_mysql_close(m, NGX_ERROR); return; } if (m->buf == NULL) { m->peer.log->action = "reading mysql server greeting"; m->buf = ngx_create_temp_buf(m->pool, /* STUB */ 1024); if (m->buf == NULL) { ngx_mysql_close(m, NGX_ERROR); return; } } n = ngx_recv(m->peer.connection, m->buf->pos, /* STUB */ 1024); if (n == NGX_AGAIN) { return; } if (n < 5) { ngx_mysql_close(m, NGX_ERROR); return; } gr1 = (ngx_mysql_greeting1_pkt_t *) m->buf->pos; if (ngx_m24toh(gr1->pktlen) > n - 4) { ngx_log_error(NGX_LOG_ERR, rev->log, 0, "mysql server %V sent incomplete greeting packet", m->peer.name); ngx_mysql_close(m, NGX_ERROR); return; } if (gr1->protocol < 10) { ngx_log_error(NGX_LOG_ERR, rev->log, 0, "mysql server %V sent unsupported protocol version %ud", m->peer.name, gr1->protocol); ngx_mysql_close(m, NGX_ERROR); return; } gr2 = (ngx_mysql_greeting2_pkt_t *) (gr1->version + ngx_strlen(gr1->version) + 1); capacity = ngx_m16toh(gr2->capacity); ngx_log_debug8(NGX_LOG_DEBUG_MYSQL, rev->log, 0, "mysql version: %ud, \"%s\", thread: %ud, salt: \"%s\", " "capacity: %Xd, charset: %ud, status: %ud, salt rest \"%s\"", gr1->protocol, gr1->version, ngx_m32toh(gr2->thread), gr2->salt1, capacity, gr2->charset, ngx_m16toh(gr2->status), &gr2->salt2); capacity = NGX_MYSQL_LONG_PASSWORD | NGX_MYSQL_CONNECT_WITH_DB | NGX_MYSQL_PROTOCOL_41 | NGX_MYSQL_SECURE_CONNECTION; len = 4 + 4 + 4 + 1 + 23 + m->login->len + 1 + 1 + m->database->len + 1; if (m->passwd->len) { len += 20; } auth = ngx_pnalloc(m->pool, len); if (auth == NULL) { ngx_mysql_close(m, NGX_ERROR); return; } ngx_htom24(auth->pktlen, len - 4); auth->pktn = (u_char) (gr1->pktn + 1); ngx_htom32(auth->capacity, capacity); ngx_htom32(auth->max_packet, 0x01000000); /* max packet size 2^24 */ ngx_memzero(auth->zero, 24); auth->charset = gr2->charset; p = ngx_copy(auth->login, m->login->data, m->login->len); *p++ = '\0'; if (m->passwd->len) { *p++ = (u_char) 20; ngx_sha1_init(&sha); ngx_sha1_update(&sha, m->passwd->data, m->passwd->len); ngx_sha1_final(hash1, &sha); ngx_sha1_init(&sha); ngx_sha1_update(&sha, hash1, 20); ngx_sha1_final(hash2, &sha); ngx_sha1_init(&sha); ngx_sha1_update(&sha, gr2->salt1, 8); ngx_sha1_update(&sha, gr2->salt2, 12); ngx_sha1_update(&sha, hash2, 20); ngx_sha1_final(hash2, &sha); for (i = 0; i < 20; i++) { *p++ = (u_char) (hash1[i] ^ hash2[i]); } } else { *p++ = '\0'; } p = ngx_copy(p, m->database->data, m->database->len); *p = '\0'; n = ngx_send(m->peer.connection, (void *) auth, len); if (n < (ssize_t) len) { ngx_log_error(NGX_LOG_ERR, rev->log, 0, "the incomplete packet was sent to mysql server %V", m->peer.name); ngx_mysql_close(m, NGX_ERROR); return; } m->peer.connection->read->handler = ngx_mysql_read_auth_result; ngx_add_timer(m->peer.connection->read, /* STUB */ 5000); } static void ngx_mysql_empty_handler(ngx_event_t *wev) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0, "mysql empty handler"); return; } static void ngx_mysql_read_auth_result(ngx_event_t *rev) { ssize_t n, len; ngx_str_t msg; ngx_mysql_t *m; ngx_connection_t *c; ngx_mysql_error_pkt_t *epkt; ngx_mysql_response_pkt_t *pkt; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "mysql read auth"); c = rev->data; m = c->data; m->peer.log->action = "reading mysql auth result"; n = ngx_recv(m->peer.connection, m->buf->pos, /* STUB */ 1024); if (n == NGX_AGAIN) { return; } if (n < 5) { ngx_mysql_close(m, NGX_ERROR); return; } pkt = (ngx_mysql_response_pkt_t *) m->buf->pos; len = ngx_m24toh(pkt->pktlen); if (len > n - 4) { ngx_log_error(NGX_LOG_ERR, rev->log, 0, "mysql server %V sent incomplete response packet", m->peer.name); ngx_mysql_close(m, NGX_ERROR); return; } if (pkt->fields == 0) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "mysql auth OK"); m->state = NGX_OK; m->pktn = 0; m->handler(m); return; } epkt = (ngx_mysql_error_pkt_t *) pkt; msg.len = (u_char *) epkt + 4 + len - epkt->message; msg.data = epkt->message; ngx_log_error(NGX_LOG_ERR, rev->log, 0, "mysql server %V sent error (%ud): \"%V\"", m->peer.name, ngx_m16toh(epkt->code), &msg); ngx_mysql_close(m, NGX_ERROR); } ngx_int_t ngx_mysql_query(ngx_mysql_t *m) { ssize_t n; ngx_mysql_command_pkt_t *pkt; pkt = (ngx_mysql_command_pkt_t *) m->query.data; ngx_htom24(pkt->pktlen, m->query.len - 4); pkt->pktn = (u_char) m->pktn++; pkt->command = NGX_MYSQL_CMD_QUERY; n = ngx_send(m->peer.connection, m->query.data, m->query.len); if (n < (ssize_t) m->query.len) { ngx_log_error(NGX_LOG_ERR, m->peer.log, 0, "the incomplete packet was sent to mysql server %V", m->peer.name); ngx_mysql_close(m, NGX_ERROR); return NGX_OK; } m->peer.connection->read->handler = ngx_mysql_read_query_result; ngx_add_timer(m->peer.connection->read, /* STUB */ 5000); /* STUB handle event */ return NGX_OK; } static void ngx_mysql_read_query_result(ngx_event_t *rev) { ssize_t n, len; ngx_str_t msg; ngx_mysql_t *m; ngx_connection_t *c; ngx_mysql_error_pkt_t *epkt; ngx_mysql_response_pkt_t *pkt; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "mysql read query result"); c = rev->data; m = c->data; m->peer.log->action = "reading mysql read query result"; n = ngx_recv(m->peer.connection, m->buf->pos, /* STUB */ 1024); if (n == NGX_AGAIN) { return; } if (n < 5) { ngx_mysql_close(m, NGX_ERROR); return; } pkt = (ngx_mysql_response_pkt_t *) m->buf->pos; len = ngx_m24toh(pkt->pktlen); if (len > n - 4) { ngx_log_error(NGX_LOG_ERR, rev->log, 0, "mysql server %V sent incomplete response packet", m->peer.name); ngx_mysql_close(m, NGX_ERROR); return; } if (pkt->fields != 0xff) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "mysql query OK"); m->state = NGX_OK; m->pktn = pkt->pktn; m->handler(m); return; } epkt = (ngx_mysql_error_pkt_t *) pkt; msg.len = (u_char *) epkt + 4 + len - epkt->message; msg.data = epkt->message; ngx_log_error(NGX_LOG_ERR, rev->log, 0, "mysql server %V sent error (%ud): \"%V\"", m->peer.name, ngx_m16toh(epkt->code), &msg); ngx_mysql_close(m, NGX_ERROR); } static void ngx_mysql_close(ngx_mysql_t *m, ngx_int_t rc) { if (rc == NGX_ERROR) { ngx_close_connection(m->peer.connection); } m->state = rc; m->handler(m); }