From a046af40dc1d4683555f2ab8119719dcc3d51af6 Mon Sep 17 00:00:00 2001 From: lingel <2894340009@qq.com> Date: Mon, 17 Jun 2024 15:13:12 +0800 Subject: [PATCH 1/3] 1 --- .../ngx_http_upstream_check.c | 0 .../ngx_http_upstream_check.h | 0 src/epollip/connector_controller.cpp | 288 ++++++++++++++++++ src/epollip/connector_database.cpp | 31 ++ src/epollip/connector_gateway.cpp | 86 ++++++ src/epollip/db_processer/basic_db.cpp | 66 ++++ .../interface/connector_controller.cpp | 280 +++++++++++++++++ src/epollip/interface/connector_controller.h | 22 ++ src/epollip/interface/connector_database.cpp | 68 +++++ src/epollip/interface/connector_database.h | 10 + src/epollip/interface/main.cpp | 35 +++ src/epollip/interface/main_program | Bin 0 -> 90968 bytes src/epollip/new_client.cpp | 125 ++++++++ 13 files changed, 1011 insertions(+) rename src/{positivedetect => detect}/ngx_http_upstream_check.c (100%) rename src/{positivedetect => detect}/ngx_http_upstream_check.h (100%) create mode 100644 src/epollip/connector_controller.cpp create mode 100644 src/epollip/connector_database.cpp create mode 100644 src/epollip/connector_gateway.cpp create mode 100644 src/epollip/db_processer/basic_db.cpp create mode 100644 src/epollip/interface/connector_controller.cpp create mode 100644 src/epollip/interface/connector_controller.h create mode 100644 src/epollip/interface/connector_database.cpp create mode 100644 src/epollip/interface/connector_database.h create mode 100644 src/epollip/interface/main.cpp create mode 100644 src/epollip/interface/main_program create mode 100644 src/epollip/new_client.cpp diff --git a/src/positivedetect/ngx_http_upstream_check.c b/src/detect/ngx_http_upstream_check.c similarity index 100% rename from src/positivedetect/ngx_http_upstream_check.c rename to src/detect/ngx_http_upstream_check.c diff --git a/src/positivedetect/ngx_http_upstream_check.h b/src/detect/ngx_http_upstream_check.h similarity index 100% rename from src/positivedetect/ngx_http_upstream_check.h rename to src/detect/ngx_http_upstream_check.h diff --git a/src/epollip/connector_controller.cpp b/src/epollip/connector_controller.cpp new file mode 100644 index 0000000..6b0d54c --- /dev/null +++ b/src/epollip/connector_controller.cpp @@ -0,0 +1,288 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BUFFER_SIZE 1024 +#define HTTP_SERVER_PORT 8080 + +std::vector threads; // 存储所有连接线程 +std::map sockets; // 存储套接字 +std::mutex sockets_mutex; // 用于同步访问 sockets +std::atomic exit_flag(false); // 原子退出标志 + + +// 维护连接的函数 +void KeepConnection(int sock) { + char buffer[BUFFER_SIZE]; + int nbytes; + while (!exit_flag) { + nbytes = recv(sock, buffer, BUFFER_SIZE, 0); + if (nbytes <= 0) { + std::cout << "Gateway disconnected" << std::endl; + break; + } + std::cout << "Received from gateway (Socket " << sock << "): " << buffer << std::endl; + } + + { + std::lock_guard lock(sockets_mutex); + sockets.erase(sock); // 从集合中移除套接字 + } + close(sock); +} +// 连接到网关的函数 +void ConnectToGateway(const std::string& ip, int port) { + int sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) { + perror("Could not create socket"); + return; + } + + struct sockaddr_in server_addr; + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(port); + if (inet_pton(AF_INET, ip.c_str(), &server_addr.sin_addr) <= 0) { + perror("Invalid address"); + close(sock); + return; + } + + if (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { + perror("Connection to the server failed"); + close(sock); + return; + } + + { + std::lock_guard lock(sockets_mutex); + sockets[sock] = 1; // 将套接字添加到集合中 + } + + std::cout << "Connected to gateway at " << ip << ":" << port << " (Socket " << sock << ")" << std::endl; + + // 在新线程中维护连接 + threads.emplace_back(KeepConnection, sock); +} + +// 处理HTTP请求的函数 +void HandleHttpRequest(int client_socket) { + char buffer[BUFFER_SIZE]; + int bytes_read = recv(client_socket, buffer, sizeof(buffer), 0); + if (bytes_read <= 0) { + close(client_socket); + return; + } + + // 简单解析HTTP请求 + std::string http_request(buffer, bytes_read); + std::string ip; + int port; + + // 寻找IP和端口号 + auto host_pos = http_request.find("Host: "); + if (host_pos != std::string::npos) { + auto start = host_pos + std::string("Host: ").size(); + ip = http_request.substr(start, http_request.find("\r\n", start) - start); + } + + auto content_length_pos = http_request.find("Content-Length:"); + if (content_length_pos != std::string::npos) { + auto start = content_length_pos + std::string("Content-Length: ").size(); + int length = std::stoi(http_request.substr(start, http_request.find("\r\n", start) - start)); + if (length > 0) { + char* content = new char[length]; + bytes_read = recv(client_socket, content, length, 0); + if (bytes_read > 0) { + // 解析JSON内容(假设前端发送的是JSON格式) + // 这里需要添加JSON解析逻辑来提取IP和端口 + // 示例:{"ip":"192.168.1.1","port":8080} + // 可以使用第三方库如nlohmann/json来解析JSON + + // 假设解析后得到ip和port + // ConnectToGateway(ip, port); + + delete[] content; + } + } + } + + // 发送HTTP响应 + std::string response = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\n"; + send(client_socket, response.c_str(), response.size(), 0); + close(client_socket); +} + +// 启动HTTP服务器的函数 +void StartHttpServer() { + int http_server_socket = socket(AF_INET, SOCK_STREAM, 0); + if (http_server_socket < 0) { + perror("Could not create HTTP server socket"); + return; + } + + int opt = 1; + if (setsockopt(http_server_socket, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) { + perror("Setsockopt failed"); + close(http_server_socket); + return; + } + + struct sockaddr_in server_addr; + server_addr.sin_family = AF_INET; + server_addr.sin_addr.s_addr = INADDR_ANY; + server_addr.sin_port = htons(HTTP_SERVER_PORT); + + if (bind(http_server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { + perror("Bind failed"); + close(http_server_socket); + return; + } + + if (listen(http_server_socket, 5) < 0) { + perror("Listen failed"); + close(http_server_socket); + return; + } + + std::cout << "HTTP server listening on port " << HTTP_SERVER_PORT << std::endl; + + while (!exit_flag) { + int client_socket = accept(http_server_socket, NULL, NULL); + if (client_socket < 0) { + perror("Accept failed"); + continue; + } + + threads.emplace_back(HandleHttpRequest, client_socket); + } + + close(http_server_socket); +} + +int main() { + // threads.emplace_back(StartHttpServer); + + // std::string command, ip; + // int port; + // bool in_connect_mode = false; + // std::cout << "Enter command (connect/exit): "; + // while (true) { + + // if (in_connect_mode) + // { + // std::cout << "continue connect or not ? (y or n) "; + // std::cin >> command; + // if(command=="y"){ + // std::cout << "Enter the gateway IP address: "; + // std::cin >> ip; + // std::cout << "Enter the gateway port: "; + // std::cin >> port; + // ConnectToGateway(ip, port); + // } + // else { + // in_connect_mode = false; // 退出连接模式 + // std::cout << "Exiting connect mode." << std::endl; + // } + // } + // else{ + // std::cout << "Enter command (connect/exit): "; + // std::cin>>command; + // if (command == "connect") { + // if (in_connect_mode) { + // std::cout << "Already in connect mode." << std::endl; + // continue; + // } + // in_connect_mode = true; // 进入连接模式 + // std::cout << "Enter the gateway IP address: "; + // std::cin >> ip; + // std::cout << "Enter the gateway port: "; + // std::cin >> port; + // ConnectToGateway(ip, port); + // } else if (command == "exit") { + // exit_flag = true; // 设置退出标志 + // std::cout << "Exiting program." << std::endl; + // // 关闭所有套接字 + // for (auto& sock_pair : sockets) { + // shutdown(sock_pair.first, SHUT_RDWR); // 关闭套接字的发送和接收 + // close(sock_pair.first); + // } + // sockets.clear(); + // std::cout << "sockets.clear" << std::endl; + // // 等待所有线程结束 + // for (auto& thread : threads) { + // if (thread.joinable()) { + // thread.join(); + // } + // } + // threads.clear(); + // break; // 退出主循环 + // } else { + // std::cout << "Unknown command" << std::endl; + // } + // } + // } + // std::cout<<"out"<> command; + + if (command == "connect") { + if (in_connect_mode) { + std::cout << "Already in connect mode." << std::endl; + continue; + } + in_connect_mode = true; + std::cout << "Enter the gateway IP address: "; + std::cin >> ip; + std::cout << "Enter the gateway port: "; + std::cin >> port; + ConnectToGateway(ip, port); + } else if (command == "exit") { + break; // 接收到退出命令,退出主循环 + } else { + std::cout << "Unknown command" << std::endl; + } + } + + // 设置退出标志 + exit_flag = true; + + // 强制结束HTTP服务器线程 + if (http_server_thread.joinable()) { + http_server_thread.join(); + } + + // 关闭所有套接字 + for (auto& sock_pair : sockets) { + shutdown(sock_pair.first, SHUT_RDWR); + close(sock_pair.first); + } + sockets.clear(); + + // 等待所有工作线程结束 + for (auto& thread : threads) { + if (thread.joinable()) { + thread.join(); + } + } + threads.clear(); + + std::cout << "Exited program." << std::endl; + return 0; + +} \ No newline at end of file diff --git a/src/epollip/connector_database.cpp b/src/epollip/connector_database.cpp new file mode 100644 index 0000000..d0768cc --- /dev/null +++ b/src/epollip/connector_database.cpp @@ -0,0 +1,31 @@ +#include +#include + +int main() { + MYSQL *conn; + conn = mysql_init(NULL); + + if (conn == NULL) { + std::cerr << "MySQL init failed" << std::endl; + return 1; + } + + const char *server = "localhost"; + const char *user = "rtsw"; + const char *password = "123456"; + const char *database = "nginxdb"; + unsigned int port = 3306; // 使用云数据库提供的端口 + + if (mysql_real_connect(conn, server, user, password, database, port, NULL, 0) == NULL) { + std::cerr << "Connection error: " << mysql_error(conn) << std::endl; + mysql_close(conn); + return 1; + } + + std::cout << "Successfully connected to the database" << std::endl; + + // ... 执行数据库操作 ... + + mysql_close(conn); + return 0; +} \ No newline at end of file diff --git a/src/epollip/connector_gateway.cpp b/src/epollip/connector_gateway.cpp new file mode 100644 index 0000000..b6ba4d7 --- /dev/null +++ b/src/epollip/connector_gateway.cpp @@ -0,0 +1,86 @@ +#include +#include +#include +#include +#include +#include +#include + +#define PORT 8080 +#define MAX_CLIENTS 5 +#define BUFFER_SIZE 1024 + +// 声明 handle_client 函数 +void handle_client(int client_socket); + +int main() { + int server_fd, new_socket; + struct sockaddr_in server_addr, client_addr; + socklen_t client_len = sizeof(client_addr); + char buffer[BUFFER_SIZE]; + int opt = 1; + + // 创建套接字 + server_fd = socket(AF_INET, SOCK_STREAM, 0); + if (server_fd < 0) { + perror("socket creation failed"); + exit(EXIT_FAILURE); + } + + // 设置选项,允许重用地址 + if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) { + perror("setsockopt failed"); + exit(EXIT_FAILURE); + } + + server_addr.sin_family = AF_INET; + server_addr.sin_addr.s_addr = INADDR_ANY; + server_addr.sin_port = htons(PORT); + + // 绑定 + if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { + perror("bind failed"); + exit(EXIT_FAILURE); + } + + // 监听 + if (listen(server_fd, MAX_CLIENTS) < 0) { + perror("listen failed"); + exit(EXIT_FAILURE); + } + + std::cout << "Server listening on port " << PORT << std::endl; + + while (true) { + client_len = sizeof(client_addr); + new_socket = accept(server_fd, (struct sockaddr *)&client_addr, &client_len); + if (new_socket < 0) { + perror("accept failed"); + exit(EXIT_FAILURE); + } + + std::cout << "New client connected from " << inet_ntoa(client_addr.sin_addr) << " port " << ntohs(client_addr.sin_port) << std::endl; + + // 创建并启动线程处理客户端 + std::thread(handle_client, new_socket).detach(); + } + + close(server_fd); + return 0; +} + +// 定义 handle_client 函数 +void handle_client(int client_socket) { + while (true) { + char buffer[BUFFER_SIZE]; + memset(buffer, 0, BUFFER_SIZE); // 清空缓冲区 + int nbytes = read(client_socket, buffer, BUFFER_SIZE); + if (nbytes <= 0) { + std::cout << "Client disconnected." << std::endl; + close(client_socket); + break; + } + std::cout << "Received message from client: " << buffer << std::endl; + // 这里可以添加更多的处理逻辑 + } +} \ No newline at end of file diff --git a/src/epollip/db_processer/basic_db.cpp b/src/epollip/db_processer/basic_db.cpp new file mode 100644 index 0000000..0abc9ed --- /dev/null +++ b/src/epollip/db_processer/basic_db.cpp @@ -0,0 +1,66 @@ +#include +#include + +int main() { + MYSQL *conn; + conn = mysql_init(NULL); + + if (conn == NULL) { + std::cerr << "MySQL init failed" << std::endl; + return 1; + } + + const char *server = "localhost"; + const char *user = "rtsw"; + const char *password = "123456"; + const char *database = "nginxdb"; + unsigned int port = 3306; + + if (mysql_real_connect(conn, server, user, password, database, port, NULL, 0) == NULL) { + std::cerr << "Connection error: " << mysql_error(conn) << std::endl; + mysql_close(conn); + return 1; + } + + std::cout << "Successfully connected to the database" << std::endl; + + // 插入数据 + const char *insert_query = "INSERT INTO users (username, email) VALUES ('newuser', 'newuser@example.com')"; + if (mysql_query(conn, insert_query)) { + std::cerr << "Insert error: " << mysql_error(conn) << std::endl; + } else { + std::cout << "Insert successful" << std::endl; + } + + // 查询数据 + const char *select_query = "SELECT * FROM users"; + MYSQL_RES *result = mysql_store_result(conn); + if (result) { + MYSQL_ROW row; + while ((row = mysql_fetch_row(result))) { + std::cout << "id: " << row[0] << ", username: " << row[1] << ", email: " << row[2] << std::endl; + } + mysql_free_result(result); + } else { + std::cerr << "Select error: " << mysql_error(conn) << std::endl; + } + + // 更新数据 + const char *update_query = "UPDATE users SET email = 'newuser_updated@example.com' WHERE username = 'newuser'"; + if (mysql_query(conn, update_query)) { + std::cerr << "Update error: " << mysql_error(conn) << std::endl; + } else { + std::cout << "Update successful" << std::endl; + } + + // 删除数据 + const char *delete_query = "DELETE FROM users WHERE username = 'newuser'"; + if (mysql_query(conn, delete_query)) { + std::cerr << "Delete error: " << mysql_error(conn) << std::endl; + } else { + std::cout << "Delete successful" << std::endl; + } + + mysql_close(conn); + return 0; +} \ No newline at end of file diff --git a/src/epollip/interface/connector_controller.cpp b/src/epollip/interface/connector_controller.cpp new file mode 100644 index 0000000..2c93baf --- /dev/null +++ b/src/epollip/interface/connector_controller.cpp @@ -0,0 +1,280 @@ +#include "connector_controller.h" + +#define BUFFER_SIZE 1024 +#define HTTP_SERVER_PORT 8080 + +std::vector threads; // 存储所有连接线程 +std::map sockets; // 存储套接字 +std::mutex sockets_mutex; // 用于同步访问 sockets +std::atomic exit_flag(false); // 原子退出标志 + + +// 维护连接的函数 +void KeepConnection(int sock) { + char buffer[BUFFER_SIZE]; + int nbytes; + while (!exit_flag) { + nbytes = recv(sock, buffer, BUFFER_SIZE, 0); + if (nbytes <= 0) { + std::cout << "Gateway disconnected" << std::endl; + break; + } + std::cout << "Received from gateway (Socket " << sock << "): " << buffer << std::endl; + } + + { + std::lock_guard lock(sockets_mutex); + sockets.erase(sock); // 从集合中移除套接字 + } + close(sock); +} +// 连接到网关的函数 +void ConnectToGateway(const std::string& ip, int port) { + int sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) { + perror("Could not create socket"); + return; + } + + struct sockaddr_in server_addr; + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(port); + if (inet_pton(AF_INET, ip.c_str(), &server_addr.sin_addr) <= 0) { + perror("Invalid address"); + close(sock); + return; + } + + if (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { + perror("Connection to the server failed"); + close(sock); + return; + } + + { + std::lock_guard lock(sockets_mutex); + sockets[sock] = 1; // 将套接字添加到集合中 + } + + std::cout << "Connected to gateway at " << ip << ":" << port << " (Socket " << sock << ")" << std::endl; + + // 在新线程中维护连接 + threads.emplace_back(KeepConnection, sock); +} + +// 处理HTTP请求的函数 +void HandleHttpRequest(int client_socket) { + char buffer[BUFFER_SIZE]; + int bytes_read = recv(client_socket, buffer, sizeof(buffer), 0); + if (bytes_read <= 0) { + close(client_socket); + return; + } + + // 简单解析HTTP请求 + std::string http_request(buffer, bytes_read); + std::string ip; + int port; + + // 寻找IP和端口号 + auto host_pos = http_request.find("Host: "); + if (host_pos != std::string::npos) { + auto start = host_pos + std::string("Host: ").size(); + ip = http_request.substr(start, http_request.find("\r\n", start) - start); + } + + auto content_length_pos = http_request.find("Content-Length:"); + if (content_length_pos != std::string::npos) { + auto start = content_length_pos + std::string("Content-Length: ").size(); + int length = std::stoi(http_request.substr(start, http_request.find("\r\n", start) - start)); + if (length > 0) { + char* content = new char[length]; + bytes_read = recv(client_socket, content, length, 0); + if (bytes_read > 0) { + // 解析JSON内容(假设前端发送的是JSON格式) + // 这里需要添加JSON解析逻辑来提取IP和端口 + // 示例:{"ip":"192.168.1.1","port":8080} + // 可以使用第三方库如nlohmann/json来解析JSON + + // 假设解析后得到ip和port + // ConnectToGateway(ip, port); + + delete[] content; + } + } + } + + // 发送HTTP响应 + std::string response = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\n"; + send(client_socket, response.c_str(), response.size(), 0); + close(client_socket); +} + +// 启动HTTP服务器的函数 +void StartHttpServer() { + int http_server_socket = socket(AF_INET, SOCK_STREAM, 0); + if (http_server_socket < 0) { + perror("Could not create HTTP server socket"); + return; + } + + int opt = 1; + if (setsockopt(http_server_socket, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) { + perror("Setsockopt failed"); + close(http_server_socket); + return; + } + + struct sockaddr_in server_addr; + server_addr.sin_family = AF_INET; + server_addr.sin_addr.s_addr = INADDR_ANY; + server_addr.sin_port = htons(HTTP_SERVER_PORT); + + if (bind(http_server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { + perror("Bind failed"); + close(http_server_socket); + return; + } + + if (listen(http_server_socket, 5) < 0) { + perror("Listen failed"); + close(http_server_socket); + return; + } + + std::cout << "HTTP server listening on port " << HTTP_SERVER_PORT << std::endl; + + while (!exit_flag) { + int client_socket = accept(http_server_socket, NULL, NULL); + if (client_socket < 0) { + perror("Accept failed"); + continue; + } + + threads.emplace_back(HandleHttpRequest, client_socket); + } + + close(http_server_socket); +} + +/* +int main() { + // threads.emplace_back(StartHttpServer); + + // std::string command, ip; + // int port; + // bool in_connect_mode = false; + // std::cout << "Enter command (connect/exit): "; + // while (true) { + + // if (in_connect_mode) + // { + // std::cout << "continue connect or not ? (y or n) "; + // std::cin >> command; + // if(command=="y"){ + // std::cout << "Enter the gateway IP address: "; + // std::cin >> ip; + // std::cout << "Enter the gateway port: "; + // std::cin >> port; + // ConnectToGateway(ip, port); + // } + // else { + // in_connect_mode = false; // 退出连接模式 + // std::cout << "Exiting connect mode." << std::endl; + // } + // } + // else{ + // std::cout << "Enter command (connect/exit): "; + // std::cin>>command; + // if (command == "connect") { + // if (in_connect_mode) { + // std::cout << "Already in connect mode." << std::endl; + // continue; + // } + // in_connect_mode = true; // 进入连接模式 + // std::cout << "Enter the gateway IP address: "; + // std::cin >> ip; + // std::cout << "Enter the gateway port: "; + // std::cin >> port; + // ConnectToGateway(ip, port); + // } else if (command == "exit") { + // exit_flag = true; // 设置退出标志 + // std::cout << "Exiting program." << std::endl; + // // 关闭所有套接字 + // for (auto& sock_pair : sockets) { + // shutdown(sock_pair.first, SHUT_RDWR); // 关闭套接字的发送和接收 + // close(sock_pair.first); + // } + // sockets.clear(); + // std::cout << "sockets.clear" << std::endl; + // // 等待所有线程结束 + // for (auto& thread : threads) { + // if (thread.joinable()) { + // thread.join(); + // } + // } + // threads.clear(); + // break; // 退出主循环 + // } else { + // std::cout << "Unknown command" << std::endl; + // } + // } + // } + // std::cout<<"out"<> command; + + if (command == "connect") { + if (in_connect_mode) { + std::cout << "Already in connect mode." << std::endl; + continue; + } + in_connect_mode = true; + std::cout << "Enter the gateway IP address: "; + std::cin >> ip; + std::cout << "Enter the gateway port: "; + std::cin >> port; + ConnectToGateway(ip, port); + } else if (command == "exit") { + break; // 接收到退出命令,退出主循环 + } else { + std::cout << "Unknown command" << std::endl; + } + } + + // 设置退出标志 + exit_flag = true; + + // 强制结束HTTP服务器线程 + if (http_server_thread.joinable()) { + http_server_thread.join(); + } + + // 关闭所有套接字 + for (auto& sock_pair : sockets) { + shutdown(sock_pair.first, SHUT_RDWR); + close(sock_pair.first); + } + sockets.clear(); + + // 等待所有工作线程结束 + for (auto& thread : threads) { + if (thread.joinable()) { + thread.join(); + } + } + threads.clear(); + + std::cout << "Exited program." << std::endl; + return 0; + +} +*/ \ No newline at end of file diff --git a/src/epollip/interface/connector_controller.h b/src/epollip/interface/connector_controller.h new file mode 100644 index 0000000..c45ca15 --- /dev/null +++ b/src/epollip/interface/connector_controller.h @@ -0,0 +1,22 @@ +#ifndef CONNECTOR_CONTROLLER_H +#define CONNECTOR_CONTROLLER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// 函数声明 +void StartHttpServer(); +void ConnectToGateway(const std::string& ip, int port); +void KeepConnection(int sock); +void HandleHttpRequest(int client_socket); + +#endif // CONNECTOR_CONTROLLER_H \ No newline at end of file diff --git a/src/epollip/interface/connector_database.cpp b/src/epollip/interface/connector_database.cpp new file mode 100644 index 0000000..212bfd5 --- /dev/null +++ b/src/epollip/interface/connector_database.cpp @@ -0,0 +1,68 @@ +/* + 这个文件可以只负责链接数据库,其他的都不管 + 把数据库的句柄传给主程序 +*/ + +/* +#include +#include + +int main() { + MYSQL *conn; + conn = mysql_init(NULL); + + if (conn == NULL) { + std::cerr << "MySQL init failed" << std::endl; + return 1; + } + + const char *server = "localhost"; + const char *user = "rtsw"; + const char *password = "123456"; + const char *database = "nginxdb"; + unsigned int port = 3306; // 使用云数据库提供的端口 + + if (mysql_real_connect(conn, server, user, password, database, port, NULL, 0) == NULL) { + std::cerr << "Connection error: " << mysql_error(conn) << std::endl; + mysql_close(conn); + return 1; + } + + std::cout << "Successfully connected to the database" << std::endl; + + // ... 执行数据库操作 ... + + mysql_close(conn); + return 0; +} +*/ + +#include "connector_database.h" + +// DatabaseOperation函数定义 +void DatabaseOperation() { + MYSQL *conn = mysql_init(NULL); + + if (conn == NULL) { + std::cerr << "MySQL init failed" << std::endl; + return; + } + + const char *server = "localhost"; + const char *user = "rtsw"; + const char *password = "123456"; + const char *database = "nginxdb"; + unsigned int port = 3306; + + if (mysql_real_connect(conn, server, user, password, database, port, NULL, 0) == NULL) { + std::cerr << "Connection error: " << mysql_error(conn) << std::endl; + mysql_close(conn); + return; + } + + std::cout << "Successfully connected to the database" << std::endl; + + // ... 执行数据库操作 ... + + mysql_close(conn); +} \ No newline at end of file diff --git a/src/epollip/interface/connector_database.h b/src/epollip/interface/connector_database.h new file mode 100644 index 0000000..83a2cf6 --- /dev/null +++ b/src/epollip/interface/connector_database.h @@ -0,0 +1,10 @@ +#ifndef CONNECTOR_DATABASE_H +#define CONNECTOR_DATABASE_H + +#include +#include + +// 函数声明 +void DatabaseOperation(); + +#endif // CONNECTOR_DATABASE_H \ No newline at end of file diff --git a/src/epollip/interface/main.cpp b/src/epollip/interface/main.cpp new file mode 100644 index 0000000..e469900 --- /dev/null +++ b/src/epollip/interface/main.cpp @@ -0,0 +1,35 @@ +#include +#include +#include "connector_controller.h" +#include "connector_database.h" + +int main() { + std::string command; + bool running = true; + + while (running) { + std::cout << "Enter command (start_http_server/connect_gateway/database_operation/exit): "; + std::cin >> command; + + if (command == "start_http_server") { + StartHttpServer(); + } else if (command == "connect_gateway") { + std::string ip; + int port; + std::cout << "Enter the gateway IP address: "<>ip; // 使用getline以获取包含空格的IP地址 + std::cout << "Enter the gateway port: "<> port; + ConnectToGateway(ip, port); + } else if (command == "database_operation") { + DatabaseOperation(); + } else if (command == "exit") { + running = false; + } else { + std::cout << "Unknown command" << std::endl; + } + } + + std::cout << "Exiting program." << std::endl; + return 0; +} \ No newline at end of file diff --git a/src/epollip/interface/main_program b/src/epollip/interface/main_program new file mode 100644 index 0000000000000000000000000000000000000000..71bad27e38cebcd16ab3583728dd749c317ac390 GIT binary patch literal 90968 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BUFFER_SIZE 1024 + +std::vector threads; // 存储所有连接线程 +std::map sockets; // 存储套接字 +std::mutex sockets_mutex; // 用于同步访问 sockets +std::atomic exit_flag(false); // 原子退出标志 + + +// 维护连接的函数 +void KeepConnection(int sock) { + char buffer[BUFFER_SIZE]; + int nbytes; + while (!exit_flag) { + nbytes = recv(sock, buffer, BUFFER_SIZE, 0); + if (nbytes <= 0) { + std::cout << "Gateway disconnected" << std::endl; + break; + } + std::cout << "Received from gateway (Socket " << sock << "): " << buffer << std::endl; + } + + { + std::lock_guard lock(sockets_mutex); + sockets.erase(sock); // 从集合中移除套接字 + } + close(sock); +} +// 连接到网关的函数 +void ConnectToGateway(const std::string& ip, int port) { + int sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) { + perror("Could not create socket"); + return; + } + + struct sockaddr_in server_addr; + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(port); + if (inet_pton(AF_INET, ip.c_str(), &server_addr.sin_addr) <= 0) { + perror("Invalid address"); + close(sock); + return; + } + + if (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { + perror("Connection to the server failed"); + close(sock); + return; + } + + { + std::lock_guard lock(sockets_mutex); + sockets[sock] = 1; // 将套接字添加到集合中 + } + + std::cout << "Connected to gateway at " << ip << ":" << port << " (Socket " << sock << ")" << std::endl; + + // 在新线程中维护连接 + threads.emplace_back(KeepConnection, sock); +} + + + +int main() { + std::string command, ip; + int port; + bool in_connect_mode = false; + + while (true) { + std::cout << "Enter command (connect/exitconnect/exit): "; + std::cin >> command; + + if (command == "connect") { + if (in_connect_mode) { + std::cout << "Already in connect mode." << std::endl; + continue; + } + in_connect_mode = true; // 进入连接模式 + std::cout << "Enter the gateway IP address: "; + std::cin >> ip; + std::cout << "Enter the gateway port: "; + std::cin >> port; + ConnectToGateway(ip, port); + } else if (command == "exitconnect") { + if (!in_connect_mode) { + std::cout << "Not in connect mode." << std::endl; + continue; + } + in_connect_mode = false; // 退出连接模式 + std::cout << "Exiting connect mode." << std::endl; + } else if (command == "exit") { + exit_flag = true; // 设置退出标志 + std::cout << "Exiting program." << std::endl; + // 关闭所有套接字 + for (auto& sock_pair : sockets) { + shutdown(sock_pair.first, SHUT_RDWR); // 关闭套接字的发送和接收 + close(sock_pair.first); + } + sockets.clear(); + // 等待所有线程结束 + for (auto& thread : threads) { + if (thread.joinable()) { + thread.join(); + } + } + threads.clear(); + break; // 退出主循环 + } else { + std::cout << "Unknown command" << std::endl; + } + } + + return 0; +} \ No newline at end of file -- 2.34.1 From df431210c9a3794c490dd2b5aa530e7366a3105a Mon Sep 17 00:00:00 2001 From: lingel <2894340009@qq.com> Date: Mon, 17 Jun 2024 15:23:05 +0800 Subject: [PATCH 2/3] 1 --- src/detecter/ngx_http_upstream_checker.c | 4071 ++++++++++++++++++++++ src/detecter/ngx_http_upstream_checker.h | 19 + 2 files changed, 4090 insertions(+) create mode 100644 src/detecter/ngx_http_upstream_checker.c create mode 100644 src/detecter/ngx_http_upstream_checker.h diff --git a/src/detecter/ngx_http_upstream_checker.c b/src/detecter/ngx_http_upstream_checker.c new file mode 100644 index 0000000..6cec650 --- /dev/null +++ b/src/detecter/ngx_http_upstream_checker.c @@ -0,0 +1,4071 @@ + + +#include +#include "ngx_http_upstream_check_module.h" + + +typedef struct ngx_http_upstream_check_peer_s ngx_http_upstream_check_peer_t; +typedef struct ngx_http_upstream_check_srv_conf_s + ngx_http_upstream_check_srv_conf_t; + + +#pragma pack(push, 1) + +typedef struct { + u_char major; + u_char minor; +} ngx_ssl_protocol_version_t; + + +typedef struct { + u_char msg_type; + ngx_ssl_protocol_version_t version; + uint16_t length; + + u_char handshake_type; + u_char handshake_length[3]; + ngx_ssl_protocol_version_t hello_version; + + time_t time; + u_char random[28]; + + u_char others[0]; +} ngx_ssl_server_hello_t; + + +typedef struct { + u_char packet_length[3]; + u_char packet_number; + + u_char protocol_version; + u_char others[0]; +} ngx_mysql_handshake_init_t; + + +typedef struct { + uint16_t preamble; + uint16_t length; + u_char type; +} ngx_ajp_raw_packet_t; + +#pragma pack() + + +typedef struct { + ngx_buf_t send; + ngx_buf_t recv; + + ngx_uint_t state; + ngx_http_status_t status; + + size_t padding; + size_t length; +} ngx_http_upstream_check_ctx_t; + + +typedef struct { + ngx_shmtx_t mutex; +#if (nginx_version >= 1002000) + ngx_shmtx_sh_t lock; +#else + ngx_atomic_t lock; +#endif + + ngx_pid_t owner; + + ngx_msec_t access_time; + + ngx_uint_t fall_count; + ngx_uint_t rise_count; + + ngx_uint_t busyness; + ngx_uint_t access_count; + + struct sockaddr *sockaddr; + socklen_t socklen; + + ngx_atomic_t down; + + u_char padding[64]; +} ngx_http_upstream_check_peer_shm_t; + + +typedef struct { + ngx_uint_t generation; + ngx_uint_t checksum; + ngx_uint_t number; + + /* ngx_http_upstream_check_status_peer_t */ + ngx_http_upstream_check_peer_shm_t peers[1]; +} ngx_http_upstream_check_peers_shm_t; + + +#define NGX_HTTP_CHECK_CONNECT_DONE 0x0001 +#define NGX_HTTP_CHECK_SEND_DONE 0x0002 +#define NGX_HTTP_CHECK_RECV_DONE 0x0004 +#define NGX_HTTP_CHECK_ALL_DONE 0x0008 + + +typedef ngx_int_t (*ngx_http_upstream_check_packet_init_pt) + (ngx_http_upstream_check_peer_t *peer); +typedef ngx_int_t (*ngx_http_upstream_check_packet_parse_pt) + (ngx_http_upstream_check_peer_t *peer); +typedef void (*ngx_http_upstream_check_packet_clean_pt) + (ngx_http_upstream_check_peer_t *peer); + +struct ngx_http_upstream_check_peer_s { + ngx_flag_t state; + ngx_pool_t *pool; + ngx_uint_t index; + ngx_uint_t max_busy; + ngx_str_t *upstream_name; + ngx_addr_t *check_peer_addr; + ngx_addr_t *peer_addr; + ngx_event_t check_ev; + ngx_event_t check_timeout_ev; + ngx_peer_connection_t pc; + + void *check_data; + ngx_event_handler_pt send_handler; + ngx_event_handler_pt recv_handler; + + ngx_http_upstream_check_packet_init_pt init; + ngx_http_upstream_check_packet_parse_pt parse; + ngx_http_upstream_check_packet_clean_pt reinit; + + ngx_http_upstream_check_peer_shm_t *shm; + ngx_http_upstream_check_srv_conf_t *conf; +}; + + +typedef struct { + ngx_str_t check_shm_name; + ngx_uint_t checksum; + ngx_array_t peers; + + ngx_http_upstream_check_peers_shm_t *peers_shm; +} ngx_http_upstream_check_peers_t; + + +#define NGX_HTTP_CHECK_TCP 0x0001 +#define NGX_HTTP_CHECK_HTTP 0x0002 +#define NGX_HTTP_CHECK_SSL_HELLO 0x0004 +#define NGX_HTTP_CHECK_MYSQL 0x0008 +#define NGX_HTTP_CHECK_AJP 0x0010 + +#define NGX_CHECK_HTTP_2XX 0x0002 +#define NGX_CHECK_HTTP_3XX 0x0004 +#define NGX_CHECK_HTTP_4XX 0x0008 +#define NGX_CHECK_HTTP_5XX 0x0010 +#define NGX_CHECK_HTTP_ERR 0x8000 + +typedef struct { + ngx_uint_t type; + + ngx_str_t name; + + ngx_str_t default_send; + + /* HTTP */ + ngx_uint_t default_status_alive; + + ngx_event_handler_pt send_handler; + ngx_event_handler_pt recv_handler; + + ngx_http_upstream_check_packet_init_pt init; + ngx_http_upstream_check_packet_parse_pt parse; + ngx_http_upstream_check_packet_clean_pt reinit; + + unsigned need_pool; + unsigned need_keepalive; +} ngx_check_conf_t; + + +typedef void (*ngx_http_upstream_check_status_format_pt) (ngx_buf_t *b, + ngx_http_upstream_check_peers_t *peers, ngx_uint_t flag); + +typedef struct { + ngx_str_t format; + ngx_str_t content_type; + + ngx_http_upstream_check_status_format_pt output; +} ngx_check_status_conf_t; + + +#define NGX_CHECK_STATUS_DOWN 0x0001 +#define NGX_CHECK_STATUS_UP 0x0002 + +typedef struct { + ngx_check_status_conf_t *format; + ngx_flag_t flag; +} ngx_http_upstream_check_status_ctx_t; + + +typedef ngx_int_t (*ngx_http_upstream_check_status_command_pt) + (ngx_http_upstream_check_status_ctx_t *ctx, ngx_str_t *value); + +typedef struct { + ngx_str_t name; + ngx_http_upstream_check_status_command_pt handler; +} ngx_check_status_command_t; + + +typedef struct { + ngx_uint_t check_shm_size; + ngx_http_upstream_check_peers_t *peers; +} ngx_http_upstream_check_main_conf_t; + + +struct ngx_http_upstream_check_srv_conf_s { + ngx_uint_t port; + ngx_uint_t fall_count; + ngx_uint_t rise_count; + ngx_msec_t check_interval; + ngx_msec_t check_timeout; + ngx_uint_t check_keepalive_requests; + + ngx_check_conf_t *check_type_conf; + ngx_str_t send; + + union { + ngx_uint_t return_code; + ngx_uint_t status_alive; + } code; + + ngx_array_t *fastcgi_params; + + ngx_uint_t default_down; +}; + + +typedef struct { + ngx_check_status_conf_t *format; +} ngx_http_upstream_check_loc_conf_t; + + +typedef struct { + u_char version; + u_char type; + u_char request_id_hi; + u_char request_id_lo; + u_char content_length_hi; + u_char content_length_lo; + u_char padding_length; + u_char reserved; +} ngx_http_fastcgi_header_t; + + +typedef struct { + u_char role_hi; + u_char role_lo; + u_char flags; + u_char reserved[5]; +} ngx_http_fastcgi_begin_request_t; + + +typedef struct { + u_char version; + u_char type; + u_char request_id_hi; + u_char request_id_lo; +} ngx_http_fastcgi_header_small_t; + + +typedef struct { + ngx_http_fastcgi_header_t h0; + ngx_http_fastcgi_begin_request_t br; + ngx_http_fastcgi_header_small_t h1; +} ngx_http_fastcgi_request_start_t; + + +#define NGX_HTTP_FASTCGI_RESPONDER 1 + +#define NGX_HTTP_FASTCGI_KEEP_CONN 1 + +#define NGX_HTTP_FASTCGI_BEGIN_REQUEST 1 +#define NGX_HTTP_FASTCGI_ABORT_REQUEST 2 +#define NGX_HTTP_FASTCGI_END_REQUEST 3 +#define NGX_HTTP_FASTCGI_PARAMS 4 +#define NGX_HTTP_FASTCGI_STDIN 5 +#define NGX_HTTP_FASTCGI_STDOUT 6 +#define NGX_HTTP_FASTCGI_STDERR 7 +#define NGX_HTTP_FASTCGI_DATA 8 + + +typedef enum { + ngx_http_fastcgi_st_version = 0, + ngx_http_fastcgi_st_type, + ngx_http_fastcgi_st_request_id_hi, + ngx_http_fastcgi_st_request_id_lo, + ngx_http_fastcgi_st_content_length_hi, + ngx_http_fastcgi_st_content_length_lo, + ngx_http_fastcgi_st_padding_length, + ngx_http_fastcgi_st_reserved, + ngx_http_fastcgi_st_data, + ngx_http_fastcgi_st_padding +} ngx_http_fastcgi_state_e; + + +static ngx_http_fastcgi_request_start_t ngx_http_fastcgi_request_start = { + { 1, /* version */ + NGX_HTTP_FASTCGI_BEGIN_REQUEST, /* type */ + 0, /* request_id_hi */ + 1, /* request_id_lo */ + 0, /* content_length_hi */ + sizeof(ngx_http_fastcgi_begin_request_t), /* content_length_lo */ + 0, /* padding_length */ + 0 }, /* reserved */ + + { 0, /* role_hi */ + NGX_HTTP_FASTCGI_RESPONDER, /* role_lo */ + 0, /* NGX_HTTP_FASTCGI_KEEP_CONN */ /* flags */ + { 0, 0, 0, 0, 0 } }, /* reserved[5] */ + + { 1, /* version */ + NGX_HTTP_FASTCGI_PARAMS, /* type */ + 0, /* request_id_hi */ + 1 }, /* request_id_lo */ + +}; + + +static ngx_int_t ngx_http_upstream_check_add_timers(ngx_cycle_t *cycle); + +static ngx_int_t ngx_http_upstream_check_peek_one_byte(ngx_connection_t *c); + +static void ngx_http_upstream_check_begin_handler(ngx_event_t *event); +static void ngx_http_upstream_check_connect_handler(ngx_event_t *event); + +static void ngx_http_upstream_check_peek_handler(ngx_event_t *event); + +static void ngx_http_upstream_check_send_handler(ngx_event_t *event); +static void ngx_http_upstream_check_recv_handler(ngx_event_t *event); + +static void ngx_http_upstream_check_discard_handler(ngx_event_t *event); +static void ngx_http_upstream_check_dummy_handler(ngx_event_t *event); + +static ngx_int_t ngx_http_upstream_check_http_init( + ngx_http_upstream_check_peer_t *peer); +static ngx_int_t ngx_http_upstream_check_http_parse( + ngx_http_upstream_check_peer_t *peer); +static ngx_int_t ngx_http_upstream_check_parse_status_line( + ngx_http_upstream_check_ctx_t *ctx, ngx_buf_t *b, + ngx_http_status_t *status); +static void ngx_http_upstream_check_http_reinit( + ngx_http_upstream_check_peer_t *peer); + +static ngx_buf_t *ngx_http_upstream_check_create_fastcgi_request( + ngx_pool_t *pool, ngx_str_t *params, ngx_uint_t num); + +static ngx_int_t ngx_http_upstream_check_fastcgi_parse( + ngx_http_upstream_check_peer_t *peer); +static ngx_int_t ngx_http_upstream_check_fastcgi_process_record( + ngx_http_upstream_check_ctx_t *ctx, ngx_buf_t *b, + ngx_http_status_t *status); +static ngx_int_t ngx_http_upstream_check_parse_fastcgi_status( + ngx_http_upstream_check_ctx_t *ctx, ngx_buf_t *b, + ngx_http_status_t *status); + +static ngx_int_t ngx_http_upstream_check_ssl_hello_init( + ngx_http_upstream_check_peer_t *peer); +static ngx_int_t ngx_http_upstream_check_ssl_hello_parse( + ngx_http_upstream_check_peer_t *peer); +static void ngx_http_upstream_check_ssl_hello_reinit( + ngx_http_upstream_check_peer_t *peer); + +static ngx_int_t ngx_http_upstream_check_mysql_init( + ngx_http_upstream_check_peer_t *peer); +static ngx_int_t ngx_http_upstream_check_mysql_parse( + ngx_http_upstream_check_peer_t *peer); +static void ngx_http_upstream_check_mysql_reinit( + ngx_http_upstream_check_peer_t *peer); + +static ngx_int_t ngx_http_upstream_check_ajp_init( + ngx_http_upstream_check_peer_t *peer); +static ngx_int_t ngx_http_upstream_check_ajp_parse( + ngx_http_upstream_check_peer_t *peer); +static void ngx_http_upstream_check_ajp_reinit( + ngx_http_upstream_check_peer_t *peer); + +static void ngx_http_upstream_check_status_update( + ngx_http_upstream_check_peer_t *peer, + ngx_int_t result); + +static void ngx_http_upstream_check_clean_event( + ngx_http_upstream_check_peer_t *peer); + +static void ngx_http_upstream_check_timeout_handler(ngx_event_t *event); +static void ngx_http_upstream_check_finish_handler(ngx_event_t *event); + +static ngx_int_t ngx_http_upstream_check_need_exit(); +static void ngx_http_upstream_check_clear_all_events(); + +static ngx_int_t ngx_http_upstream_check_status_handler( + ngx_http_request_t *r); + +static void ngx_http_upstream_check_status_parse_args(ngx_http_request_t *r, + ngx_http_upstream_check_status_ctx_t *ctx); + +static ngx_int_t ngx_http_upstream_check_status_command_format( + ngx_http_upstream_check_status_ctx_t *ctx, ngx_str_t *value); +static ngx_int_t ngx_http_upstream_check_status_command_status( + ngx_http_upstream_check_status_ctx_t *ctx, ngx_str_t *value); + +static void ngx_http_upstream_check_status_html_format(ngx_buf_t *b, + ngx_http_upstream_check_peers_t *peers, ngx_uint_t flag); +static void ngx_http_upstream_check_status_csv_format(ngx_buf_t *b, + ngx_http_upstream_check_peers_t *peers, ngx_uint_t flag); +static void ngx_http_upstream_check_status_json_format(ngx_buf_t *b, + ngx_http_upstream_check_peers_t *peers, ngx_uint_t flag); + +static ngx_int_t ngx_http_upstream_check_addr_change_port(ngx_pool_t *pool, + ngx_addr_t *dst, ngx_addr_t *src, ngx_uint_t port); + +static ngx_check_conf_t *ngx_http_get_check_type_conf(ngx_str_t *str); + +static char *ngx_http_upstream_check(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); +static char *ngx_http_upstream_check_keepalive_requests(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); +static char *ngx_http_upstream_check_http_send(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); +static char *ngx_http_upstream_check_http_expect_alive(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); + +static char *ngx_http_upstream_check_fastcgi_params(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); + +static char *ngx_http_upstream_check_shm_size(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); + +static ngx_check_status_conf_t *ngx_http_get_check_status_format_conf( + ngx_str_t *str); +static char *ngx_http_upstream_check_status(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); + +static void *ngx_http_upstream_check_create_main_conf(ngx_conf_t *cf); +static char *ngx_http_upstream_check_init_main_conf(ngx_conf_t *cf, + void *conf); + +static void *ngx_http_upstream_check_create_srv_conf(ngx_conf_t *cf); +static char *ngx_http_upstream_check_init_srv_conf(ngx_conf_t *cf, void *conf); + +static void *ngx_http_upstream_check_create_loc_conf(ngx_conf_t *cf); +static char * ngx_http_upstream_check_merge_loc_conf(ngx_conf_t *cf, + void *parent, void *child); + +#define SHM_NAME_LEN 256 + +static char *ngx_http_upstream_check_init_shm(ngx_conf_t *cf, void *conf); + +static ngx_int_t ngx_http_upstream_check_get_shm_name(ngx_str_t *shm_name, + ngx_pool_t *pool, ngx_uint_t generation); +static ngx_shm_zone_t *ngx_shared_memory_find(ngx_cycle_t *cycle, + ngx_str_t *name, void *tag); +static ngx_http_upstream_check_peer_shm_t * +ngx_http_upstream_check_find_shm_peer(ngx_http_upstream_check_peers_shm_t *peers_shm, + ngx_addr_t *addr); + +static ngx_int_t ngx_http_upstream_check_init_shm_peer( + ngx_http_upstream_check_peer_shm_t *peer_shm, + ngx_http_upstream_check_peer_shm_t *opeer_shm, + ngx_uint_t init_down, ngx_pool_t *pool, ngx_str_t *peer_name); + +static ngx_int_t ngx_http_upstream_check_init_shm_zone( + ngx_shm_zone_t *shm_zone, void *data); + + +static ngx_int_t ngx_http_upstream_check_init_process(ngx_cycle_t *cycle); + + +static ngx_conf_bitmask_t ngx_check_http_expect_alive_masks[] = { + { ngx_string("http_2xx"), NGX_CHECK_HTTP_2XX }, + { ngx_string("http_3xx"), NGX_CHECK_HTTP_3XX }, + { ngx_string("http_4xx"), NGX_CHECK_HTTP_4XX }, + { ngx_string("http_5xx"), NGX_CHECK_HTTP_5XX }, + { ngx_null_string, 0 } +}; + + +static ngx_command_t ngx_http_upstream_check_commands[] = { + + { ngx_string("check"), + NGX_HTTP_UPS_CONF|NGX_CONF_1MORE, + ngx_http_upstream_check, + 0, + 0, + NULL }, + + { ngx_string("check_keepalive_requests"), + NGX_HTTP_UPS_CONF|NGX_CONF_TAKE1, + ngx_http_upstream_check_keepalive_requests, + 0, + 0, + NULL }, + + { ngx_string("check_http_send"), + NGX_HTTP_UPS_CONF|NGX_CONF_TAKE1, + ngx_http_upstream_check_http_send, + 0, + 0, + NULL }, + + { ngx_string("check_http_expect_alive"), + NGX_HTTP_UPS_CONF|NGX_CONF_1MORE, + ngx_http_upstream_check_http_expect_alive, + 0, + 0, + NULL }, + + { ngx_string("check_fastcgi_param"), + NGX_HTTP_UPS_CONF|NGX_CONF_TAKE2, + ngx_http_upstream_check_fastcgi_params, + 0, + 0, + NULL }, + + { ngx_string("check_shm_size"), + NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, + ngx_http_upstream_check_shm_size, + 0, + 0, + NULL }, + + { ngx_string("check_status"), + NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1|NGX_CONF_NOARGS, + ngx_http_upstream_check_status, + 0, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_upstream_check_module_ctx = { + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ + + ngx_http_upstream_check_create_main_conf,/* create main configuration */ + ngx_http_upstream_check_init_main_conf, /* init main configuration */ + + ngx_http_upstream_check_create_srv_conf, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_upstream_check_create_loc_conf, /* create location configuration */ + ngx_http_upstream_check_merge_loc_conf /* merge location configuration */ +}; + + +ngx_module_t ngx_http_upstream_check_module = { + NGX_MODULE_V1, + &ngx_http_upstream_check_module_ctx, /* module context */ + ngx_http_upstream_check_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + ngx_http_upstream_check_init_process, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static ngx_str_t fastcgi_default_request; +static ngx_str_t fastcgi_default_params[] = { + ngx_string("REQUEST_METHOD"), ngx_string("GET"), + ngx_string("REQUEST_URI"), ngx_string("/"), + ngx_string("SCRIPT_FILENAME"), ngx_string("index.php"), +}; + + +#define NGX_SSL_RANDOM "NGX_HTTP_CHECK_SSL_HELLO\n\n\n\n" + +/* + * This is the SSLv3 CLIENT HELLO packet used in conjunction with the + * check type of ssl_hello to ensure that the remote server speaks SSL. + * + * Check RFC 2246 (TLSv1.0) sections A.3 and A.4 for details. + */ +static char sslv3_client_hello_pkt[] = { + "\x16" /* ContentType : 0x16 = Hanshake */ + "\x03\x01" /* ProtocolVersion : 0x0301 = TLSv1.0 */ + "\x00\x6f" /* ContentLength : 0x6f bytes after this one */ + "\x01" /* HanshakeType : 0x01 = CLIENT HELLO */ + "\x00\x00\x6b" /* HandshakeLength : 0x6b bytes after this one */ + "\x03\x03" /* Hello Version : 0x0303 = TLSv1.2 */ + "\x00\x00\x00\x00" /* Unix GMT Time (s) : filled with (@0x0B) */ + NGX_SSL_RANDOM /* Random : must be exactly 28 bytes */ + "\x00" /* Session ID length : empty (no session ID) */ + "\x00\x1a" /* Cipher Suite Length : \x1a bytes after this one */ + "\xc0\x2b" "\xc0\x2f" "\xcc\xa9" "\xcc\xa8" /* 13 modern ciphers */ + "\xc0\x0a" "\xc0\x09" "\xc0\x13" "\xc0\x14" + "\x00\x33" "\x00\x39" "\x00\x2f" "\x00\x35" + "\x00\x0a" + "\x01" /* Compression Length : 0x01 = 1 byte for types */ + "\x00" /* Compression Type : 0x00 = NULL compression */ + "\x00\x28" /* Extensions length */ + "\x00\x0a" /* EC extension */ + "\x00\x08" /* extension length */ + "\x00\x06" /* curves length */ + "\x00\x17" "\x00\x18" "\x00\x19" /* Three curves */ + "\x00\x0d" /* Signature extension */ + "\x00\x18" /* extension length */ + "\x00\x16" /* hash list length */ + "\x04\x01" "\x05\x01" "\x06\x01" "\x02\x01" /* 11 hash algorithms */ + "\x04\x03" "\x05\x03" "\x06\x03" "\x02\x03" + "\x05\x02" "\x04\x02" "\x02\x02" +}; + + +#define NGX_SSL_HANDSHAKE 0x16 +#define NGX_SSL_SERVER_HELLO 0x02 + + +#define NGX_AJP_CPING 0x0a +#define NGX_AJP_CPONG 0x09 + + +static char ngx_ajp_cping_packet[] = { + 0x12, 0x34, 0x00, 0x01, NGX_AJP_CPING, 0x00 +}; + +static char ngx_ajp_cpong_packet[] = { + 0x41, 0x42, 0x00, 0x01, NGX_AJP_CPONG +}; + + +static ngx_check_conf_t ngx_check_types[] = { + + { NGX_HTTP_CHECK_TCP, + ngx_string("tcp"), + ngx_null_string, + 0, + ngx_http_upstream_check_peek_handler, + ngx_http_upstream_check_peek_handler, + NULL, + NULL, + NULL, + 0, + 1 }, + + { NGX_HTTP_CHECK_HTTP, + ngx_string("http"), + ngx_string("GET / HTTP/1.0\r\n\r\n"), + NGX_CONF_BITMASK_SET | NGX_CHECK_HTTP_2XX | NGX_CHECK_HTTP_3XX, + ngx_http_upstream_check_send_handler, + ngx_http_upstream_check_recv_handler, + ngx_http_upstream_check_http_init, + ngx_http_upstream_check_http_parse, + ngx_http_upstream_check_http_reinit, + 1, + 1 }, + + { NGX_HTTP_CHECK_HTTP, + ngx_string("fastcgi"), + ngx_null_string, + 0, + ngx_http_upstream_check_send_handler, + ngx_http_upstream_check_recv_handler, + ngx_http_upstream_check_http_init, + ngx_http_upstream_check_fastcgi_parse, + ngx_http_upstream_check_http_reinit, + 1, + 0 }, + + { NGX_HTTP_CHECK_SSL_HELLO, + ngx_string("ssl_hello"), + ngx_string(sslv3_client_hello_pkt), + 0, + ngx_http_upstream_check_send_handler, + ngx_http_upstream_check_recv_handler, + ngx_http_upstream_check_ssl_hello_init, + ngx_http_upstream_check_ssl_hello_parse, + ngx_http_upstream_check_ssl_hello_reinit, + 1, + 0 }, + + { NGX_HTTP_CHECK_MYSQL, + ngx_string("mysql"), + ngx_null_string, + 0, + ngx_http_upstream_check_send_handler, + ngx_http_upstream_check_recv_handler, + ngx_http_upstream_check_mysql_init, + ngx_http_upstream_check_mysql_parse, + ngx_http_upstream_check_mysql_reinit, + 1, + 0 }, + + { NGX_HTTP_CHECK_AJP, + ngx_string("ajp"), + ngx_string(ngx_ajp_cping_packet), + 0, + ngx_http_upstream_check_send_handler, + ngx_http_upstream_check_recv_handler, + ngx_http_upstream_check_ajp_init, + ngx_http_upstream_check_ajp_parse, + ngx_http_upstream_check_ajp_reinit, + 1, + 0 }, + + { 0, + ngx_null_string, + ngx_null_string, + 0, + NULL, + NULL, + NULL, + NULL, + NULL, + 0, + 0 } +}; + + +static ngx_check_status_conf_t ngx_check_status_formats[] = { + + { ngx_string("html"), + ngx_string("text/html"), + ngx_http_upstream_check_status_html_format }, + + { ngx_string("csv"), + ngx_string("text/plain"), + ngx_http_upstream_check_status_csv_format }, + + { ngx_string("json"), + ngx_string("application/json"), /* RFC 4627 */ + ngx_http_upstream_check_status_json_format }, + + { ngx_null_string, ngx_null_string, NULL } +}; + + +static ngx_check_status_command_t ngx_check_status_commands[] = { + + { ngx_string("format"), + ngx_http_upstream_check_status_command_format }, + + { ngx_string("status"), + ngx_http_upstream_check_status_command_status }, + + { ngx_null_string, NULL } +}; + + +static ngx_uint_t ngx_http_upstream_check_shm_generation = 0; +static ngx_http_upstream_check_peers_t *check_peers_ctx = NULL; + + +ngx_uint_t +ngx_http_upstream_check_add_peer(ngx_conf_t *cf, + ngx_http_upstream_srv_conf_t *us, ngx_addr_t *peer_addr) +{ + ngx_http_upstream_check_peer_t *peer; + ngx_http_upstream_check_peers_t *peers; + ngx_http_upstream_check_srv_conf_t *ucscf; + ngx_http_upstream_check_main_conf_t *ucmcf; + + if (us->srv_conf == NULL) { + return NGX_ERROR; + } + + ucscf = ngx_http_conf_upstream_srv_conf(us, ngx_http_upstream_check_module); + + if(ucscf->check_interval == 0) { + return NGX_ERROR; + } + + ucmcf = ngx_http_conf_get_module_main_conf(cf, + ngx_http_upstream_check_module); + peers = ucmcf->peers; + + peer = ngx_array_push(&peers->peers); + if (peer == NULL) { + return NGX_ERROR; + } + + ngx_memzero(peer, sizeof(ngx_http_upstream_check_peer_t)); + + peer->index = peers->peers.nelts - 1; + peer->conf = ucscf; + peer->upstream_name = &us->host; + peer->peer_addr = peer_addr; + + if (ucscf->port) { + peer->check_peer_addr = ngx_pcalloc(cf->pool, sizeof(ngx_addr_t)); + if (peer->check_peer_addr == NULL) { + return NGX_ERROR; + } + + if (ngx_http_upstream_check_addr_change_port(cf->pool, + peer->check_peer_addr, peer_addr, ucscf->port) + != NGX_OK) { + + return NGX_ERROR; + } + + } else { + peer->check_peer_addr = peer->peer_addr; + } + + peers->checksum += + ngx_murmur_hash2(peer_addr->name.data, peer_addr->name.len); + + return peer->index; +} + + +static ngx_int_t +ngx_http_upstream_check_addr_change_port(ngx_pool_t *pool, ngx_addr_t *dst, + ngx_addr_t *src, ngx_uint_t port) +{ + size_t len; + u_char *p; + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif + + dst->socklen = src->socklen; + dst->sockaddr = ngx_palloc(pool, dst->socklen); + if (dst->sockaddr == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(dst->sockaddr, src->sockaddr, dst->socklen); + + switch (dst->sockaddr->sa_family) { + + case AF_INET: + + len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1; + sin = (struct sockaddr_in *) dst->sockaddr; + sin->sin_port = htons(port); + + break; + +#if (NGX_HAVE_INET6) + case AF_INET6: + + len = NGX_INET6_ADDRSTRLEN + sizeof(":65535") - 1; + sin6 = (struct sockaddr_in6 *) dst->sockaddr; + sin6->sin6_port = htons(port); + + break; +#endif + + default: + return NGX_ERROR; + } + + p = ngx_pnalloc(pool, len); + if (p == NULL) { + return NGX_ERROR; + } + +#if (nginx_version >= 1005012) + len = ngx_sock_ntop(dst->sockaddr, dst->socklen, p, len, 1); +#else + len = ngx_sock_ntop(dst->sockaddr, p, len, 1); +#endif + + dst->name.len = len; + dst->name.data = p; + + return NGX_OK; +} + + +ngx_uint_t +ngx_http_upstream_check_peer_down(ngx_uint_t index) +{ + ngx_http_upstream_check_peer_t *peer; + + if (check_peers_ctx == NULL || index >= check_peers_ctx->peers.nelts) { + return 0; + } + + peer = check_peers_ctx->peers.elts; + + return (peer[index].shm->down); +} + + +/* TODO: this interface can count each peer's busyness */ +void +ngx_http_upstream_check_get_peer(ngx_uint_t index) +{ + ngx_http_upstream_check_peer_t *peer; + + if (check_peers_ctx == NULL || index >= check_peers_ctx->peers.nelts) { + return; + } + + peer = check_peers_ctx->peers.elts; + + ngx_shmtx_lock(&peer[index].shm->mutex); + + peer[index].shm->busyness++; + peer[index].shm->access_count++; + + ngx_shmtx_unlock(&peer[index].shm->mutex); +} + + +void +ngx_http_upstream_check_free_peer(ngx_uint_t index) +{ + ngx_http_upstream_check_peer_t *peer; + + if (check_peers_ctx == NULL || index >= check_peers_ctx->peers.nelts) { + return; + } + + peer = check_peers_ctx->peers.elts; + + ngx_shmtx_lock(&peer[index].shm->mutex); + + if (peer[index].shm->busyness > 0) { + peer[index].shm->busyness--; + } + + ngx_shmtx_unlock(&peer[index].shm->mutex); +} + + +static ngx_int_t +ngx_http_upstream_check_add_timers(ngx_cycle_t *cycle) +{ + ngx_uint_t i; + ngx_msec_t t, delay; + ngx_check_conf_t *cf; + ngx_http_upstream_check_peer_t *peer; + ngx_http_upstream_check_peers_t *peers; + ngx_http_upstream_check_srv_conf_t *ucscf; + ngx_http_upstream_check_peer_shm_t *peer_shm; + ngx_http_upstream_check_peers_shm_t *peers_shm; + + peers = check_peers_ctx; + if (peers == NULL) { + return NGX_OK; + } + + peers_shm = peers->peers_shm; + if (peers_shm == NULL) { + return NGX_OK; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cycle->log, 0, + "http check upstream init_process, shm_name: %V, " + "peer number: %ud", + &peers->check_shm_name, + peers->peers.nelts); + + srandom(ngx_pid); + + peer = peers->peers.elts; + peer_shm = peers_shm->peers; + + for (i = 0; i < peers->peers.nelts; i++) { + peer[i].shm = &peer_shm[i]; + + peer[i].check_ev.handler = ngx_http_upstream_check_begin_handler; + peer[i].check_ev.log = cycle->log; + peer[i].check_ev.data = &peer[i]; + peer[i].check_ev.timer_set = 0; + + peer[i].check_timeout_ev.handler = + ngx_http_upstream_check_timeout_handler; + peer[i].check_timeout_ev.log = cycle->log; + peer[i].check_timeout_ev.data = &peer[i]; + peer[i].check_timeout_ev.timer_set = 0; + + ucscf = peer[i].conf; + cf = ucscf->check_type_conf; + + if (cf->need_pool) { + peer[i].pool = ngx_create_pool(ngx_pagesize, cycle->log); + if (peer[i].pool == NULL) { + return NGX_ERROR; + } + } + + peer[i].send_handler = cf->send_handler; + peer[i].recv_handler = cf->recv_handler; + + peer[i].init = cf->init; + peer[i].parse = cf->parse; + peer[i].reinit = cf->reinit; + + /* + * We add a random start time here, since we don't want to trigger + * the check events too close to each other at the beginning. + */ + delay = ucscf->check_interval > 1000 ? ucscf->check_interval : 1000; + t = ngx_random() % delay; + + ngx_add_timer(&peer[i].check_ev, t); + } + + return NGX_OK; +} + + +static void +ngx_http_upstream_check_begin_handler(ngx_event_t *event) +{ + ngx_msec_t interval; + ngx_http_upstream_check_peer_t *peer; + ngx_http_upstream_check_peers_t *peers; + ngx_http_upstream_check_srv_conf_t *ucscf; + ngx_http_upstream_check_peers_shm_t *peers_shm; + + if (ngx_http_upstream_check_need_exit()) { + return; + } + + peers = check_peers_ctx; + if (peers == NULL) { + return; + } + + peers_shm = peers->peers_shm; + if (peers_shm == NULL) { + return; + } + + peer = event->data; + ucscf = peer->conf; + + ngx_add_timer(event, ucscf->check_interval / 2); + + /* This process is processing this peer now. */ + if ((peer->shm->owner == ngx_pid || + (peer->pc.connection != NULL) || + peer->check_timeout_ev.timer_set)) { + return; + } + + interval = ngx_current_msec - peer->shm->access_time; + ngx_log_debug5(NGX_LOG_DEBUG_HTTP, event->log, 0, + "http check begin handler index: %ui, owner: %P, " + "ngx_pid: %P, interval: %M, check_interval: %M", + peer->index, peer->shm->owner, + ngx_pid, interval, + ucscf->check_interval); + + ngx_shmtx_lock(&peer->shm->mutex); + + if (peers_shm->generation != ngx_http_upstream_check_shm_generation) { + ngx_shmtx_unlock(&peer->shm->mutex); + return; + } + + if ((interval >= ucscf->check_interval) + && (peer->shm->owner == NGX_INVALID_PID)) + { + peer->shm->owner = ngx_pid; + + } else if (interval >= (ucscf->check_interval << 4)) { + + /* + * If the check peer has been untouched for 2^4 times of + * the check interval, activate the current timer. + * Sometimes, the checking process may disappear + * in some circumstances, and the clean event will never + * be triggered. + */ + peer->shm->owner = ngx_pid; + peer->shm->access_time = ngx_current_msec; + } + + ngx_shmtx_unlock(&peer->shm->mutex); + + if (peer->shm->owner == ngx_pid) { + ngx_http_upstream_check_connect_handler(event); + } +} + + +static void +ngx_http_upstream_check_connect_handler(ngx_event_t *event) +{ + ngx_int_t rc; + ngx_connection_t *c; + ngx_http_upstream_check_peer_t *peer; + ngx_http_upstream_check_srv_conf_t *ucscf; + + if (ngx_http_upstream_check_need_exit()) { + return; + } + + peer = event->data; + ucscf = peer->conf; + + if (peer->pc.connection != NULL) { + c = peer->pc.connection; + if ((rc = ngx_http_upstream_check_peek_one_byte(c)) == NGX_OK) { + goto upstream_check_connect_done; + } else { + ngx_close_connection(c); + peer->pc.connection = NULL; + } + } + ngx_memzero(&peer->pc, sizeof(ngx_peer_connection_t)); + + peer->pc.sockaddr = peer->check_peer_addr->sockaddr; + peer->pc.socklen = peer->check_peer_addr->socklen; + peer->pc.name = &peer->check_peer_addr->name; + + peer->pc.get = ngx_event_get_peer; + peer->pc.log = event->log; + peer->pc.log_error = NGX_ERROR_ERR; + + peer->pc.cached = 0; + peer->pc.connection = NULL; + + rc = ngx_event_connect_peer(&peer->pc); + + if (rc == NGX_ERROR || rc == NGX_DECLINED) { + ngx_http_upstream_check_status_update(peer, 0); + ngx_http_upstream_check_clean_event(peer); + return; + } + + /* NGX_OK or NGX_AGAIN */ + c = peer->pc.connection; + c->data = peer; + c->log = peer->pc.log; + c->sendfile = 0; + c->read->log = c->log; + c->write->log = c->log; + c->pool = peer->pool; + +upstream_check_connect_done: + peer->state = NGX_HTTP_CHECK_CONNECT_DONE; + + c->write->handler = peer->send_handler; + c->read->handler = peer->recv_handler; + + ngx_add_timer(&peer->check_timeout_ev, ucscf->check_timeout); + + /* The kqueue's loop interface needs it. */ + if (rc == NGX_OK) { + c->write->handler(c->write); + } +} + +static ngx_int_t +ngx_http_upstream_check_peek_one_byte(ngx_connection_t *c) +{ + char buf[1]; + ngx_int_t n; + ngx_err_t err; + + n = recv(c->fd, buf, 1, MSG_PEEK); + err = ngx_socket_errno; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, err, + "http check upstream recv(): %i, fd: %d", + n, c->fd); + + if (n == 1 || (n == -1 && err == NGX_EAGAIN)) { + return NGX_OK; + } else { + return NGX_ERROR; + } +} + +static void +ngx_http_upstream_check_peek_handler(ngx_event_t *event) +{ + ngx_connection_t *c; + ngx_http_upstream_check_peer_t *peer; + + if (ngx_http_upstream_check_need_exit()) { + return; + } + + c = event->data; + peer = c->data; + + if (ngx_http_upstream_check_peek_one_byte(c) == NGX_OK) { + ngx_http_upstream_check_status_update(peer, 1); + + } else { + c->error = 1; + ngx_http_upstream_check_status_update(peer, 0); + } + + ngx_http_upstream_check_clean_event(peer); + + ngx_http_upstream_check_finish_handler(event); +} + + +static void +ngx_http_upstream_check_discard_handler(ngx_event_t *event) +{ + u_char buf[4096]; + ssize_t size; + ngx_connection_t *c; + ngx_http_upstream_check_peer_t *peer; + + c = event->data; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "upstream check discard handler"); + + if (ngx_http_upstream_check_need_exit()) { + return; + } + + peer = c->data; + + while (1) { + size = c->recv(c, buf, 4096); + + if (size > 0) { + continue; + + } else if (size == NGX_AGAIN) { + break; + + } else { + if (size == 0) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "peer closed its half side of the connection"); + } + + goto check_discard_fail; + } + } + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + goto check_discard_fail; + } + + return; + + check_discard_fail: + c->error = 1; + ngx_http_upstream_check_clean_event(peer); +} + + +static void +ngx_http_upstream_check_dummy_handler(ngx_event_t *event) +{ + return; +} + + +static void +ngx_http_upstream_check_send_handler(ngx_event_t *event) +{ + ssize_t size; + ngx_connection_t *c; + ngx_http_upstream_check_ctx_t *ctx; + ngx_http_upstream_check_peer_t *peer; + + if (ngx_http_upstream_check_need_exit()) { + return; + } + + c = event->data; + peer = c->data; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http check send."); + + if (c->pool == NULL) { + ngx_log_error(NGX_LOG_ERR, event->log, 0, + "check pool NULL with peer: %V ", + &peer->check_peer_addr->name); + + goto check_send_fail; + } + + if (peer->state != NGX_HTTP_CHECK_CONNECT_DONE) { + if (ngx_handle_write_event(c->write, 0) != NGX_OK) { + + ngx_log_error(NGX_LOG_ERR, event->log, 0, + "check handle write event error with peer: %V ", + &peer->check_peer_addr->name); + + goto check_send_fail; + } + + return; + } + + if (peer->check_data == NULL) { + + peer->check_data = ngx_pcalloc(peer->pool, + sizeof(ngx_http_upstream_check_ctx_t)); + if (peer->check_data == NULL) { + goto check_send_fail; + } + + if (peer->init == NULL || peer->init(peer) != NGX_OK) { + + ngx_log_error(NGX_LOG_ERR, event->log, 0, + "check init error with peer: %V ", + &peer->check_peer_addr->name); + + goto check_send_fail; + } + } + + ctx = peer->check_data; + + while (ctx->send.pos < ctx->send.last) { + + size = c->send(c, ctx->send.pos, ctx->send.last - ctx->send.pos); + +#if (NGX_DEBUG) + { + ngx_err_t err; + + err = (size >=0) ? 0 : ngx_socket_errno; + ngx_log_error(NGX_LOG_DEBUG, ngx_cycle->log, err, + "http check send size: %z, total: %z", + size, ctx->send.last - ctx->send.pos); + } +#endif + + if (size > 0) { + ctx->send.pos += size; + } else if (size == 0 || size == NGX_AGAIN) { + return; + } else { + c->error = 1; + goto check_send_fail; + } + } + + if (ctx->send.pos == ctx->send.last) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http check send done."); + peer->state = NGX_HTTP_CHECK_SEND_DONE; + c->requests++; + } + + return; + +check_send_fail: + ngx_http_upstream_check_status_update(peer, 0); + ngx_http_upstream_check_clean_event(peer); +} + + +static void +ngx_http_upstream_check_recv_handler(ngx_event_t *event) +{ + u_char *new_buf; + ssize_t size, n; + ngx_int_t rc; + ngx_connection_t *c; + ngx_http_upstream_check_ctx_t *ctx; + ngx_http_upstream_check_peer_t *peer; + + if (ngx_http_upstream_check_need_exit()) { + return; + } + + c = event->data; + peer = c->data; + + if (peer->state != NGX_HTTP_CHECK_SEND_DONE) { + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + goto check_recv_fail; + } + + return; + } + + ctx = peer->check_data; + + if (ctx->recv.start == NULL) { + /* 1/2 of the page_size, is it enough? */ + ctx->recv.start = ngx_palloc(c->pool, ngx_pagesize / 2); + if (ctx->recv.start == NULL) { + goto check_recv_fail; + } + + ctx->recv.last = ctx->recv.pos = ctx->recv.start; + ctx->recv.end = ctx->recv.start + ngx_pagesize / 2; + } + + while (1) { + n = ctx->recv.end - ctx->recv.last; + + /* buffer not big enough? enlarge it by twice */ + if (n == 0) { + size = ctx->recv.end - ctx->recv.start; + new_buf = ngx_palloc(c->pool, size * 2); + if (new_buf == NULL) { + goto check_recv_fail; + } + + ngx_memcpy(new_buf, ctx->recv.start, size); + + ctx->recv.pos = ctx->recv.start = new_buf; + ctx->recv.last = new_buf + size; + ctx->recv.end = new_buf + size * 2; + + n = ctx->recv.end - ctx->recv.last; + } + + size = c->recv(c, ctx->recv.last, n); + +#if (NGX_DEBUG) + { + ngx_err_t err; + + err = (size >= 0) ? 0 : ngx_socket_errno; + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, err, + "http check recv size: %z, peer: %V ", + size, &peer->check_peer_addr->name); + } +#endif + + if (size > 0) { + ctx->recv.last += size; + continue; + } else if (size == 0 || size == NGX_AGAIN) { + break; + } else { + c->error = 1; + goto check_recv_fail; + } + } + + rc = peer->parse(peer); + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http check parse rc: %i, peer: %V ", + rc, &peer->check_peer_addr->name); + + switch (rc) { + + case NGX_AGAIN: + /* The peer has closed its half side of the connection. */ + if (size == 0) { + ngx_http_upstream_check_status_update(peer, 0); + c->error = 1; + break; + } + + return; + + case NGX_ERROR: + ngx_log_error(NGX_LOG_ERR, event->log, 0, + "check protocol %V error with peer: %V ", + &peer->conf->check_type_conf->name, + &peer->check_peer_addr->name); + + ngx_http_upstream_check_status_update(peer, 0); + break; + + case NGX_OK: + /* fall through */ + + default: + ngx_http_upstream_check_status_update(peer, 1); + break; + } + + peer->state = NGX_HTTP_CHECK_RECV_DONE; + ngx_http_upstream_check_clean_event(peer); + return; + +check_recv_fail: + ngx_http_upstream_check_status_update(peer, 0); + ngx_http_upstream_check_clean_event(peer); +} + + +static ngx_int_t +ngx_http_upstream_check_http_init(ngx_http_upstream_check_peer_t *peer) +{ + ngx_http_upstream_check_ctx_t *ctx; + ngx_http_upstream_check_srv_conf_t *ucscf; + + ctx = peer->check_data; + ucscf = peer->conf; + + ctx->send.start = ctx->send.pos = (u_char *)ucscf->send.data; + ctx->send.end = ctx->send.last = ctx->send.start + ucscf->send.len; + + ctx->recv.start = ctx->recv.pos = NULL; + ctx->recv.end = ctx->recv.last = NULL; + + ctx->state = 0; + + ngx_memzero(&ctx->status, sizeof(ngx_http_status_t)); + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_check_http_parse(ngx_http_upstream_check_peer_t *peer) +{ + ngx_int_t rc; + ngx_uint_t code, code_n; + ngx_http_upstream_check_ctx_t *ctx; + ngx_http_upstream_check_srv_conf_t *ucscf; + + ucscf = peer->conf; + ctx = peer->check_data; + + if ((ctx->recv.last - ctx->recv.pos) > 0) { + + rc = ngx_http_upstream_check_parse_status_line(ctx, + &ctx->recv, + &ctx->status); + if (rc == NGX_AGAIN) { + return rc; + } + + if (rc == NGX_ERROR) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "http parse status line error with peer: %V ", + &peer->check_peer_addr->name); + return rc; + } + + code = ctx->status.code; + + if (code >= 200 && code < 300) { + code_n = NGX_CHECK_HTTP_2XX; + } else if (code >= 300 && code < 400) { + code_n = NGX_CHECK_HTTP_3XX; + } else if (code >= 400 && code < 500) { + peer->pc.connection->error = 1; + code_n = NGX_CHECK_HTTP_4XX; + } else if (code >= 500 && code < 600) { + peer->pc.connection->error = 1; + code_n = NGX_CHECK_HTTP_5XX; + } else { + peer->pc.connection->error = 1; + code_n = NGX_CHECK_HTTP_ERR; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "http_parse: code_n: %ui, conf: %ui", + code_n, ucscf->code.status_alive); + + if (code_n & ucscf->code.status_alive) { + return NGX_OK; + } else { + return NGX_ERROR; + } + } else { + return NGX_AGAIN; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_check_fastcgi_process_record( + ngx_http_upstream_check_ctx_t *ctx, ngx_buf_t *b, ngx_http_status_t *status) +{ + u_char ch, *p; + ngx_http_fastcgi_state_e state; + + state = ctx->state; + + for (p = b->pos; p < b->last; p++) { + + ch = *p; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "http fastcgi record byte: %02Xd", ch); + + switch (state) { + + case ngx_http_fastcgi_st_version: + if (ch != 1) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "upstream sent unsupported FastCGI " + "protocol version: %d", ch); + return NGX_ERROR; + } + state = ngx_http_fastcgi_st_type; + break; + + case ngx_http_fastcgi_st_type: + switch (ch) { + case NGX_HTTP_FASTCGI_STDOUT: + case NGX_HTTP_FASTCGI_STDERR: + case NGX_HTTP_FASTCGI_END_REQUEST: + status->code = (ngx_uint_t) ch; + break; + default: + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "upstream sent invalid FastCGI " + "record type: %d", ch); + return NGX_ERROR; + + } + state = ngx_http_fastcgi_st_request_id_hi; + break; + + /* we support the single request per connection */ + + case ngx_http_fastcgi_st_request_id_hi: + if (ch != 0) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "upstream sent unexpected FastCGI " + "request id high byte: %d", ch); + return NGX_ERROR; + } + state = ngx_http_fastcgi_st_request_id_lo; + break; + + case ngx_http_fastcgi_st_request_id_lo: + if (ch != 1) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "upstream sent unexpected FastCGI " + "request id low byte: %d", ch); + return NGX_ERROR; + } + state = ngx_http_fastcgi_st_content_length_hi; + break; + + case ngx_http_fastcgi_st_content_length_hi: + ctx->length = ch << 8; + state = ngx_http_fastcgi_st_content_length_lo; + break; + + case ngx_http_fastcgi_st_content_length_lo: + ctx->length |= (size_t) ch; + state = ngx_http_fastcgi_st_padding_length; + break; + + case ngx_http_fastcgi_st_padding_length: + ctx->padding = (size_t) ch; + state = ngx_http_fastcgi_st_reserved; + break; + + case ngx_http_fastcgi_st_reserved: + state = ngx_http_fastcgi_st_data; + + b->pos = p + 1; + ctx->state = state; + + return NGX_OK; + + /* suppress warning */ + case ngx_http_fastcgi_st_data: + case ngx_http_fastcgi_st_padding: + break; + } + } + + ctx->state = state; + + return NGX_AGAIN; +} + + +static ngx_int_t +ngx_http_upstream_check_fastcgi_parse(ngx_http_upstream_check_peer_t *peer) +{ + ngx_int_t rc; + ngx_flag_t done; + ngx_uint_t type, code, code_n; + ngx_http_upstream_check_ctx_t *ctx; + ngx_http_upstream_check_srv_conf_t *ucscf; + + ucscf = peer->conf; + ctx = peer->check_data; + + if ((ctx->recv.last - ctx->recv.pos) <= 0) { + return NGX_AGAIN; + } + + done = 0; + + for ( ;; ) { + + if (ctx->state < ngx_http_fastcgi_st_data) { + rc = ngx_http_upstream_check_fastcgi_process_record(ctx, + &ctx->recv, &ctx->status); + + type = ctx->status.code; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "fastcgi_parse rc: [%i], type: [%ui]", rc, type); + + if (rc == NGX_AGAIN) { + return rc; + } + + if (rc == NGX_ERROR) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "check fastcgi parse status line error with peer: %V", + &peer->check_peer_addr->name); + + return rc; + } + + if (type != NGX_HTTP_FASTCGI_STDOUT + && type != NGX_HTTP_FASTCGI_STDERR) + { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "check fastcgi sent unexpected FastCGI record: %d", type); + + return NGX_ERROR; + } + + if (type == NGX_HTTP_FASTCGI_STDOUT && ctx->length == 0) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "check fastcgi prematurely closed FastCGI stdout"); + + return NGX_ERROR; + } + } + + if (ctx->state == ngx_http_fastcgi_st_padding) { + + if (ctx->recv.pos + ctx->padding < ctx->recv.last) { + ctx->status.code = ngx_http_fastcgi_st_version; + ctx->recv.pos += ctx->padding; + + continue; + } + + if (ctx->recv.pos + ctx->padding == ctx->recv.last) { + ctx->status.code = ngx_http_fastcgi_st_version; + ctx->recv.pos = ctx->recv.last; + + return NGX_AGAIN; + } + + ctx->padding -= ctx->recv.last - ctx->recv.pos; + ctx->recv.pos = ctx->recv.last; + + return NGX_AGAIN; + } + + if (ctx->status.code == NGX_HTTP_FASTCGI_STDERR) { + + ngx_log_error(NGX_LOG_WARN, ngx_cycle->log, 0, + "fastcgi check error"); + + return NGX_ERROR; + } + + /* ctx->status.code == NGX_HTTP_FASTCGI_STDOUT */ + + if (ctx->recv.pos + ctx->length < ctx->recv.last) { + ctx->recv.last = ctx->recv.pos + ctx->length; + } else { + return NGX_ERROR; + } + + ctx->status.code = 0; + + for ( ;; ) { + rc = ngx_http_upstream_check_parse_fastcgi_status(ctx, + &ctx->recv, + &ctx->status); + ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0, + "fastcgi http parse status line rc: %i ", rc); + + if (rc == NGX_ERROR) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "fastcgi http parse status line error with peer: %V ", + &peer->check_peer_addr->name); + return NGX_ERROR; + } + + if (rc == NGX_AGAIN) { + break; + } + + if (rc == NGX_DONE) { + done = 1; + ngx_log_error(NGX_LOG_DEBUG, ngx_cycle->log, 0, + "fastcgi http parse status: %i", + ctx->status.code); + break; + } + + /* rc = NGX_OK */ + } + + if (ucscf->code.status_alive == 0 || done == 0) { + return NGX_OK; + } + + code = ctx->status.code; + + if (code >= 200 && code < 300) { + code_n = NGX_CHECK_HTTP_2XX; + } else if (code >= 300 && code < 400) { + code_n = NGX_CHECK_HTTP_3XX; + } else if (code >= 400 && code < 500) { + code_n = NGX_CHECK_HTTP_4XX; + } else if (code >= 500 && code < 600) { + code_n = NGX_CHECK_HTTP_5XX; + } else { + code_n = NGX_CHECK_HTTP_ERR; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "fastcgi http_parse: code_n: %ui, conf: %ui", + code_n, ucscf->code.status_alive); + + if (code_n & ucscf->code.status_alive) { + return NGX_OK; + } else { + return NGX_ERROR; + } + + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_check_parse_fastcgi_status(ngx_http_upstream_check_ctx_t *ctx, + ngx_buf_t *b, ngx_http_status_t *status) +{ + u_char c, ch, *p, *name_s, *name_e; + ngx_flag_t find; + + enum { + sw_start = 0, + sw_name, + sw_space_before_value, + sw_value, + sw_space_after_value, + sw_ignore_line, + sw_almost_done, + sw_header_almost_done + } state; + + /* the last '\0' is not needed because string is zero terminated */ + + static u_char lowcase[] = + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0-\0\0" "0123456789\0\0\0\0\0\0" + "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0\0" + "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; + + status->count = 0; + status->code = 0; + find = 0; + name_s = name_e = NULL; + state = sw_start; + + for (p = b->pos; p < b->last; p++) { + ch = *p; + + switch (state) { + + /* first char */ + case sw_start: + + switch (ch) { + case CR: + state = sw_header_almost_done; + break; + case LF: + goto header_done; + default: + state = sw_name; + + c = lowcase[ch]; + + if (c) { + name_s = p; + break; + } + + if (ch == '\0') { + return NGX_ERROR; + } + + + break; + } + + break; + + /* header name */ + case sw_name: + c = lowcase[ch]; + + if (c) { + break; + } + + if (ch == ':') { + name_e = p; +#if (NGX_DEBUG) + ngx_str_t name; + name.data = name_s; + name.len = name_e - name_s; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "fastcgi header: %V", &name); +#endif + state = sw_space_before_value; + + if (ngx_strncasecmp(name_s, (u_char *) "status", + name_e - name_s) + == 0) + { + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "find status header"); + + find = 1; + } + + break; + } + + if (ch == CR) { + state = sw_almost_done; + break; + } + + if (ch == LF) { + goto done; + } + + /* IIS may send the duplicate "HTTP/1.1 ..." lines */ + if (ch == '\0') { + return NGX_ERROR; + } + + break; + + /* space* before header value */ + case sw_space_before_value: + switch (ch) { + case ' ': + break; + case CR: + state = sw_almost_done; + break; + case LF: + goto done; + case '\0': + return NGX_ERROR; + default: + state = sw_value; + if (find) { + if (ch < '1' || ch > '9') { + return NGX_ERROR; + } + + status->code = status->code * 10 + ch - '0'; + if (status->count++ != 0) { + return NGX_ERROR; + } + } + + break; + } + + break; + + /* header value */ + case sw_value: + + if (find) { + if (ch < '0' || ch > '9') { + return NGX_ERROR; + } + + status->code = status->code * 10 + ch - '0'; + + if (++status->count == 3) { + return NGX_DONE; + } + } + + switch (ch) { + case ' ': + state = sw_space_after_value; + break; + case CR: + state = sw_almost_done; + break; + case LF: + goto done; + case '\0': + return NGX_ERROR; + } + + break; + + /* space* before end of header line */ + case sw_space_after_value: + switch (ch) { + case ' ': + break; + case CR: + state = sw_almost_done; + break; + case LF: + state = sw_start; + break; + case '\0': + return NGX_ERROR; + default: + state = sw_value; + break; + } + break; + + /* ignore header line */ + case sw_ignore_line: + switch (ch) { + case LF: + state = sw_start; + break; + default: + break; + } + break; + + /* end of header line */ + case sw_almost_done: + switch (ch) { + case LF: + goto done; + case CR: + break; + default: + return NGX_ERROR; + } + break; + + /* end of header */ + case sw_header_almost_done: + switch (ch) { + case LF: + goto header_done; + default: + return NGX_ERROR; + } + } + } + + b->pos = p; + ctx->state = state; + + return NGX_AGAIN; + +done: + + b->pos = p + 1; + ctx->state = sw_start; + + return NGX_OK; + +header_done: + + b->pos = p + 1; + ctx->state = sw_start; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_check_parse_status_line(ngx_http_upstream_check_ctx_t *ctx, + ngx_buf_t *b, ngx_http_status_t *status) +{ + u_char ch, *p; + enum { + sw_start = 0, + sw_H, + sw_HT, + sw_HTT, + sw_HTTP, + sw_first_major_digit, + sw_major_digit, + sw_first_minor_digit, + sw_minor_digit, + sw_status, + sw_space_after_status, + sw_status_text, + sw_almost_done + } state; + + state = ctx->state; + + for (p = b->pos; p < b->last; p++) { + ch = *p; + + switch (state) { + + /* "HTTP/" */ + case sw_start: + if (ch != 'H') { + return NGX_ERROR; + } + + state = sw_H; + break; + + case sw_H: + if (ch != 'T') { + return NGX_ERROR; + } + + state = sw_HT; + break; + + case sw_HT: + if (ch != 'T') { + return NGX_ERROR; + } + + state = sw_HTT; + break; + + case sw_HTT: + if (ch != 'P') { + return NGX_ERROR; + } + + state = sw_HTTP; + break; + + case sw_HTTP: + if (ch != '/') { + return NGX_ERROR; + } + + state = sw_first_major_digit; + break; + + /* the first digit of major HTTP version */ + case sw_first_major_digit: + if (ch < '1' || ch > '9') { + return NGX_ERROR; + } + + state = sw_major_digit; + break; + + /* the major HTTP version or dot */ + case sw_major_digit: + if (ch == '.') { + state = sw_first_minor_digit; + break; + } + + if (ch < '0' || ch > '9') { + return NGX_ERROR; + } + + break; + + /* the first digit of minor HTTP version */ + case sw_first_minor_digit: + if (ch < '0' || ch > '9') { + return NGX_ERROR; + } + + state = sw_minor_digit; + break; + + /* the minor HTTP version or the end of the request line */ + case sw_minor_digit: + if (ch == ' ') { + state = sw_status; + break; + } + + if (ch < '0' || ch > '9') { + return NGX_ERROR; + } + + break; + + /* HTTP status code */ + case sw_status: + if (ch == ' ') { + break; + } + + if (ch < '0' || ch > '9') { + return NGX_ERROR; + } + + status->code = status->code * 10 + ch - '0'; + + if (++status->count == 3) { + state = sw_space_after_status; + status->start = p - 2; + } + + break; + + /* space or end of line */ + case sw_space_after_status: + switch (ch) { + case ' ': + state = sw_status_text; + break; + case '.': /* IIS may send 403.1, 403.2, etc */ + state = sw_status_text; + break; + case CR: + state = sw_almost_done; + break; + case LF: + goto done; + default: + return NGX_ERROR; + } + break; + + /* any text until end of line */ + case sw_status_text: + switch (ch) { + case CR: + state = sw_almost_done; + + break; + case LF: + goto done; + } + break; + + /* end of status line */ + case sw_almost_done: + status->end = p - 1; + if (ch == LF) { + goto done; + } else { + return NGX_ERROR; + } + } + } + + b->pos = p; + ctx->state = state; + + return NGX_AGAIN; + +done: + + b->pos = p + 1; + + if (status->end == NULL) { + status->end = p; + } + + ctx->state = sw_start; + + return NGX_OK; +} + + +static void +ngx_http_upstream_check_http_reinit(ngx_http_upstream_check_peer_t *peer) +{ + ngx_http_upstream_check_ctx_t *ctx; + + ctx = peer->check_data; + + ctx->send.pos = ctx->send.start; + ctx->send.last = ctx->send.end; + + ctx->recv.pos = ctx->recv.last = ctx->recv.start; + + ctx->state = 0; + + ngx_memzero(&ctx->status, sizeof(ngx_http_status_t)); +} + + +static ngx_int_t +ngx_http_upstream_check_ssl_hello_init(ngx_http_upstream_check_peer_t *peer) +{ + ngx_http_upstream_check_ctx_t *ctx; + ngx_http_upstream_check_srv_conf_t *ucscf; + + ctx = peer->check_data; + ucscf = peer->conf; + + ctx->send.start = ctx->send.pos = (u_char *)ucscf->send.data; + ctx->send.end = ctx->send.last = ctx->send.start + ucscf->send.len; + + ctx->recv.start = ctx->recv.pos = NULL; + ctx->recv.end = ctx->recv.last = NULL; + + return NGX_OK; +} + + +/* a rough check of server ssl_hello responses */ +static ngx_int_t +ngx_http_upstream_check_ssl_hello_parse(ngx_http_upstream_check_peer_t *peer) +{ + size_t size; + ngx_ssl_server_hello_t *resp; + ngx_http_upstream_check_ctx_t *ctx; + + ctx = peer->check_data; + + size = ctx->recv.last - ctx->recv.pos; + if (size < sizeof(ngx_ssl_server_hello_t)) { + return NGX_AGAIN; + } + + resp = (ngx_ssl_server_hello_t *) ctx->recv.pos; + + ngx_log_debug7(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "http check ssl_parse, type: %ud, version: %ud.%ud, " + "length: %ud, handshanke_type: %ud, hello_version: %ud.%ud", + resp->msg_type, resp->version.major, resp->version.minor, + ntohs(resp->length), resp->handshake_type, + resp->hello_version.major, resp->hello_version.minor); + + if (resp->msg_type != NGX_SSL_HANDSHAKE) { + return NGX_ERROR; + } + + if (resp->handshake_type != NGX_SSL_SERVER_HELLO) { + return NGX_ERROR; + } + + return NGX_OK; +} + + +static void +ngx_http_upstream_check_ssl_hello_reinit(ngx_http_upstream_check_peer_t *peer) +{ + ngx_http_upstream_check_ctx_t *ctx; + + ctx = peer->check_data; + + ctx->send.pos = ctx->send.start; + ctx->send.last = ctx->send.end; + + ctx->recv.pos = ctx->recv.last = ctx->recv.start; +} + + +static ngx_int_t +ngx_http_upstream_check_mysql_init(ngx_http_upstream_check_peer_t *peer) +{ + ngx_http_upstream_check_ctx_t *ctx; + ngx_http_upstream_check_srv_conf_t *ucscf; + + ctx = peer->check_data; + ucscf = peer->conf; + + ctx->send.start = ctx->send.pos = (u_char *)ucscf->send.data; + ctx->send.end = ctx->send.last = ctx->send.start + ucscf->send.len; + + ctx->recv.start = ctx->recv.pos = NULL; + ctx->recv.end = ctx->recv.last = NULL; + + return NGX_OK; +} + + +/* a rough check of mysql greeting responses */ +static ngx_int_t +ngx_http_upstream_check_mysql_parse(ngx_http_upstream_check_peer_t *peer) +{ + size_t size; + ngx_mysql_handshake_init_t *handshake; + ngx_http_upstream_check_ctx_t *ctx; + + ctx = peer->check_data; + + size = ctx->recv.last - ctx->recv.pos; + if (size < sizeof(ngx_mysql_handshake_init_t)) { + return NGX_AGAIN; + } + + handshake = (ngx_mysql_handshake_init_t *) ctx->recv.pos; + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "mysql_parse: packet_number=%ud, protocol=%ud, server=%s", + handshake->packet_number, handshake->protocol_version, + handshake->others); + + /* The mysql greeting packet's serial number always begins with 0. */ + if (handshake->packet_number != 0x00) { + return NGX_ERROR; + } + + return NGX_OK; +} + + +static void +ngx_http_upstream_check_mysql_reinit(ngx_http_upstream_check_peer_t *peer) +{ + ngx_http_upstream_check_ctx_t *ctx; + + ctx = peer->check_data; + + ctx->send.pos = ctx->send.start; + ctx->send.last = ctx->send.end; + + ctx->recv.pos = ctx->recv.last = ctx->recv.start; +} + + +static ngx_int_t +ngx_http_upstream_check_ajp_init(ngx_http_upstream_check_peer_t *peer) +{ + ngx_http_upstream_check_ctx_t *ctx; + ngx_http_upstream_check_srv_conf_t *ucscf; + + ctx = peer->check_data; + ucscf = peer->conf; + + ctx->send.start = ctx->send.pos = (u_char *)ucscf->send.data; + ctx->send.end = ctx->send.last = ctx->send.start + ucscf->send.len; + + ctx->recv.start = ctx->recv.pos = NULL; + ctx->recv.end = ctx->recv.last = NULL; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_check_ajp_parse(ngx_http_upstream_check_peer_t *peer) +{ + size_t size; + u_char *p; + ngx_http_upstream_check_ctx_t *ctx; + + ctx = peer->check_data; + + size = ctx->recv.last - ctx->recv.pos; + if (size < sizeof(ngx_ajp_cpong_packet)) { + return NGX_AGAIN; + } + + p = ctx->recv.pos; + +#if (NGX_DEBUG) + { + ngx_ajp_raw_packet_t *ajp; + + ajp = (ngx_ajp_raw_packet_t *) p; + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "ajp_parse: preamble=0x%uxd, length=0x%uxd, type=0x%uxd", + ntohs(ajp->preamble), ntohs(ajp->length), ajp->type); + } +#endif + + if (ngx_memcmp(ngx_ajp_cpong_packet, p, sizeof(ngx_ajp_cpong_packet)) == 0) + { + return NGX_OK; + } else { + return NGX_ERROR; + } +} + + +static void +ngx_http_upstream_check_ajp_reinit(ngx_http_upstream_check_peer_t *peer) +{ + ngx_http_upstream_check_ctx_t *ctx; + + ctx = peer->check_data; + + ctx->send.pos = ctx->send.start; + ctx->send.last = ctx->send.end; + + ctx->recv.pos = ctx->recv.last = ctx->recv.start; +} + + +static void +ngx_http_upstream_check_status_update(ngx_http_upstream_check_peer_t *peer, + ngx_int_t result) +{ + ngx_http_upstream_check_srv_conf_t *ucscf; + + ucscf = peer->conf; + + if (result) { + peer->shm->rise_count++; + peer->shm->fall_count = 0; + if (peer->shm->down && peer->shm->rise_count >= ucscf->rise_count) { + peer->shm->down = 0; + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "enable check peer: %V ", + &peer->check_peer_addr->name); + } + } else { + peer->shm->rise_count = 0; + peer->shm->fall_count++; + if (!peer->shm->down && peer->shm->fall_count >= ucscf->fall_count) { + peer->shm->down = 1; + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "disable check peer: %V ", + &peer->check_peer_addr->name); + } + } + + peer->shm->access_time = ngx_current_msec; +} + + +static void +ngx_http_upstream_check_clean_event(ngx_http_upstream_check_peer_t *peer) +{ + ngx_connection_t *c; + ngx_http_upstream_check_srv_conf_t *ucscf; + ngx_check_conf_t *cf; + + c = peer->pc.connection; + ucscf = peer->conf; + cf = ucscf->check_type_conf; + + if (c) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http check clean event: index:%i, fd: %d", + peer->index, c->fd); + if (c->error == 0 && + cf->need_keepalive && + (c->requests < ucscf->check_keepalive_requests)) + { + c->write->handler = ngx_http_upstream_check_dummy_handler; + c->read->handler = ngx_http_upstream_check_discard_handler; + } else { + ngx_close_connection(c); + peer->pc.connection = NULL; + } + } + + if (peer->check_timeout_ev.timer_set) { + ngx_del_timer(&peer->check_timeout_ev); + } + + peer->state = NGX_HTTP_CHECK_ALL_DONE; + + if (peer->check_data != NULL && peer->reinit) { + peer->reinit(peer); + } + + peer->shm->owner = NGX_INVALID_PID; +} + + +static void +ngx_http_upstream_check_timeout_handler(ngx_event_t *event) +{ + ngx_http_upstream_check_peer_t *peer; + + if (ngx_http_upstream_check_need_exit()) { + return; + } + + peer = event->data; + peer->pc.connection->error = 1; + + ngx_log_error(NGX_LOG_ERR, event->log, 0, + "check time out with peer: %V ", + &peer->check_peer_addr->name); + + ngx_http_upstream_check_status_update(peer, 0); + ngx_http_upstream_check_clean_event(peer); +} + + +static void +ngx_http_upstream_check_finish_handler(ngx_event_t *event) +{ + if (ngx_http_upstream_check_need_exit()) { + return; + } +} + + +static ngx_int_t +ngx_http_upstream_check_need_exit() +{ + if (ngx_terminate || ngx_exiting || ngx_quit) { + ngx_http_upstream_check_clear_all_events(); + return 1; + } + + return 0; +} + + +static void +ngx_http_upstream_check_clear_all_events() +{ + ngx_uint_t i; + ngx_connection_t *c; + ngx_http_upstream_check_peer_t *peer; + ngx_http_upstream_check_peers_t *peers; + + static ngx_flag_t has_cleared = 0; + + if (has_cleared || check_peers_ctx == NULL) { + return; + } + + ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0, + "clear all the events on %P ", ngx_pid); + + has_cleared = 1; + + peers = check_peers_ctx; + + peer = peers->peers.elts; + for (i = 0; i < peers->peers.nelts; i++) { + + if (peer[i].check_ev.timer_set) { + ngx_del_timer(&peer[i].check_ev); + } + + if (peer[i].check_timeout_ev.timer_set) { + ngx_del_timer(&peer[i].check_timeout_ev); + } + + c = peer[i].pc.connection; + if (c) { + ngx_close_connection(c); + peer[i].pc.connection = NULL; + } + + if (peer[i].pool != NULL) { + ngx_destroy_pool(peer[i].pool); + peer[i].pool = NULL; + } + } +} + + +static ngx_int_t +ngx_http_upstream_check_status_handler(ngx_http_request_t *r) +{ + size_t buffer_size; + ngx_int_t rc; + ngx_buf_t *b; + ngx_chain_t out; + ngx_http_upstream_check_peers_t *peers; + ngx_http_upstream_check_loc_conf_t *uclcf; + ngx_http_upstream_check_status_ctx_t *ctx; + + if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) { + return NGX_HTTP_NOT_ALLOWED; + } + + rc = ngx_http_discard_request_body(r); + + if (rc != NGX_OK) { + return rc; + } + + uclcf = ngx_http_get_module_loc_conf(r, ngx_http_upstream_check_module); + + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_check_status_ctx_t)); + if (ctx == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + ngx_http_upstream_check_status_parse_args(r, ctx); + + if (ctx->format == NULL) { + ctx->format = uclcf->format; + } + + r->headers_out.content_type = ctx->format->content_type; + + if (r->method == NGX_HTTP_HEAD) { + r->headers_out.status = NGX_HTTP_OK; + + rc = ngx_http_send_header(r); + + if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { + return rc; + } + } + + peers = check_peers_ctx; + if (peers == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "http upstream check module can not find any check " + "server, make sure you've added the check servers"); + + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + /* 1/4 pagesize for each record */ + buffer_size = peers->peers.nelts * ngx_pagesize / 4; + buffer_size = ngx_align(buffer_size, ngx_pagesize) + ngx_pagesize; + + b = ngx_create_temp_buf(r->pool, buffer_size); + if (b == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + out.buf = b; + out.next = NULL; + + ctx->format->output(b, peers, ctx->flag); + + r->headers_out.status = NGX_HTTP_OK; + r->headers_out.content_length_n = b->last - b->pos; + + if (r->headers_out.content_length_n == 0) { + r->header_only = 1; + } + + b->last_buf = 1; + + rc = ngx_http_send_header(r); + + if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { + return rc; + } + + return ngx_http_output_filter(r, &out); +} + + +static void +ngx_http_upstream_check_status_parse_args(ngx_http_request_t *r, + ngx_http_upstream_check_status_ctx_t *ctx) +{ + ngx_str_t value; + ngx_uint_t i; + ngx_check_status_command_t *command; + + if (r->args.len == 0) { + return; + } + + for (i = 0; /* void */ ; i++) { + + command = &ngx_check_status_commands[i]; + + if (command->name.len == 0) { + break; + } + + if (ngx_http_arg(r, command->name.data, command->name.len, &value) + == NGX_OK) { + + if (command->handler(ctx, &value) != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "http upstream check, bad argument: \"%V\"", + &value); + } + } + } + + ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, + "http upstream check, flag: \"%ui\"", ctx->flag); +} + + +static ngx_int_t +ngx_http_upstream_check_status_command_format( + ngx_http_upstream_check_status_ctx_t *ctx, ngx_str_t *value) +{ + ctx->format = ngx_http_get_check_status_format_conf(value); + if (ctx->format == NULL) { + return NGX_ERROR; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_check_status_command_status( + ngx_http_upstream_check_status_ctx_t *ctx, ngx_str_t *value) +{ + if (value->len == (sizeof("down") - 1) + && ngx_strncasecmp(value->data, (u_char *) "down", value->len) == 0) { + + ctx->flag |= NGX_CHECK_STATUS_DOWN; + + } else if (value->len == (sizeof("up") - 1) + && ngx_strncasecmp(value->data, (u_char *) "up", value->len) + == 0) { + + ctx->flag |= NGX_CHECK_STATUS_UP; + + } else { + return NGX_ERROR; + } + + return NGX_OK; +} + + +static void +ngx_http_upstream_check_status_html_format(ngx_buf_t *b, + ngx_http_upstream_check_peers_t *peers, ngx_uint_t flag) +{ + ngx_uint_t i, count; + ngx_http_upstream_check_peer_t *peer; + + peer = peers->peers.elts; + + count = 0; + + for (i = 0; i < peers->peers.nelts; i++) { + + if (flag & NGX_CHECK_STATUS_DOWN) { + + if (!peer[i].shm->down) { + continue; + } + + } else if (flag & NGX_CHECK_STATUS_UP) { + + if (peer[i].shm->down) { + continue; + } + } + + count++; + } + + b->last = ngx_snprintf(b->last, b->end - b->last, + "\n" + "\n" + "\n" + " Nginx http upstream check status\n" + "\n" + "\n" + "

Nginx http upstream check status

\n" + "

Check upstream server number: %ui, generation: %ui

\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n", + count, ngx_http_upstream_check_shm_generation); + + for (i = 0; i < peers->peers.nelts; i++) { + + if (flag & NGX_CHECK_STATUS_DOWN) { + + if (!peer[i].shm->down) { + continue; + } + + } else if (flag & NGX_CHECK_STATUS_UP) { + + if (peer[i].shm->down) { + continue; + } + } + + b->last = ngx_snprintf(b->last, b->end - b->last, + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n", + peer[i].shm->down ? " bgcolor=\"#FF0000\"" : "", + i, + peer[i].upstream_name, + &peer[i].peer_addr->name, + peer[i].shm->down ? "down" : "up", + peer[i].shm->rise_count, + peer[i].shm->fall_count, + &peer[i].conf->check_type_conf->name, + peer[i].conf->port); + } + + b->last = ngx_snprintf(b->last, b->end - b->last, + "
IndexUpstreamNameStatusRise countsFall countsCheck typeCheck port
%ui%V%V%s%ui%ui%V%ui
\n" + "\n" + "\n"); +} + + +static void +ngx_http_upstream_check_status_csv_format(ngx_buf_t *b, + ngx_http_upstream_check_peers_t *peers, ngx_uint_t flag) +{ + ngx_uint_t i; + ngx_http_upstream_check_peer_t *peer; + + peer = peers->peers.elts; + for (i = 0; i < peers->peers.nelts; i++) { + + if (flag & NGX_CHECK_STATUS_DOWN) { + + if (!peer[i].shm->down) { + continue; + } + + } else if (flag & NGX_CHECK_STATUS_UP) { + + if (peer[i].shm->down) { + continue; + } + } + + b->last = ngx_snprintf(b->last, b->end - b->last, + "%ui,%V,%V,%s,%ui,%ui,%V,%ui\n", + i, + peer[i].upstream_name, + &peer[i].peer_addr->name, + peer[i].shm->down ? "down" : "up", + peer[i].shm->rise_count, + peer[i].shm->fall_count, + &peer[i].conf->check_type_conf->name, + peer[i].conf->port); + } +} + + +static void +ngx_http_upstream_check_status_json_format(ngx_buf_t *b, + ngx_http_upstream_check_peers_t *peers, ngx_uint_t flag) +{ + ngx_uint_t count, i, last; + ngx_http_upstream_check_peer_t *peer; + + peer = peers->peers.elts; + + count = 0; + + for (i = 0; i < peers->peers.nelts; i++) { + + if (flag & NGX_CHECK_STATUS_DOWN) { + + if (!peer[i].shm->down) { + continue; + } + + } else if (flag & NGX_CHECK_STATUS_UP) { + + if (peer[i].shm->down) { + continue; + } + } + + count++; + } + + b->last = ngx_snprintf(b->last, b->end - b->last, + "{\"servers\": {\n" + " \"total\": %ui,\n" + " \"generation\": %ui,\n" + " \"server\": [\n", + count, + ngx_http_upstream_check_shm_generation); + + last = peers->peers.nelts - 1; + for (i = 0; i < peers->peers.nelts; i++) { + + if (flag & NGX_CHECK_STATUS_DOWN) { + + if (!peer[i].shm->down) { + continue; + } + + } else if (flag & NGX_CHECK_STATUS_UP) { + + if (peer[i].shm->down) { + continue; + } + } + + b->last = ngx_snprintf(b->last, b->end - b->last, + " {\"index\": %ui, " + "\"upstream\": \"%V\", " + "\"name\": \"%V\", " + "\"status\": \"%s\", " + "\"rise\": %ui, " + "\"fall\": %ui, " + "\"type\": \"%V\", " + "\"port\": %ui}" + "%s\n", + i, + peer[i].upstream_name, + &peer[i].peer_addr->name, + peer[i].shm->down ? "down" : "up", + peer[i].shm->rise_count, + peer[i].shm->fall_count, + &peer[i].conf->check_type_conf->name, + peer[i].conf->port, + (i == last) ? "" : ","); + } + + b->last = ngx_snprintf(b->last, b->end - b->last, + " ]\n"); + + b->last = ngx_snprintf(b->last, b->end - b->last, + "}}\n"); +} + + +static ngx_check_conf_t * +ngx_http_get_check_type_conf(ngx_str_t *str) +{ + ngx_uint_t i; + + for (i = 0; /* void */ ; i++) { + + if (ngx_check_types[i].type == 0) { + break; + } + + if (str->len != ngx_check_types[i].name.len) { + continue; + } + + if (ngx_strncmp(str->data, ngx_check_types[i].name.data, + str->len) == 0) + { + return &ngx_check_types[i]; + } + } + + return NULL; +} + + +static char * +ngx_http_upstream_check(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_str_t *value, s; + ngx_uint_t i, port, rise, fall, default_down; + ngx_msec_t interval, timeout; + ngx_http_upstream_check_srv_conf_t *ucscf; + + /* default values */ + port = 0; + rise = 2; + fall = 5; + interval = 30000; + timeout = 1000; + default_down = 1; + + value = cf->args->elts; + + ucscf = ngx_http_conf_get_module_srv_conf(cf, + ngx_http_upstream_check_module); + if (ucscf == NULL) { + return NGX_CONF_ERROR; + } + + for (i = 1; i < cf->args->nelts; i++) { + + if (ngx_strncmp(value[i].data, "type=", 5) == 0) { + s.len = value[i].len - 5; + s.data = value[i].data + 5; + + ucscf->check_type_conf = ngx_http_get_check_type_conf(&s); + + if (ucscf->check_type_conf == NULL) { + goto invalid_check_parameter; + } + + continue; + } + + if (ngx_strncmp(value[i].data, "port=", 5) == 0) { + s.len = value[i].len - 5; + s.data = value[i].data + 5; + + port = ngx_atoi(s.data, s.len); + if (port == (ngx_uint_t) NGX_ERROR || port == 0) { + goto invalid_check_parameter; + } + + continue; + } + + if (ngx_strncmp(value[i].data, "interval=", 9) == 0) { + s.len = value[i].len - 9; + s.data = value[i].data + 9; + + interval = ngx_atoi(s.data, s.len); + if (interval == (ngx_msec_t) NGX_ERROR || interval == 0) { + goto invalid_check_parameter; + } + + continue; + } + + if (ngx_strncmp(value[i].data, "timeout=", 8) == 0) { + s.len = value[i].len - 8; + s.data = value[i].data + 8; + + timeout = ngx_atoi(s.data, s.len); + if (timeout == (ngx_msec_t) NGX_ERROR || timeout == 0) { + goto invalid_check_parameter; + } + + continue; + } + + if (ngx_strncmp(value[i].data, "rise=", 5) == 0) { + s.len = value[i].len - 5; + s.data = value[i].data + 5; + + rise = ngx_atoi(s.data, s.len); + if (rise == (ngx_uint_t) NGX_ERROR || rise == 0) { + goto invalid_check_parameter; + } + + continue; + } + + if (ngx_strncmp(value[i].data, "fall=", 5) == 0) { + s.len = value[i].len - 5; + s.data = value[i].data + 5; + + fall = ngx_atoi(s.data, s.len); + if (fall == (ngx_uint_t) NGX_ERROR || fall == 0) { + goto invalid_check_parameter; + } + + continue; + } + + if (ngx_strncmp(value[i].data, "default_down=", 13) == 0) { + s.len = value[i].len - 13; + s.data = value[i].data + 13; + + if (ngx_strcasecmp(s.data, (u_char *) "true") == 0) { + default_down = 1; + } else if (ngx_strcasecmp(s.data, (u_char *) "false") == 0) { + default_down = 0; + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid value \"%s\", " + "it must be \"true\" or \"false\"", + value[i].data); + return NGX_CONF_ERROR; + } + + continue; + } + + goto invalid_check_parameter; + } + + ucscf->port = port; + ucscf->check_interval = interval; + ucscf->check_timeout = timeout; + ucscf->fall_count = fall; + ucscf->rise_count = rise; + ucscf->default_down = default_down; + + if (ucscf->check_type_conf == NGX_CONF_UNSET_PTR) { + ngx_str_set(&s, "tcp"); + ucscf->check_type_conf = ngx_http_get_check_type_conf(&s); + } + + return NGX_CONF_OK; + +invalid_check_parameter: + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[i]); + + return NGX_CONF_ERROR; +} + + +static char * +ngx_http_upstream_check_keepalive_requests(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + ngx_str_t *value; + ngx_http_upstream_check_srv_conf_t *ucscf; + ngx_uint_t requests; + + value = cf->args->elts; + + ucscf = ngx_http_conf_get_module_srv_conf(cf, + ngx_http_upstream_check_module); + + requests = ngx_atoi(value[1].data, value[1].len); + if (requests == (ngx_uint_t) NGX_ERROR || requests == 0) { + return "invalid value"; + } + + ucscf->check_keepalive_requests = requests; + + return NGX_CONF_OK; +} + + +static char * +ngx_http_upstream_check_http_send(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + ngx_str_t *value; + ngx_http_upstream_check_srv_conf_t *ucscf; + + value = cf->args->elts; + + ucscf = ngx_http_conf_get_module_srv_conf(cf, + ngx_http_upstream_check_module); + + ucscf->send = value[1]; + + return NGX_CONF_OK; +} + + +static char * +ngx_http_upstream_check_fastcgi_params(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + ngx_str_t *value, *k, *v; + ngx_http_upstream_check_srv_conf_t *ucscf; + + value = cf->args->elts; + + ucscf = ngx_http_conf_get_module_srv_conf(cf, + ngx_http_upstream_check_module); + + k = ngx_array_push(ucscf->fastcgi_params); + if (k == NULL) { + return NGX_CONF_ERROR; + } + + v = ngx_array_push(ucscf->fastcgi_params); + if (v == NULL) { + return NGX_CONF_ERROR; + } + + *k = value[1]; + *v = value[2]; + + return NGX_CONF_OK; +} + + +static char * +ngx_http_upstream_check_http_expect_alive(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + ngx_str_t *value; + ngx_uint_t bit, i, m; + ngx_conf_bitmask_t *mask; + ngx_http_upstream_check_srv_conf_t *ucscf; + + value = cf->args->elts; + mask = ngx_check_http_expect_alive_masks; + + ucscf = ngx_http_conf_get_module_srv_conf(cf, + ngx_http_upstream_check_module); + bit = ucscf->code.status_alive; + + for (i = 1; i < cf->args->nelts; i++) { + for (m = 0; mask[m].name.len != 0; m++) { + + if (mask[m].name.len != value[i].len + || ngx_strcasecmp(mask[m].name.data, value[i].data) != 0) + { + continue; + } + + if (bit & mask[m].mask) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "duplicate value \"%s\"", value[i].data); + + } else { + bit |= mask[m].mask; + } + + break; + } + + if (mask[m].name.len == 0) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "invalid value \"%s\"", value[i].data); + + return NGX_CONF_ERROR; + } + } + + ucscf->code.status_alive = bit; + + return NGX_CONF_OK; +} + + +static char * +ngx_http_upstream_check_shm_size(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_str_t *value; + ngx_http_upstream_check_main_conf_t *ucmcf; + + ucmcf = ngx_http_conf_get_module_main_conf(cf, + ngx_http_upstream_check_module); + if (ucmcf->check_shm_size) { + return "is duplicate"; + } + + value = cf->args->elts; + + ucmcf->check_shm_size = ngx_parse_size(&value[1]); + if (ucmcf->check_shm_size == (size_t) NGX_ERROR) { + return "invalid value"; + } + + return NGX_CONF_OK; +} + + +static ngx_check_status_conf_t * +ngx_http_get_check_status_format_conf(ngx_str_t *str) +{ + ngx_uint_t i; + + for (i = 0; /* void */ ; i++) { + + if (ngx_check_status_formats[i].format.len == 0) { + break; + } + + if (str->len != ngx_check_status_formats[i].format.len) { + continue; + } + + if (ngx_strncmp(str->data, ngx_check_status_formats[i].format.data, + str->len) == 0) + { + return &ngx_check_status_formats[i]; + } + } + + return NULL; +} + + +static char * +ngx_http_upstream_check_status(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_str_t *value; + ngx_http_core_loc_conf_t *clcf; + ngx_http_upstream_check_loc_conf_t *uclcf; + + value = cf->args->elts; + + clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); + + clcf->handler = ngx_http_upstream_check_status_handler; + + if (cf->args->nelts == 2) { + uclcf = ngx_http_conf_get_module_loc_conf(cf, + ngx_http_upstream_check_module); + + uclcf->format = ngx_http_get_check_status_format_conf(&value[1]); + if (uclcf->format == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid check format \"%V\"", &value[1]); + + return NGX_CONF_ERROR; + } + } + + return NGX_CONF_OK; +} + + +static void * +ngx_http_upstream_check_create_main_conf(ngx_conf_t *cf) +{ + ngx_http_upstream_check_main_conf_t *ucmcf; + + ucmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_check_main_conf_t)); + if (ucmcf == NULL) { + return NULL; + } + + ucmcf->peers = ngx_pcalloc(cf->pool, + sizeof(ngx_http_upstream_check_peers_t)); + if (ucmcf->peers == NULL) { + return NULL; + } + + ucmcf->peers->checksum = 0; + + if (ngx_array_init(&ucmcf->peers->peers, cf->pool, 16, + sizeof(ngx_http_upstream_check_peer_t)) != NGX_OK) + { + return NULL; + } + + return ucmcf; +} + + +static ngx_buf_t * +ngx_http_upstream_check_create_fastcgi_request(ngx_pool_t *pool, + ngx_str_t *params, ngx_uint_t num) +{ + size_t size, len, padding; + ngx_buf_t *b; + ngx_str_t *k, *v; + ngx_uint_t i, j; + ngx_http_fastcgi_header_t *h; + + len = 0; + for (i = 0, j = 0; i < num; i++, j = i * 2) { + k = ¶ms[j]; + v = ¶ms[j + 1]; + + len += 1 + k->len + ((v->len > 127) ? 4 : 1) + v->len; + } + + padding = 8 - len % 8; + padding = (padding == 8) ? 0 : padding; + + size = sizeof(ngx_http_fastcgi_header_t) + + sizeof(ngx_http_fastcgi_begin_request_t) + + + sizeof(ngx_http_fastcgi_header_t) /* NGX_HTTP_FASTCGI_PARAMS */ + + len + padding + + sizeof(ngx_http_fastcgi_header_t) /* NGX_HTTP_FASTCGI_PARAMS */ + + + sizeof(ngx_http_fastcgi_header_t); /* NGX_HTTP_FASTCGI_STDIN */ + + + b = ngx_create_temp_buf(pool, size); + if (b == NULL) { + return NULL; + } + + ngx_http_fastcgi_request_start.br.flags = 0; + + ngx_memcpy(b->pos, &ngx_http_fastcgi_request_start, + sizeof(ngx_http_fastcgi_request_start_t)); + + h = (ngx_http_fastcgi_header_t *) + (b->pos + sizeof(ngx_http_fastcgi_header_t) + + sizeof(ngx_http_fastcgi_begin_request_t)); + + h->content_length_hi = (u_char) ((len >> 8) & 0xff); + h->content_length_lo = (u_char) (len & 0xff); + h->padding_length = (u_char) padding; + h->reserved = 0; + + b->last = b->pos + sizeof(ngx_http_fastcgi_header_t) + + sizeof(ngx_http_fastcgi_begin_request_t) + + sizeof(ngx_http_fastcgi_header_t); + + for (i = 0, j = 0; i < num; i++, j = i * 2) { + k = ¶ms[j]; + v = ¶ms[j + 1]; + + if (k->len > 127) { + *b->last++ = (u_char) (((k->len >> 24) & 0x7f) | 0x80); + *b->last++ = (u_char) ((k->len >> 16) & 0xff); + *b->last++ = (u_char) ((k->len >> 8) & 0xff); + *b->last++ = (u_char) (k->len & 0xff); + + } else { + *b->last++ = (u_char) k->len; + } + + if (v->len > 127) { + *b->last++ = (u_char) (((v->len >> 24) & 0x7f) | 0x80); + *b->last++ = (u_char) ((v->len >> 16) & 0xff); + *b->last++ = (u_char) ((v->len >> 8) & 0xff); + *b->last++ = (u_char) (v->len & 0xff); + + } else { + *b->last++ = (u_char) v->len; + } + + b->last = ngx_copy(b->last, k->data, k->len); + b->last = ngx_copy(b->last, v->data, v->len); + } + + if (padding) { + ngx_memzero(b->last, padding); + b->last += padding; + } + + h = (ngx_http_fastcgi_header_t *) b->last; + b->last += sizeof(ngx_http_fastcgi_header_t); + + h->version = 1; + h->type = NGX_HTTP_FASTCGI_PARAMS; + h->request_id_hi = 0; + h->request_id_lo = 1; + h->content_length_hi = 0; + h->content_length_lo = 0; + h->padding_length = 0; + h->reserved = 0; + + h = (ngx_http_fastcgi_header_t *) b->last; + b->last += sizeof(ngx_http_fastcgi_header_t); + + return b; +} + + +static char * +ngx_http_upstream_check_init_main_conf(ngx_conf_t *cf, void *conf) +{ + ngx_buf_t *b; + ngx_uint_t i; + ngx_http_upstream_srv_conf_t **uscfp; + ngx_http_upstream_main_conf_t *umcf; + + umcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_upstream_module); + + b = ngx_http_upstream_check_create_fastcgi_request(cf->pool, + fastcgi_default_params, + sizeof(fastcgi_default_params) / sizeof(ngx_str_t) / 2); + + if (b == NULL) { + return NGX_CONF_ERROR; + } + + fastcgi_default_request.data = b->pos; + fastcgi_default_request.len = b->last - b->pos; + + uscfp = umcf->upstreams.elts; + + for (i = 0; i < umcf->upstreams.nelts; i++) { + + if (ngx_http_upstream_check_init_srv_conf(cf, uscfp[i]) != NGX_OK) { + return NGX_CONF_ERROR; + } + } + + return ngx_http_upstream_check_init_shm(cf, conf); +} + + +static void * +ngx_http_upstream_check_create_srv_conf(ngx_conf_t *cf) +{ + ngx_http_upstream_check_srv_conf_t *ucscf; + + ucscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_check_srv_conf_t)); + if (ucscf == NULL) { + return NULL; + } + + ucscf->fastcgi_params = ngx_array_create(cf->pool, 2 * 4, sizeof(ngx_str_t)); + if (ucscf->fastcgi_params == NULL) { + return NULL; + } + + ucscf->port = NGX_CONF_UNSET_UINT; + ucscf->fall_count = NGX_CONF_UNSET_UINT; + ucscf->rise_count = NGX_CONF_UNSET_UINT; + ucscf->check_timeout = NGX_CONF_UNSET_MSEC; + ucscf->check_keepalive_requests = NGX_CONF_UNSET_UINT; + ucscf->check_type_conf = NGX_CONF_UNSET_PTR; + + return ucscf; +} + + +static void * +ngx_http_upstream_check_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_upstream_check_loc_conf_t *uclcf; + + uclcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_check_loc_conf_t)); + if (uclcf == NULL) { + return NULL; + } + + uclcf->format = NGX_CONF_UNSET_PTR; + + return uclcf; +} + + +static char * +ngx_http_upstream_check_init_srv_conf(ngx_conf_t *cf, void *conf) +{ + ngx_str_t s; + ngx_buf_t *b; + ngx_check_conf_t *check; + ngx_http_upstream_srv_conf_t *us = conf; + ngx_http_upstream_check_srv_conf_t *ucscf; + + if (us->srv_conf == NULL) { + return NGX_CONF_OK; + } + + ucscf = ngx_http_conf_upstream_srv_conf(us, ngx_http_upstream_check_module); + + if (ucscf->port == NGX_CONF_UNSET_UINT) { + ucscf->port = 0; + } + + if (ucscf->fall_count == NGX_CONF_UNSET_UINT) { + ucscf->fall_count = 2; + } + + if (ucscf->rise_count == NGX_CONF_UNSET_UINT) { + ucscf->rise_count = 5; + } + + if (ucscf->check_interval == NGX_CONF_UNSET_MSEC) { + ucscf->check_interval = 0; + } + + if (ucscf->check_timeout == NGX_CONF_UNSET_MSEC) { + ucscf->check_timeout = 1000; + } + + if (ucscf->check_keepalive_requests == NGX_CONF_UNSET_UINT) { + ucscf->check_keepalive_requests = 1; + } + + if (ucscf->check_type_conf == NGX_CONF_UNSET_PTR) { + ucscf->check_type_conf = NULL; + } + + check = ucscf->check_type_conf; + + if (check) { + if (ucscf->send.len == 0) { + ngx_str_set(&s, "fastcgi"); + + if (check == ngx_http_get_check_type_conf(&s)) { + + if (ucscf->fastcgi_params->nelts == 0) { + ucscf->send.data = fastcgi_default_request.data; + ucscf->send.len = fastcgi_default_request.len; + + } else { + b = ngx_http_upstream_check_create_fastcgi_request( + cf->pool, ucscf->fastcgi_params->elts, + ucscf->fastcgi_params->nelts / 2); + if (b == NULL) { + return NGX_CONF_ERROR; + } + + ucscf->send.data = b->pos; + ucscf->send.len = b->last - b->pos; + } + } else { + ucscf->send.data = check->default_send.data; + ucscf->send.len = check->default_send.len; + } + } + + + if (ucscf->code.status_alive == 0) { + ucscf->code.status_alive = check->default_status_alive; + } + } + + return NGX_CONF_OK; +} + + +static char * +ngx_http_upstream_check_merge_loc_conf(ngx_conf_t *cf, void *parent, + void *child) +{ + ngx_str_t format = ngx_string("html"); + ngx_http_upstream_check_loc_conf_t *prev = parent; + ngx_http_upstream_check_loc_conf_t *conf = child; + + ngx_conf_merge_ptr_value(conf->format, prev->format, + ngx_http_get_check_status_format_conf(&format)); + + return NGX_CONF_OK; +} + + +static char * +ngx_http_upstream_check_init_shm(ngx_conf_t *cf, void *conf) +{ + ngx_str_t *shm_name; + ngx_uint_t shm_size; + ngx_shm_zone_t *shm_zone; + ngx_http_upstream_check_main_conf_t *ucmcf = conf; + + if (ucmcf->peers->peers.nelts > 0) { + + ngx_http_upstream_check_shm_generation++; + + shm_name = &ucmcf->peers->check_shm_name; + + ngx_http_upstream_check_get_shm_name(shm_name, cf->pool, + ngx_http_upstream_check_shm_generation); + + /* The default check shared memory size is 1M */ + shm_size = 1 * 1024 * 1024; + + shm_size = shm_size < ucmcf->check_shm_size ? + ucmcf->check_shm_size : shm_size; + + shm_zone = ngx_shared_memory_add(cf, shm_name, shm_size, + &ngx_http_upstream_check_module); + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0, + "http upstream check, upsteam:%V, shm_zone size:%ui", + shm_name, shm_size); + + shm_zone->data = cf->pool; + check_peers_ctx = ucmcf->peers; + + shm_zone->init = ngx_http_upstream_check_init_shm_zone; + } + else { + check_peers_ctx = NULL; + } + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_http_upstream_check_get_shm_name(ngx_str_t *shm_name, ngx_pool_t *pool, + ngx_uint_t generation) +{ + u_char *last; + + shm_name->data = ngx_palloc(pool, SHM_NAME_LEN); + if (shm_name->data == NULL) { + return NGX_ERROR; + } + + last = ngx_snprintf(shm_name->data, SHM_NAME_LEN, "%s#%ui", + "ngx_http_upstream_check", generation); + + shm_name->len = last - shm_name->data; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_check_init_shm_zone(ngx_shm_zone_t *shm_zone, void *data) +{ + size_t size; + ngx_str_t oshm_name; + ngx_int_t rc; + ngx_uint_t i, same, number; + ngx_pool_t *pool; + ngx_shm_zone_t *oshm_zone; + ngx_slab_pool_t *shpool; + ngx_http_upstream_check_peer_t *peer; + ngx_http_upstream_check_peers_t *peers; + ngx_http_upstream_check_srv_conf_t *ucscf; + ngx_http_upstream_check_peer_shm_t *peer_shm, *opeer_shm; + ngx_http_upstream_check_peers_shm_t *peers_shm, *opeers_shm; + + opeers_shm = NULL; + peers_shm = NULL; + ngx_str_null(&oshm_name); + + same = 0; + peers = check_peers_ctx; + if (peers == NULL) { + return NGX_OK; + } + + number = peers->peers.nelts; + if (number == 0) { + return NGX_OK; + } + + pool = shm_zone->data; + if (pool == NULL) { + pool = ngx_cycle->pool; + } + + shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; + + if (data) { + opeers_shm = data; + + if ((opeers_shm->number == number) + && (opeers_shm->checksum == peers->checksum)) { + + peers_shm = data; + same = 1; + } + } + + if (!same) { + + if (ngx_http_upstream_check_shm_generation > 1) { + + ngx_http_upstream_check_get_shm_name(&oshm_name, + pool, ngx_http_upstream_check_shm_generation - 1); + + /* The global variable ngx_cycle still points to the old one */ + oshm_zone = ngx_shared_memory_find((ngx_cycle_t *) ngx_cycle, + &oshm_name, + &ngx_http_upstream_check_module); + + if (oshm_zone) { + opeers_shm = oshm_zone->data; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, shm_zone->shm.log, 0, + "http upstream check, find oshm_zone:%p, " + "opeers_shm: %p", + oshm_zone, opeers_shm); + } + } + + size = sizeof(*peers_shm) + + (number - 1) * sizeof(ngx_http_upstream_check_peer_shm_t); + + peers_shm = ngx_slab_alloc(shpool, size); + + if (peers_shm == NULL) { + goto failure; + } + + ngx_memzero(peers_shm, size); + } + + peers_shm->generation = ngx_http_upstream_check_shm_generation; + peers_shm->checksum = peers->checksum; + peers_shm->number = number; + + peer = peers->peers.elts; + + for (i = 0; i < number; i++) { + + peer_shm = &peers_shm->peers[i]; + + /* + * This function may be triggered before the old stale + * work process exits. The owner may stick to the old + * pid. + */ + peer_shm->owner = NGX_INVALID_PID; + + if (same) { + continue; + } + + peer_shm->socklen = peer[i].peer_addr->socklen; + peer_shm->sockaddr = ngx_slab_alloc(shpool, peer_shm->socklen); + if (peer_shm->sockaddr == NULL) { + goto failure; + } + + ngx_memcpy(peer_shm->sockaddr, peer[i].peer_addr->sockaddr, + peer_shm->socklen); + + if (opeers_shm) { + + opeer_shm = ngx_http_upstream_check_find_shm_peer(opeers_shm, + peer[i].peer_addr); + if (opeer_shm) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, shm_zone->shm.log, 0, + "http upstream check, inherit opeer: %V ", + &peer[i].peer_addr->name); + + rc = ngx_http_upstream_check_init_shm_peer(peer_shm, opeer_shm, + 0, pool, &peer[i].peer_addr->name); + if (rc != NGX_OK) { + return NGX_ERROR; + } + + continue; + } + } + + ucscf = peer[i].conf; + rc = ngx_http_upstream_check_init_shm_peer(peer_shm, NULL, + ucscf->default_down, pool, + &peer[i].peer_addr->name); + if (rc != NGX_OK) { + return NGX_ERROR; + } + } + + peers->peers_shm = peers_shm; + shm_zone->data = peers_shm; + + return NGX_OK; + +failure: + ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0, + "http upstream check_shm_size is too small, " + "you should specify a larger size."); + return NGX_ERROR; +} + + +static ngx_shm_zone_t * +ngx_shared_memory_find(ngx_cycle_t *cycle, ngx_str_t *name, void *tag) +{ + ngx_uint_t i; + ngx_shm_zone_t *shm_zone; + ngx_list_part_t *part; + + part = (ngx_list_part_t *) &(cycle->shared_memory.part); + shm_zone = part->elts; + + for (i = 0; /* void */ ; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + part = part->next; + shm_zone = part->elts; + i = 0; + } + + if (name->len != shm_zone[i].shm.name.len) { + continue; + } + + if (ngx_strncmp(name->data, shm_zone[i].shm.name.data, name->len) != 0) + { + continue; + } + + if (tag != shm_zone[i].tag) { + continue; + } + + return &shm_zone[i]; + } + + return NULL; +} + + +static ngx_http_upstream_check_peer_shm_t * +ngx_http_upstream_check_find_shm_peer(ngx_http_upstream_check_peers_shm_t *p, + ngx_addr_t *addr) +{ + ngx_uint_t i; + ngx_http_upstream_check_peer_shm_t *peer_shm; + + for (i = 0; i < p->number; i++) { + + peer_shm = &p->peers[i]; + + if (addr->socklen != peer_shm->socklen) { + continue; + } + + if (ngx_memcmp(addr->sockaddr, peer_shm->sockaddr, addr->socklen) == 0) { + return peer_shm; + } + } + + return NULL; +} + + +static ngx_int_t +ngx_http_upstream_check_init_shm_peer(ngx_http_upstream_check_peer_shm_t *psh, + ngx_http_upstream_check_peer_shm_t *opsh, ngx_uint_t init_down, + ngx_pool_t *pool, ngx_str_t *name) +{ + u_char *file; + + if (opsh) { + psh->access_time = opsh->access_time; + psh->access_count = opsh->access_count; + + psh->fall_count = opsh->fall_count; + psh->rise_count = opsh->rise_count; + psh->busyness = opsh->busyness; + + psh->down = opsh->down; + + } else { + psh->access_time = 0; + psh->access_count = 0; + + psh->fall_count = 0; + psh->rise_count = 0; + psh->busyness = 0; + + psh->down = init_down; + } + +#if (NGX_HAVE_ATOMIC_OPS) + + file = NULL; + +#else + + file = ngx_pnalloc(pool, ngx_cycle->lock_file.len + name->len); + if (file == NULL) { + return NGX_ERROR; + } + + (void) ngx_sprintf(file, "%V%V%Z", &ngx_cycle->lock_file, name); + +#endif + +#if (nginx_version >= 1002000) + if (ngx_shmtx_create(&psh->mutex, &psh->lock, file) != NGX_OK) { +#else + if (ngx_shmtx_create(&psh->mutex, (void *) &psh->lock, file) != NGX_OK) { +#endif + return NGX_ERROR; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_check_init_process(ngx_cycle_t *cycle) +{ + ngx_http_upstream_check_main_conf_t *ucmcf; + + if (ngx_process != NGX_PROCESS_WORKER) { + return NGX_OK; + } + + ucmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_upstream_check_module); + if (ucmcf == NULL) { + return NGX_OK; + } + + return ngx_http_upstream_check_add_timers(cycle); +} diff --git a/src/detecter/ngx_http_upstream_checker.h b/src/detecter/ngx_http_upstream_checker.h new file mode 100644 index 0000000..b08b396 --- /dev/null +++ b/src/detecter/ngx_http_upstream_checker.h @@ -0,0 +1,19 @@ +#ifndef _NGX_HTTP_UPSTREAM_CHECK_MODELE_H_INCLUDED_ +#define _NGX_HTTP_UPSTREAM_CHECK_MODELE_H_INCLUDED_ + + +#include +#include +#include + +ngx_uint_t ngx_http_upstream_check_add_peer(ngx_conf_t *cf, + ngx_http_upstream_srv_conf_t *us, ngx_addr_t *peer); + +ngx_uint_t ngx_http_upstream_check_peer_down(ngx_uint_t index); + +void ngx_http_upstream_check_get_peer(ngx_uint_t index); +void ngx_http_upstream_check_free_peer(ngx_uint_t index); + + +#endif //_NGX_HTTP_UPSTREAM_CHECK_MODELE_H_INCLUDED_ + -- 2.34.1 From bdc6324f400d27a84e6ad036ed63593e63b1d75f Mon Sep 17 00:00:00 2001 From: lingel <2894340009@qq.com> Date: Mon, 17 Jun 2024 15:23:22 +0800 Subject: [PATCH 3/3] 1 --- .../connector_controller.cpp | 0 .../connector_database.cpp | 0 .../connector_gateway.cpp | 0 .../db_processer/basic_db.cpp | 0 .../interface/connector_controller.cpp | 0 .../interface/connector_controller.h | 0 .../interface/connector_database.cpp | 0 .../interface/connector_database.h | 0 .../interface/main.cpp | 0 .../interface/main_program | Bin src/{epollip => controller}/new_client.cpp | 0 src/detect/ngx_http_upstream_check.c | 4071 ----------------- src/detect/ngx_http_upstream_check.h | 19 - 13 files changed, 4090 deletions(-) rename src/{epollip => controller}/connector_controller.cpp (100%) rename src/{epollip => controller}/connector_database.cpp (100%) rename src/{epollip => controller}/connector_gateway.cpp (100%) rename src/{epollip => controller}/db_processer/basic_db.cpp (100%) rename src/{epollip => controller}/interface/connector_controller.cpp (100%) rename src/{epollip => controller}/interface/connector_controller.h (100%) rename src/{epollip => controller}/interface/connector_database.cpp (100%) rename src/{epollip => controller}/interface/connector_database.h (100%) rename src/{epollip => controller}/interface/main.cpp (100%) rename src/{epollip => controller}/interface/main_program (100%) rename src/{epollip => controller}/new_client.cpp (100%) delete mode 100644 src/detect/ngx_http_upstream_check.c delete mode 100644 src/detect/ngx_http_upstream_check.h diff --git a/src/epollip/connector_controller.cpp b/src/controller/connector_controller.cpp similarity index 100% rename from src/epollip/connector_controller.cpp rename to src/controller/connector_controller.cpp diff --git a/src/epollip/connector_database.cpp b/src/controller/connector_database.cpp similarity index 100% rename from src/epollip/connector_database.cpp rename to src/controller/connector_database.cpp diff --git a/src/epollip/connector_gateway.cpp b/src/controller/connector_gateway.cpp similarity index 100% rename from src/epollip/connector_gateway.cpp rename to src/controller/connector_gateway.cpp diff --git a/src/epollip/db_processer/basic_db.cpp b/src/controller/db_processer/basic_db.cpp similarity index 100% rename from src/epollip/db_processer/basic_db.cpp rename to src/controller/db_processer/basic_db.cpp diff --git a/src/epollip/interface/connector_controller.cpp b/src/controller/interface/connector_controller.cpp similarity index 100% rename from src/epollip/interface/connector_controller.cpp rename to src/controller/interface/connector_controller.cpp diff --git a/src/epollip/interface/connector_controller.h b/src/controller/interface/connector_controller.h similarity index 100% rename from src/epollip/interface/connector_controller.h rename to src/controller/interface/connector_controller.h diff --git a/src/epollip/interface/connector_database.cpp b/src/controller/interface/connector_database.cpp similarity index 100% rename from src/epollip/interface/connector_database.cpp rename to src/controller/interface/connector_database.cpp diff --git a/src/epollip/interface/connector_database.h b/src/controller/interface/connector_database.h similarity index 100% rename from src/epollip/interface/connector_database.h rename to src/controller/interface/connector_database.h diff --git a/src/epollip/interface/main.cpp b/src/controller/interface/main.cpp similarity index 100% rename from src/epollip/interface/main.cpp rename to src/controller/interface/main.cpp diff --git a/src/epollip/interface/main_program b/src/controller/interface/main_program similarity index 100% rename from src/epollip/interface/main_program rename to src/controller/interface/main_program diff --git a/src/epollip/new_client.cpp b/src/controller/new_client.cpp similarity index 100% rename from src/epollip/new_client.cpp rename to src/controller/new_client.cpp diff --git a/src/detect/ngx_http_upstream_check.c b/src/detect/ngx_http_upstream_check.c deleted file mode 100644 index 6cec650..0000000 --- a/src/detect/ngx_http_upstream_check.c +++ /dev/null @@ -1,4071 +0,0 @@ - - -#include -#include "ngx_http_upstream_check_module.h" - - -typedef struct ngx_http_upstream_check_peer_s ngx_http_upstream_check_peer_t; -typedef struct ngx_http_upstream_check_srv_conf_s - ngx_http_upstream_check_srv_conf_t; - - -#pragma pack(push, 1) - -typedef struct { - u_char major; - u_char minor; -} ngx_ssl_protocol_version_t; - - -typedef struct { - u_char msg_type; - ngx_ssl_protocol_version_t version; - uint16_t length; - - u_char handshake_type; - u_char handshake_length[3]; - ngx_ssl_protocol_version_t hello_version; - - time_t time; - u_char random[28]; - - u_char others[0]; -} ngx_ssl_server_hello_t; - - -typedef struct { - u_char packet_length[3]; - u_char packet_number; - - u_char protocol_version; - u_char others[0]; -} ngx_mysql_handshake_init_t; - - -typedef struct { - uint16_t preamble; - uint16_t length; - u_char type; -} ngx_ajp_raw_packet_t; - -#pragma pack() - - -typedef struct { - ngx_buf_t send; - ngx_buf_t recv; - - ngx_uint_t state; - ngx_http_status_t status; - - size_t padding; - size_t length; -} ngx_http_upstream_check_ctx_t; - - -typedef struct { - ngx_shmtx_t mutex; -#if (nginx_version >= 1002000) - ngx_shmtx_sh_t lock; -#else - ngx_atomic_t lock; -#endif - - ngx_pid_t owner; - - ngx_msec_t access_time; - - ngx_uint_t fall_count; - ngx_uint_t rise_count; - - ngx_uint_t busyness; - ngx_uint_t access_count; - - struct sockaddr *sockaddr; - socklen_t socklen; - - ngx_atomic_t down; - - u_char padding[64]; -} ngx_http_upstream_check_peer_shm_t; - - -typedef struct { - ngx_uint_t generation; - ngx_uint_t checksum; - ngx_uint_t number; - - /* ngx_http_upstream_check_status_peer_t */ - ngx_http_upstream_check_peer_shm_t peers[1]; -} ngx_http_upstream_check_peers_shm_t; - - -#define NGX_HTTP_CHECK_CONNECT_DONE 0x0001 -#define NGX_HTTP_CHECK_SEND_DONE 0x0002 -#define NGX_HTTP_CHECK_RECV_DONE 0x0004 -#define NGX_HTTP_CHECK_ALL_DONE 0x0008 - - -typedef ngx_int_t (*ngx_http_upstream_check_packet_init_pt) - (ngx_http_upstream_check_peer_t *peer); -typedef ngx_int_t (*ngx_http_upstream_check_packet_parse_pt) - (ngx_http_upstream_check_peer_t *peer); -typedef void (*ngx_http_upstream_check_packet_clean_pt) - (ngx_http_upstream_check_peer_t *peer); - -struct ngx_http_upstream_check_peer_s { - ngx_flag_t state; - ngx_pool_t *pool; - ngx_uint_t index; - ngx_uint_t max_busy; - ngx_str_t *upstream_name; - ngx_addr_t *check_peer_addr; - ngx_addr_t *peer_addr; - ngx_event_t check_ev; - ngx_event_t check_timeout_ev; - ngx_peer_connection_t pc; - - void *check_data; - ngx_event_handler_pt send_handler; - ngx_event_handler_pt recv_handler; - - ngx_http_upstream_check_packet_init_pt init; - ngx_http_upstream_check_packet_parse_pt parse; - ngx_http_upstream_check_packet_clean_pt reinit; - - ngx_http_upstream_check_peer_shm_t *shm; - ngx_http_upstream_check_srv_conf_t *conf; -}; - - -typedef struct { - ngx_str_t check_shm_name; - ngx_uint_t checksum; - ngx_array_t peers; - - ngx_http_upstream_check_peers_shm_t *peers_shm; -} ngx_http_upstream_check_peers_t; - - -#define NGX_HTTP_CHECK_TCP 0x0001 -#define NGX_HTTP_CHECK_HTTP 0x0002 -#define NGX_HTTP_CHECK_SSL_HELLO 0x0004 -#define NGX_HTTP_CHECK_MYSQL 0x0008 -#define NGX_HTTP_CHECK_AJP 0x0010 - -#define NGX_CHECK_HTTP_2XX 0x0002 -#define NGX_CHECK_HTTP_3XX 0x0004 -#define NGX_CHECK_HTTP_4XX 0x0008 -#define NGX_CHECK_HTTP_5XX 0x0010 -#define NGX_CHECK_HTTP_ERR 0x8000 - -typedef struct { - ngx_uint_t type; - - ngx_str_t name; - - ngx_str_t default_send; - - /* HTTP */ - ngx_uint_t default_status_alive; - - ngx_event_handler_pt send_handler; - ngx_event_handler_pt recv_handler; - - ngx_http_upstream_check_packet_init_pt init; - ngx_http_upstream_check_packet_parse_pt parse; - ngx_http_upstream_check_packet_clean_pt reinit; - - unsigned need_pool; - unsigned need_keepalive; -} ngx_check_conf_t; - - -typedef void (*ngx_http_upstream_check_status_format_pt) (ngx_buf_t *b, - ngx_http_upstream_check_peers_t *peers, ngx_uint_t flag); - -typedef struct { - ngx_str_t format; - ngx_str_t content_type; - - ngx_http_upstream_check_status_format_pt output; -} ngx_check_status_conf_t; - - -#define NGX_CHECK_STATUS_DOWN 0x0001 -#define NGX_CHECK_STATUS_UP 0x0002 - -typedef struct { - ngx_check_status_conf_t *format; - ngx_flag_t flag; -} ngx_http_upstream_check_status_ctx_t; - - -typedef ngx_int_t (*ngx_http_upstream_check_status_command_pt) - (ngx_http_upstream_check_status_ctx_t *ctx, ngx_str_t *value); - -typedef struct { - ngx_str_t name; - ngx_http_upstream_check_status_command_pt handler; -} ngx_check_status_command_t; - - -typedef struct { - ngx_uint_t check_shm_size; - ngx_http_upstream_check_peers_t *peers; -} ngx_http_upstream_check_main_conf_t; - - -struct ngx_http_upstream_check_srv_conf_s { - ngx_uint_t port; - ngx_uint_t fall_count; - ngx_uint_t rise_count; - ngx_msec_t check_interval; - ngx_msec_t check_timeout; - ngx_uint_t check_keepalive_requests; - - ngx_check_conf_t *check_type_conf; - ngx_str_t send; - - union { - ngx_uint_t return_code; - ngx_uint_t status_alive; - } code; - - ngx_array_t *fastcgi_params; - - ngx_uint_t default_down; -}; - - -typedef struct { - ngx_check_status_conf_t *format; -} ngx_http_upstream_check_loc_conf_t; - - -typedef struct { - u_char version; - u_char type; - u_char request_id_hi; - u_char request_id_lo; - u_char content_length_hi; - u_char content_length_lo; - u_char padding_length; - u_char reserved; -} ngx_http_fastcgi_header_t; - - -typedef struct { - u_char role_hi; - u_char role_lo; - u_char flags; - u_char reserved[5]; -} ngx_http_fastcgi_begin_request_t; - - -typedef struct { - u_char version; - u_char type; - u_char request_id_hi; - u_char request_id_lo; -} ngx_http_fastcgi_header_small_t; - - -typedef struct { - ngx_http_fastcgi_header_t h0; - ngx_http_fastcgi_begin_request_t br; - ngx_http_fastcgi_header_small_t h1; -} ngx_http_fastcgi_request_start_t; - - -#define NGX_HTTP_FASTCGI_RESPONDER 1 - -#define NGX_HTTP_FASTCGI_KEEP_CONN 1 - -#define NGX_HTTP_FASTCGI_BEGIN_REQUEST 1 -#define NGX_HTTP_FASTCGI_ABORT_REQUEST 2 -#define NGX_HTTP_FASTCGI_END_REQUEST 3 -#define NGX_HTTP_FASTCGI_PARAMS 4 -#define NGX_HTTP_FASTCGI_STDIN 5 -#define NGX_HTTP_FASTCGI_STDOUT 6 -#define NGX_HTTP_FASTCGI_STDERR 7 -#define NGX_HTTP_FASTCGI_DATA 8 - - -typedef enum { - ngx_http_fastcgi_st_version = 0, - ngx_http_fastcgi_st_type, - ngx_http_fastcgi_st_request_id_hi, - ngx_http_fastcgi_st_request_id_lo, - ngx_http_fastcgi_st_content_length_hi, - ngx_http_fastcgi_st_content_length_lo, - ngx_http_fastcgi_st_padding_length, - ngx_http_fastcgi_st_reserved, - ngx_http_fastcgi_st_data, - ngx_http_fastcgi_st_padding -} ngx_http_fastcgi_state_e; - - -static ngx_http_fastcgi_request_start_t ngx_http_fastcgi_request_start = { - { 1, /* version */ - NGX_HTTP_FASTCGI_BEGIN_REQUEST, /* type */ - 0, /* request_id_hi */ - 1, /* request_id_lo */ - 0, /* content_length_hi */ - sizeof(ngx_http_fastcgi_begin_request_t), /* content_length_lo */ - 0, /* padding_length */ - 0 }, /* reserved */ - - { 0, /* role_hi */ - NGX_HTTP_FASTCGI_RESPONDER, /* role_lo */ - 0, /* NGX_HTTP_FASTCGI_KEEP_CONN */ /* flags */ - { 0, 0, 0, 0, 0 } }, /* reserved[5] */ - - { 1, /* version */ - NGX_HTTP_FASTCGI_PARAMS, /* type */ - 0, /* request_id_hi */ - 1 }, /* request_id_lo */ - -}; - - -static ngx_int_t ngx_http_upstream_check_add_timers(ngx_cycle_t *cycle); - -static ngx_int_t ngx_http_upstream_check_peek_one_byte(ngx_connection_t *c); - -static void ngx_http_upstream_check_begin_handler(ngx_event_t *event); -static void ngx_http_upstream_check_connect_handler(ngx_event_t *event); - -static void ngx_http_upstream_check_peek_handler(ngx_event_t *event); - -static void ngx_http_upstream_check_send_handler(ngx_event_t *event); -static void ngx_http_upstream_check_recv_handler(ngx_event_t *event); - -static void ngx_http_upstream_check_discard_handler(ngx_event_t *event); -static void ngx_http_upstream_check_dummy_handler(ngx_event_t *event); - -static ngx_int_t ngx_http_upstream_check_http_init( - ngx_http_upstream_check_peer_t *peer); -static ngx_int_t ngx_http_upstream_check_http_parse( - ngx_http_upstream_check_peer_t *peer); -static ngx_int_t ngx_http_upstream_check_parse_status_line( - ngx_http_upstream_check_ctx_t *ctx, ngx_buf_t *b, - ngx_http_status_t *status); -static void ngx_http_upstream_check_http_reinit( - ngx_http_upstream_check_peer_t *peer); - -static ngx_buf_t *ngx_http_upstream_check_create_fastcgi_request( - ngx_pool_t *pool, ngx_str_t *params, ngx_uint_t num); - -static ngx_int_t ngx_http_upstream_check_fastcgi_parse( - ngx_http_upstream_check_peer_t *peer); -static ngx_int_t ngx_http_upstream_check_fastcgi_process_record( - ngx_http_upstream_check_ctx_t *ctx, ngx_buf_t *b, - ngx_http_status_t *status); -static ngx_int_t ngx_http_upstream_check_parse_fastcgi_status( - ngx_http_upstream_check_ctx_t *ctx, ngx_buf_t *b, - ngx_http_status_t *status); - -static ngx_int_t ngx_http_upstream_check_ssl_hello_init( - ngx_http_upstream_check_peer_t *peer); -static ngx_int_t ngx_http_upstream_check_ssl_hello_parse( - ngx_http_upstream_check_peer_t *peer); -static void ngx_http_upstream_check_ssl_hello_reinit( - ngx_http_upstream_check_peer_t *peer); - -static ngx_int_t ngx_http_upstream_check_mysql_init( - ngx_http_upstream_check_peer_t *peer); -static ngx_int_t ngx_http_upstream_check_mysql_parse( - ngx_http_upstream_check_peer_t *peer); -static void ngx_http_upstream_check_mysql_reinit( - ngx_http_upstream_check_peer_t *peer); - -static ngx_int_t ngx_http_upstream_check_ajp_init( - ngx_http_upstream_check_peer_t *peer); -static ngx_int_t ngx_http_upstream_check_ajp_parse( - ngx_http_upstream_check_peer_t *peer); -static void ngx_http_upstream_check_ajp_reinit( - ngx_http_upstream_check_peer_t *peer); - -static void ngx_http_upstream_check_status_update( - ngx_http_upstream_check_peer_t *peer, - ngx_int_t result); - -static void ngx_http_upstream_check_clean_event( - ngx_http_upstream_check_peer_t *peer); - -static void ngx_http_upstream_check_timeout_handler(ngx_event_t *event); -static void ngx_http_upstream_check_finish_handler(ngx_event_t *event); - -static ngx_int_t ngx_http_upstream_check_need_exit(); -static void ngx_http_upstream_check_clear_all_events(); - -static ngx_int_t ngx_http_upstream_check_status_handler( - ngx_http_request_t *r); - -static void ngx_http_upstream_check_status_parse_args(ngx_http_request_t *r, - ngx_http_upstream_check_status_ctx_t *ctx); - -static ngx_int_t ngx_http_upstream_check_status_command_format( - ngx_http_upstream_check_status_ctx_t *ctx, ngx_str_t *value); -static ngx_int_t ngx_http_upstream_check_status_command_status( - ngx_http_upstream_check_status_ctx_t *ctx, ngx_str_t *value); - -static void ngx_http_upstream_check_status_html_format(ngx_buf_t *b, - ngx_http_upstream_check_peers_t *peers, ngx_uint_t flag); -static void ngx_http_upstream_check_status_csv_format(ngx_buf_t *b, - ngx_http_upstream_check_peers_t *peers, ngx_uint_t flag); -static void ngx_http_upstream_check_status_json_format(ngx_buf_t *b, - ngx_http_upstream_check_peers_t *peers, ngx_uint_t flag); - -static ngx_int_t ngx_http_upstream_check_addr_change_port(ngx_pool_t *pool, - ngx_addr_t *dst, ngx_addr_t *src, ngx_uint_t port); - -static ngx_check_conf_t *ngx_http_get_check_type_conf(ngx_str_t *str); - -static char *ngx_http_upstream_check(ngx_conf_t *cf, - ngx_command_t *cmd, void *conf); -static char *ngx_http_upstream_check_keepalive_requests(ngx_conf_t *cf, - ngx_command_t *cmd, void *conf); -static char *ngx_http_upstream_check_http_send(ngx_conf_t *cf, - ngx_command_t *cmd, void *conf); -static char *ngx_http_upstream_check_http_expect_alive(ngx_conf_t *cf, - ngx_command_t *cmd, void *conf); - -static char *ngx_http_upstream_check_fastcgi_params(ngx_conf_t *cf, - ngx_command_t *cmd, void *conf); - -static char *ngx_http_upstream_check_shm_size(ngx_conf_t *cf, - ngx_command_t *cmd, void *conf); - -static ngx_check_status_conf_t *ngx_http_get_check_status_format_conf( - ngx_str_t *str); -static char *ngx_http_upstream_check_status(ngx_conf_t *cf, - ngx_command_t *cmd, void *conf); - -static void *ngx_http_upstream_check_create_main_conf(ngx_conf_t *cf); -static char *ngx_http_upstream_check_init_main_conf(ngx_conf_t *cf, - void *conf); - -static void *ngx_http_upstream_check_create_srv_conf(ngx_conf_t *cf); -static char *ngx_http_upstream_check_init_srv_conf(ngx_conf_t *cf, void *conf); - -static void *ngx_http_upstream_check_create_loc_conf(ngx_conf_t *cf); -static char * ngx_http_upstream_check_merge_loc_conf(ngx_conf_t *cf, - void *parent, void *child); - -#define SHM_NAME_LEN 256 - -static char *ngx_http_upstream_check_init_shm(ngx_conf_t *cf, void *conf); - -static ngx_int_t ngx_http_upstream_check_get_shm_name(ngx_str_t *shm_name, - ngx_pool_t *pool, ngx_uint_t generation); -static ngx_shm_zone_t *ngx_shared_memory_find(ngx_cycle_t *cycle, - ngx_str_t *name, void *tag); -static ngx_http_upstream_check_peer_shm_t * -ngx_http_upstream_check_find_shm_peer(ngx_http_upstream_check_peers_shm_t *peers_shm, - ngx_addr_t *addr); - -static ngx_int_t ngx_http_upstream_check_init_shm_peer( - ngx_http_upstream_check_peer_shm_t *peer_shm, - ngx_http_upstream_check_peer_shm_t *opeer_shm, - ngx_uint_t init_down, ngx_pool_t *pool, ngx_str_t *peer_name); - -static ngx_int_t ngx_http_upstream_check_init_shm_zone( - ngx_shm_zone_t *shm_zone, void *data); - - -static ngx_int_t ngx_http_upstream_check_init_process(ngx_cycle_t *cycle); - - -static ngx_conf_bitmask_t ngx_check_http_expect_alive_masks[] = { - { ngx_string("http_2xx"), NGX_CHECK_HTTP_2XX }, - { ngx_string("http_3xx"), NGX_CHECK_HTTP_3XX }, - { ngx_string("http_4xx"), NGX_CHECK_HTTP_4XX }, - { ngx_string("http_5xx"), NGX_CHECK_HTTP_5XX }, - { ngx_null_string, 0 } -}; - - -static ngx_command_t ngx_http_upstream_check_commands[] = { - - { ngx_string("check"), - NGX_HTTP_UPS_CONF|NGX_CONF_1MORE, - ngx_http_upstream_check, - 0, - 0, - NULL }, - - { ngx_string("check_keepalive_requests"), - NGX_HTTP_UPS_CONF|NGX_CONF_TAKE1, - ngx_http_upstream_check_keepalive_requests, - 0, - 0, - NULL }, - - { ngx_string("check_http_send"), - NGX_HTTP_UPS_CONF|NGX_CONF_TAKE1, - ngx_http_upstream_check_http_send, - 0, - 0, - NULL }, - - { ngx_string("check_http_expect_alive"), - NGX_HTTP_UPS_CONF|NGX_CONF_1MORE, - ngx_http_upstream_check_http_expect_alive, - 0, - 0, - NULL }, - - { ngx_string("check_fastcgi_param"), - NGX_HTTP_UPS_CONF|NGX_CONF_TAKE2, - ngx_http_upstream_check_fastcgi_params, - 0, - 0, - NULL }, - - { ngx_string("check_shm_size"), - NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, - ngx_http_upstream_check_shm_size, - 0, - 0, - NULL }, - - { ngx_string("check_status"), - NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1|NGX_CONF_NOARGS, - ngx_http_upstream_check_status, - 0, - 0, - NULL }, - - ngx_null_command -}; - - -static ngx_http_module_t ngx_http_upstream_check_module_ctx = { - NULL, /* preconfiguration */ - NULL, /* postconfiguration */ - - ngx_http_upstream_check_create_main_conf,/* create main configuration */ - ngx_http_upstream_check_init_main_conf, /* init main configuration */ - - ngx_http_upstream_check_create_srv_conf, /* create server configuration */ - NULL, /* merge server configuration */ - - ngx_http_upstream_check_create_loc_conf, /* create location configuration */ - ngx_http_upstream_check_merge_loc_conf /* merge location configuration */ -}; - - -ngx_module_t ngx_http_upstream_check_module = { - NGX_MODULE_V1, - &ngx_http_upstream_check_module_ctx, /* module context */ - ngx_http_upstream_check_commands, /* module directives */ - NGX_HTTP_MODULE, /* module type */ - NULL, /* init master */ - NULL, /* init module */ - ngx_http_upstream_check_init_process, /* init process */ - NULL, /* init thread */ - NULL, /* exit thread */ - NULL, /* exit process */ - NULL, /* exit master */ - NGX_MODULE_V1_PADDING -}; - - -static ngx_str_t fastcgi_default_request; -static ngx_str_t fastcgi_default_params[] = { - ngx_string("REQUEST_METHOD"), ngx_string("GET"), - ngx_string("REQUEST_URI"), ngx_string("/"), - ngx_string("SCRIPT_FILENAME"), ngx_string("index.php"), -}; - - -#define NGX_SSL_RANDOM "NGX_HTTP_CHECK_SSL_HELLO\n\n\n\n" - -/* - * This is the SSLv3 CLIENT HELLO packet used in conjunction with the - * check type of ssl_hello to ensure that the remote server speaks SSL. - * - * Check RFC 2246 (TLSv1.0) sections A.3 and A.4 for details. - */ -static char sslv3_client_hello_pkt[] = { - "\x16" /* ContentType : 0x16 = Hanshake */ - "\x03\x01" /* ProtocolVersion : 0x0301 = TLSv1.0 */ - "\x00\x6f" /* ContentLength : 0x6f bytes after this one */ - "\x01" /* HanshakeType : 0x01 = CLIENT HELLO */ - "\x00\x00\x6b" /* HandshakeLength : 0x6b bytes after this one */ - "\x03\x03" /* Hello Version : 0x0303 = TLSv1.2 */ - "\x00\x00\x00\x00" /* Unix GMT Time (s) : filled with (@0x0B) */ - NGX_SSL_RANDOM /* Random : must be exactly 28 bytes */ - "\x00" /* Session ID length : empty (no session ID) */ - "\x00\x1a" /* Cipher Suite Length : \x1a bytes after this one */ - "\xc0\x2b" "\xc0\x2f" "\xcc\xa9" "\xcc\xa8" /* 13 modern ciphers */ - "\xc0\x0a" "\xc0\x09" "\xc0\x13" "\xc0\x14" - "\x00\x33" "\x00\x39" "\x00\x2f" "\x00\x35" - "\x00\x0a" - "\x01" /* Compression Length : 0x01 = 1 byte for types */ - "\x00" /* Compression Type : 0x00 = NULL compression */ - "\x00\x28" /* Extensions length */ - "\x00\x0a" /* EC extension */ - "\x00\x08" /* extension length */ - "\x00\x06" /* curves length */ - "\x00\x17" "\x00\x18" "\x00\x19" /* Three curves */ - "\x00\x0d" /* Signature extension */ - "\x00\x18" /* extension length */ - "\x00\x16" /* hash list length */ - "\x04\x01" "\x05\x01" "\x06\x01" "\x02\x01" /* 11 hash algorithms */ - "\x04\x03" "\x05\x03" "\x06\x03" "\x02\x03" - "\x05\x02" "\x04\x02" "\x02\x02" -}; - - -#define NGX_SSL_HANDSHAKE 0x16 -#define NGX_SSL_SERVER_HELLO 0x02 - - -#define NGX_AJP_CPING 0x0a -#define NGX_AJP_CPONG 0x09 - - -static char ngx_ajp_cping_packet[] = { - 0x12, 0x34, 0x00, 0x01, NGX_AJP_CPING, 0x00 -}; - -static char ngx_ajp_cpong_packet[] = { - 0x41, 0x42, 0x00, 0x01, NGX_AJP_CPONG -}; - - -static ngx_check_conf_t ngx_check_types[] = { - - { NGX_HTTP_CHECK_TCP, - ngx_string("tcp"), - ngx_null_string, - 0, - ngx_http_upstream_check_peek_handler, - ngx_http_upstream_check_peek_handler, - NULL, - NULL, - NULL, - 0, - 1 }, - - { NGX_HTTP_CHECK_HTTP, - ngx_string("http"), - ngx_string("GET / HTTP/1.0\r\n\r\n"), - NGX_CONF_BITMASK_SET | NGX_CHECK_HTTP_2XX | NGX_CHECK_HTTP_3XX, - ngx_http_upstream_check_send_handler, - ngx_http_upstream_check_recv_handler, - ngx_http_upstream_check_http_init, - ngx_http_upstream_check_http_parse, - ngx_http_upstream_check_http_reinit, - 1, - 1 }, - - { NGX_HTTP_CHECK_HTTP, - ngx_string("fastcgi"), - ngx_null_string, - 0, - ngx_http_upstream_check_send_handler, - ngx_http_upstream_check_recv_handler, - ngx_http_upstream_check_http_init, - ngx_http_upstream_check_fastcgi_parse, - ngx_http_upstream_check_http_reinit, - 1, - 0 }, - - { NGX_HTTP_CHECK_SSL_HELLO, - ngx_string("ssl_hello"), - ngx_string(sslv3_client_hello_pkt), - 0, - ngx_http_upstream_check_send_handler, - ngx_http_upstream_check_recv_handler, - ngx_http_upstream_check_ssl_hello_init, - ngx_http_upstream_check_ssl_hello_parse, - ngx_http_upstream_check_ssl_hello_reinit, - 1, - 0 }, - - { NGX_HTTP_CHECK_MYSQL, - ngx_string("mysql"), - ngx_null_string, - 0, - ngx_http_upstream_check_send_handler, - ngx_http_upstream_check_recv_handler, - ngx_http_upstream_check_mysql_init, - ngx_http_upstream_check_mysql_parse, - ngx_http_upstream_check_mysql_reinit, - 1, - 0 }, - - { NGX_HTTP_CHECK_AJP, - ngx_string("ajp"), - ngx_string(ngx_ajp_cping_packet), - 0, - ngx_http_upstream_check_send_handler, - ngx_http_upstream_check_recv_handler, - ngx_http_upstream_check_ajp_init, - ngx_http_upstream_check_ajp_parse, - ngx_http_upstream_check_ajp_reinit, - 1, - 0 }, - - { 0, - ngx_null_string, - ngx_null_string, - 0, - NULL, - NULL, - NULL, - NULL, - NULL, - 0, - 0 } -}; - - -static ngx_check_status_conf_t ngx_check_status_formats[] = { - - { ngx_string("html"), - ngx_string("text/html"), - ngx_http_upstream_check_status_html_format }, - - { ngx_string("csv"), - ngx_string("text/plain"), - ngx_http_upstream_check_status_csv_format }, - - { ngx_string("json"), - ngx_string("application/json"), /* RFC 4627 */ - ngx_http_upstream_check_status_json_format }, - - { ngx_null_string, ngx_null_string, NULL } -}; - - -static ngx_check_status_command_t ngx_check_status_commands[] = { - - { ngx_string("format"), - ngx_http_upstream_check_status_command_format }, - - { ngx_string("status"), - ngx_http_upstream_check_status_command_status }, - - { ngx_null_string, NULL } -}; - - -static ngx_uint_t ngx_http_upstream_check_shm_generation = 0; -static ngx_http_upstream_check_peers_t *check_peers_ctx = NULL; - - -ngx_uint_t -ngx_http_upstream_check_add_peer(ngx_conf_t *cf, - ngx_http_upstream_srv_conf_t *us, ngx_addr_t *peer_addr) -{ - ngx_http_upstream_check_peer_t *peer; - ngx_http_upstream_check_peers_t *peers; - ngx_http_upstream_check_srv_conf_t *ucscf; - ngx_http_upstream_check_main_conf_t *ucmcf; - - if (us->srv_conf == NULL) { - return NGX_ERROR; - } - - ucscf = ngx_http_conf_upstream_srv_conf(us, ngx_http_upstream_check_module); - - if(ucscf->check_interval == 0) { - return NGX_ERROR; - } - - ucmcf = ngx_http_conf_get_module_main_conf(cf, - ngx_http_upstream_check_module); - peers = ucmcf->peers; - - peer = ngx_array_push(&peers->peers); - if (peer == NULL) { - return NGX_ERROR; - } - - ngx_memzero(peer, sizeof(ngx_http_upstream_check_peer_t)); - - peer->index = peers->peers.nelts - 1; - peer->conf = ucscf; - peer->upstream_name = &us->host; - peer->peer_addr = peer_addr; - - if (ucscf->port) { - peer->check_peer_addr = ngx_pcalloc(cf->pool, sizeof(ngx_addr_t)); - if (peer->check_peer_addr == NULL) { - return NGX_ERROR; - } - - if (ngx_http_upstream_check_addr_change_port(cf->pool, - peer->check_peer_addr, peer_addr, ucscf->port) - != NGX_OK) { - - return NGX_ERROR; - } - - } else { - peer->check_peer_addr = peer->peer_addr; - } - - peers->checksum += - ngx_murmur_hash2(peer_addr->name.data, peer_addr->name.len); - - return peer->index; -} - - -static ngx_int_t -ngx_http_upstream_check_addr_change_port(ngx_pool_t *pool, ngx_addr_t *dst, - ngx_addr_t *src, ngx_uint_t port) -{ - size_t len; - u_char *p; - struct sockaddr_in *sin; -#if (NGX_HAVE_INET6) - struct sockaddr_in6 *sin6; -#endif - - dst->socklen = src->socklen; - dst->sockaddr = ngx_palloc(pool, dst->socklen); - if (dst->sockaddr == NULL) { - return NGX_ERROR; - } - - ngx_memcpy(dst->sockaddr, src->sockaddr, dst->socklen); - - switch (dst->sockaddr->sa_family) { - - case AF_INET: - - len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1; - sin = (struct sockaddr_in *) dst->sockaddr; - sin->sin_port = htons(port); - - break; - -#if (NGX_HAVE_INET6) - case AF_INET6: - - len = NGX_INET6_ADDRSTRLEN + sizeof(":65535") - 1; - sin6 = (struct sockaddr_in6 *) dst->sockaddr; - sin6->sin6_port = htons(port); - - break; -#endif - - default: - return NGX_ERROR; - } - - p = ngx_pnalloc(pool, len); - if (p == NULL) { - return NGX_ERROR; - } - -#if (nginx_version >= 1005012) - len = ngx_sock_ntop(dst->sockaddr, dst->socklen, p, len, 1); -#else - len = ngx_sock_ntop(dst->sockaddr, p, len, 1); -#endif - - dst->name.len = len; - dst->name.data = p; - - return NGX_OK; -} - - -ngx_uint_t -ngx_http_upstream_check_peer_down(ngx_uint_t index) -{ - ngx_http_upstream_check_peer_t *peer; - - if (check_peers_ctx == NULL || index >= check_peers_ctx->peers.nelts) { - return 0; - } - - peer = check_peers_ctx->peers.elts; - - return (peer[index].shm->down); -} - - -/* TODO: this interface can count each peer's busyness */ -void -ngx_http_upstream_check_get_peer(ngx_uint_t index) -{ - ngx_http_upstream_check_peer_t *peer; - - if (check_peers_ctx == NULL || index >= check_peers_ctx->peers.nelts) { - return; - } - - peer = check_peers_ctx->peers.elts; - - ngx_shmtx_lock(&peer[index].shm->mutex); - - peer[index].shm->busyness++; - peer[index].shm->access_count++; - - ngx_shmtx_unlock(&peer[index].shm->mutex); -} - - -void -ngx_http_upstream_check_free_peer(ngx_uint_t index) -{ - ngx_http_upstream_check_peer_t *peer; - - if (check_peers_ctx == NULL || index >= check_peers_ctx->peers.nelts) { - return; - } - - peer = check_peers_ctx->peers.elts; - - ngx_shmtx_lock(&peer[index].shm->mutex); - - if (peer[index].shm->busyness > 0) { - peer[index].shm->busyness--; - } - - ngx_shmtx_unlock(&peer[index].shm->mutex); -} - - -static ngx_int_t -ngx_http_upstream_check_add_timers(ngx_cycle_t *cycle) -{ - ngx_uint_t i; - ngx_msec_t t, delay; - ngx_check_conf_t *cf; - ngx_http_upstream_check_peer_t *peer; - ngx_http_upstream_check_peers_t *peers; - ngx_http_upstream_check_srv_conf_t *ucscf; - ngx_http_upstream_check_peer_shm_t *peer_shm; - ngx_http_upstream_check_peers_shm_t *peers_shm; - - peers = check_peers_ctx; - if (peers == NULL) { - return NGX_OK; - } - - peers_shm = peers->peers_shm; - if (peers_shm == NULL) { - return NGX_OK; - } - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cycle->log, 0, - "http check upstream init_process, shm_name: %V, " - "peer number: %ud", - &peers->check_shm_name, - peers->peers.nelts); - - srandom(ngx_pid); - - peer = peers->peers.elts; - peer_shm = peers_shm->peers; - - for (i = 0; i < peers->peers.nelts; i++) { - peer[i].shm = &peer_shm[i]; - - peer[i].check_ev.handler = ngx_http_upstream_check_begin_handler; - peer[i].check_ev.log = cycle->log; - peer[i].check_ev.data = &peer[i]; - peer[i].check_ev.timer_set = 0; - - peer[i].check_timeout_ev.handler = - ngx_http_upstream_check_timeout_handler; - peer[i].check_timeout_ev.log = cycle->log; - peer[i].check_timeout_ev.data = &peer[i]; - peer[i].check_timeout_ev.timer_set = 0; - - ucscf = peer[i].conf; - cf = ucscf->check_type_conf; - - if (cf->need_pool) { - peer[i].pool = ngx_create_pool(ngx_pagesize, cycle->log); - if (peer[i].pool == NULL) { - return NGX_ERROR; - } - } - - peer[i].send_handler = cf->send_handler; - peer[i].recv_handler = cf->recv_handler; - - peer[i].init = cf->init; - peer[i].parse = cf->parse; - peer[i].reinit = cf->reinit; - - /* - * We add a random start time here, since we don't want to trigger - * the check events too close to each other at the beginning. - */ - delay = ucscf->check_interval > 1000 ? ucscf->check_interval : 1000; - t = ngx_random() % delay; - - ngx_add_timer(&peer[i].check_ev, t); - } - - return NGX_OK; -} - - -static void -ngx_http_upstream_check_begin_handler(ngx_event_t *event) -{ - ngx_msec_t interval; - ngx_http_upstream_check_peer_t *peer; - ngx_http_upstream_check_peers_t *peers; - ngx_http_upstream_check_srv_conf_t *ucscf; - ngx_http_upstream_check_peers_shm_t *peers_shm; - - if (ngx_http_upstream_check_need_exit()) { - return; - } - - peers = check_peers_ctx; - if (peers == NULL) { - return; - } - - peers_shm = peers->peers_shm; - if (peers_shm == NULL) { - return; - } - - peer = event->data; - ucscf = peer->conf; - - ngx_add_timer(event, ucscf->check_interval / 2); - - /* This process is processing this peer now. */ - if ((peer->shm->owner == ngx_pid || - (peer->pc.connection != NULL) || - peer->check_timeout_ev.timer_set)) { - return; - } - - interval = ngx_current_msec - peer->shm->access_time; - ngx_log_debug5(NGX_LOG_DEBUG_HTTP, event->log, 0, - "http check begin handler index: %ui, owner: %P, " - "ngx_pid: %P, interval: %M, check_interval: %M", - peer->index, peer->shm->owner, - ngx_pid, interval, - ucscf->check_interval); - - ngx_shmtx_lock(&peer->shm->mutex); - - if (peers_shm->generation != ngx_http_upstream_check_shm_generation) { - ngx_shmtx_unlock(&peer->shm->mutex); - return; - } - - if ((interval >= ucscf->check_interval) - && (peer->shm->owner == NGX_INVALID_PID)) - { - peer->shm->owner = ngx_pid; - - } else if (interval >= (ucscf->check_interval << 4)) { - - /* - * If the check peer has been untouched for 2^4 times of - * the check interval, activate the current timer. - * Sometimes, the checking process may disappear - * in some circumstances, and the clean event will never - * be triggered. - */ - peer->shm->owner = ngx_pid; - peer->shm->access_time = ngx_current_msec; - } - - ngx_shmtx_unlock(&peer->shm->mutex); - - if (peer->shm->owner == ngx_pid) { - ngx_http_upstream_check_connect_handler(event); - } -} - - -static void -ngx_http_upstream_check_connect_handler(ngx_event_t *event) -{ - ngx_int_t rc; - ngx_connection_t *c; - ngx_http_upstream_check_peer_t *peer; - ngx_http_upstream_check_srv_conf_t *ucscf; - - if (ngx_http_upstream_check_need_exit()) { - return; - } - - peer = event->data; - ucscf = peer->conf; - - if (peer->pc.connection != NULL) { - c = peer->pc.connection; - if ((rc = ngx_http_upstream_check_peek_one_byte(c)) == NGX_OK) { - goto upstream_check_connect_done; - } else { - ngx_close_connection(c); - peer->pc.connection = NULL; - } - } - ngx_memzero(&peer->pc, sizeof(ngx_peer_connection_t)); - - peer->pc.sockaddr = peer->check_peer_addr->sockaddr; - peer->pc.socklen = peer->check_peer_addr->socklen; - peer->pc.name = &peer->check_peer_addr->name; - - peer->pc.get = ngx_event_get_peer; - peer->pc.log = event->log; - peer->pc.log_error = NGX_ERROR_ERR; - - peer->pc.cached = 0; - peer->pc.connection = NULL; - - rc = ngx_event_connect_peer(&peer->pc); - - if (rc == NGX_ERROR || rc == NGX_DECLINED) { - ngx_http_upstream_check_status_update(peer, 0); - ngx_http_upstream_check_clean_event(peer); - return; - } - - /* NGX_OK or NGX_AGAIN */ - c = peer->pc.connection; - c->data = peer; - c->log = peer->pc.log; - c->sendfile = 0; - c->read->log = c->log; - c->write->log = c->log; - c->pool = peer->pool; - -upstream_check_connect_done: - peer->state = NGX_HTTP_CHECK_CONNECT_DONE; - - c->write->handler = peer->send_handler; - c->read->handler = peer->recv_handler; - - ngx_add_timer(&peer->check_timeout_ev, ucscf->check_timeout); - - /* The kqueue's loop interface needs it. */ - if (rc == NGX_OK) { - c->write->handler(c->write); - } -} - -static ngx_int_t -ngx_http_upstream_check_peek_one_byte(ngx_connection_t *c) -{ - char buf[1]; - ngx_int_t n; - ngx_err_t err; - - n = recv(c->fd, buf, 1, MSG_PEEK); - err = ngx_socket_errno; - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, err, - "http check upstream recv(): %i, fd: %d", - n, c->fd); - - if (n == 1 || (n == -1 && err == NGX_EAGAIN)) { - return NGX_OK; - } else { - return NGX_ERROR; - } -} - -static void -ngx_http_upstream_check_peek_handler(ngx_event_t *event) -{ - ngx_connection_t *c; - ngx_http_upstream_check_peer_t *peer; - - if (ngx_http_upstream_check_need_exit()) { - return; - } - - c = event->data; - peer = c->data; - - if (ngx_http_upstream_check_peek_one_byte(c) == NGX_OK) { - ngx_http_upstream_check_status_update(peer, 1); - - } else { - c->error = 1; - ngx_http_upstream_check_status_update(peer, 0); - } - - ngx_http_upstream_check_clean_event(peer); - - ngx_http_upstream_check_finish_handler(event); -} - - -static void -ngx_http_upstream_check_discard_handler(ngx_event_t *event) -{ - u_char buf[4096]; - ssize_t size; - ngx_connection_t *c; - ngx_http_upstream_check_peer_t *peer; - - c = event->data; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, - "upstream check discard handler"); - - if (ngx_http_upstream_check_need_exit()) { - return; - } - - peer = c->data; - - while (1) { - size = c->recv(c, buf, 4096); - - if (size > 0) { - continue; - - } else if (size == NGX_AGAIN) { - break; - - } else { - if (size == 0) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, - "peer closed its half side of the connection"); - } - - goto check_discard_fail; - } - } - - if (ngx_handle_read_event(c->read, 0) != NGX_OK) { - goto check_discard_fail; - } - - return; - - check_discard_fail: - c->error = 1; - ngx_http_upstream_check_clean_event(peer); -} - - -static void -ngx_http_upstream_check_dummy_handler(ngx_event_t *event) -{ - return; -} - - -static void -ngx_http_upstream_check_send_handler(ngx_event_t *event) -{ - ssize_t size; - ngx_connection_t *c; - ngx_http_upstream_check_ctx_t *ctx; - ngx_http_upstream_check_peer_t *peer; - - if (ngx_http_upstream_check_need_exit()) { - return; - } - - c = event->data; - peer = c->data; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http check send."); - - if (c->pool == NULL) { - ngx_log_error(NGX_LOG_ERR, event->log, 0, - "check pool NULL with peer: %V ", - &peer->check_peer_addr->name); - - goto check_send_fail; - } - - if (peer->state != NGX_HTTP_CHECK_CONNECT_DONE) { - if (ngx_handle_write_event(c->write, 0) != NGX_OK) { - - ngx_log_error(NGX_LOG_ERR, event->log, 0, - "check handle write event error with peer: %V ", - &peer->check_peer_addr->name); - - goto check_send_fail; - } - - return; - } - - if (peer->check_data == NULL) { - - peer->check_data = ngx_pcalloc(peer->pool, - sizeof(ngx_http_upstream_check_ctx_t)); - if (peer->check_data == NULL) { - goto check_send_fail; - } - - if (peer->init == NULL || peer->init(peer) != NGX_OK) { - - ngx_log_error(NGX_LOG_ERR, event->log, 0, - "check init error with peer: %V ", - &peer->check_peer_addr->name); - - goto check_send_fail; - } - } - - ctx = peer->check_data; - - while (ctx->send.pos < ctx->send.last) { - - size = c->send(c, ctx->send.pos, ctx->send.last - ctx->send.pos); - -#if (NGX_DEBUG) - { - ngx_err_t err; - - err = (size >=0) ? 0 : ngx_socket_errno; - ngx_log_error(NGX_LOG_DEBUG, ngx_cycle->log, err, - "http check send size: %z, total: %z", - size, ctx->send.last - ctx->send.pos); - } -#endif - - if (size > 0) { - ctx->send.pos += size; - } else if (size == 0 || size == NGX_AGAIN) { - return; - } else { - c->error = 1; - goto check_send_fail; - } - } - - if (ctx->send.pos == ctx->send.last) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http check send done."); - peer->state = NGX_HTTP_CHECK_SEND_DONE; - c->requests++; - } - - return; - -check_send_fail: - ngx_http_upstream_check_status_update(peer, 0); - ngx_http_upstream_check_clean_event(peer); -} - - -static void -ngx_http_upstream_check_recv_handler(ngx_event_t *event) -{ - u_char *new_buf; - ssize_t size, n; - ngx_int_t rc; - ngx_connection_t *c; - ngx_http_upstream_check_ctx_t *ctx; - ngx_http_upstream_check_peer_t *peer; - - if (ngx_http_upstream_check_need_exit()) { - return; - } - - c = event->data; - peer = c->data; - - if (peer->state != NGX_HTTP_CHECK_SEND_DONE) { - - if (ngx_handle_read_event(c->read, 0) != NGX_OK) { - goto check_recv_fail; - } - - return; - } - - ctx = peer->check_data; - - if (ctx->recv.start == NULL) { - /* 1/2 of the page_size, is it enough? */ - ctx->recv.start = ngx_palloc(c->pool, ngx_pagesize / 2); - if (ctx->recv.start == NULL) { - goto check_recv_fail; - } - - ctx->recv.last = ctx->recv.pos = ctx->recv.start; - ctx->recv.end = ctx->recv.start + ngx_pagesize / 2; - } - - while (1) { - n = ctx->recv.end - ctx->recv.last; - - /* buffer not big enough? enlarge it by twice */ - if (n == 0) { - size = ctx->recv.end - ctx->recv.start; - new_buf = ngx_palloc(c->pool, size * 2); - if (new_buf == NULL) { - goto check_recv_fail; - } - - ngx_memcpy(new_buf, ctx->recv.start, size); - - ctx->recv.pos = ctx->recv.start = new_buf; - ctx->recv.last = new_buf + size; - ctx->recv.end = new_buf + size * 2; - - n = ctx->recv.end - ctx->recv.last; - } - - size = c->recv(c, ctx->recv.last, n); - -#if (NGX_DEBUG) - { - ngx_err_t err; - - err = (size >= 0) ? 0 : ngx_socket_errno; - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, err, - "http check recv size: %z, peer: %V ", - size, &peer->check_peer_addr->name); - } -#endif - - if (size > 0) { - ctx->recv.last += size; - continue; - } else if (size == 0 || size == NGX_AGAIN) { - break; - } else { - c->error = 1; - goto check_recv_fail; - } - } - - rc = peer->parse(peer); - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, - "http check parse rc: %i, peer: %V ", - rc, &peer->check_peer_addr->name); - - switch (rc) { - - case NGX_AGAIN: - /* The peer has closed its half side of the connection. */ - if (size == 0) { - ngx_http_upstream_check_status_update(peer, 0); - c->error = 1; - break; - } - - return; - - case NGX_ERROR: - ngx_log_error(NGX_LOG_ERR, event->log, 0, - "check protocol %V error with peer: %V ", - &peer->conf->check_type_conf->name, - &peer->check_peer_addr->name); - - ngx_http_upstream_check_status_update(peer, 0); - break; - - case NGX_OK: - /* fall through */ - - default: - ngx_http_upstream_check_status_update(peer, 1); - break; - } - - peer->state = NGX_HTTP_CHECK_RECV_DONE; - ngx_http_upstream_check_clean_event(peer); - return; - -check_recv_fail: - ngx_http_upstream_check_status_update(peer, 0); - ngx_http_upstream_check_clean_event(peer); -} - - -static ngx_int_t -ngx_http_upstream_check_http_init(ngx_http_upstream_check_peer_t *peer) -{ - ngx_http_upstream_check_ctx_t *ctx; - ngx_http_upstream_check_srv_conf_t *ucscf; - - ctx = peer->check_data; - ucscf = peer->conf; - - ctx->send.start = ctx->send.pos = (u_char *)ucscf->send.data; - ctx->send.end = ctx->send.last = ctx->send.start + ucscf->send.len; - - ctx->recv.start = ctx->recv.pos = NULL; - ctx->recv.end = ctx->recv.last = NULL; - - ctx->state = 0; - - ngx_memzero(&ctx->status, sizeof(ngx_http_status_t)); - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_upstream_check_http_parse(ngx_http_upstream_check_peer_t *peer) -{ - ngx_int_t rc; - ngx_uint_t code, code_n; - ngx_http_upstream_check_ctx_t *ctx; - ngx_http_upstream_check_srv_conf_t *ucscf; - - ucscf = peer->conf; - ctx = peer->check_data; - - if ((ctx->recv.last - ctx->recv.pos) > 0) { - - rc = ngx_http_upstream_check_parse_status_line(ctx, - &ctx->recv, - &ctx->status); - if (rc == NGX_AGAIN) { - return rc; - } - - if (rc == NGX_ERROR) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, - "http parse status line error with peer: %V ", - &peer->check_peer_addr->name); - return rc; - } - - code = ctx->status.code; - - if (code >= 200 && code < 300) { - code_n = NGX_CHECK_HTTP_2XX; - } else if (code >= 300 && code < 400) { - code_n = NGX_CHECK_HTTP_3XX; - } else if (code >= 400 && code < 500) { - peer->pc.connection->error = 1; - code_n = NGX_CHECK_HTTP_4XX; - } else if (code >= 500 && code < 600) { - peer->pc.connection->error = 1; - code_n = NGX_CHECK_HTTP_5XX; - } else { - peer->pc.connection->error = 1; - code_n = NGX_CHECK_HTTP_ERR; - } - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "http_parse: code_n: %ui, conf: %ui", - code_n, ucscf->code.status_alive); - - if (code_n & ucscf->code.status_alive) { - return NGX_OK; - } else { - return NGX_ERROR; - } - } else { - return NGX_AGAIN; - } - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_upstream_check_fastcgi_process_record( - ngx_http_upstream_check_ctx_t *ctx, ngx_buf_t *b, ngx_http_status_t *status) -{ - u_char ch, *p; - ngx_http_fastcgi_state_e state; - - state = ctx->state; - - for (p = b->pos; p < b->last; p++) { - - ch = *p; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "http fastcgi record byte: %02Xd", ch); - - switch (state) { - - case ngx_http_fastcgi_st_version: - if (ch != 1) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, - "upstream sent unsupported FastCGI " - "protocol version: %d", ch); - return NGX_ERROR; - } - state = ngx_http_fastcgi_st_type; - break; - - case ngx_http_fastcgi_st_type: - switch (ch) { - case NGX_HTTP_FASTCGI_STDOUT: - case NGX_HTTP_FASTCGI_STDERR: - case NGX_HTTP_FASTCGI_END_REQUEST: - status->code = (ngx_uint_t) ch; - break; - default: - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, - "upstream sent invalid FastCGI " - "record type: %d", ch); - return NGX_ERROR; - - } - state = ngx_http_fastcgi_st_request_id_hi; - break; - - /* we support the single request per connection */ - - case ngx_http_fastcgi_st_request_id_hi: - if (ch != 0) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, - "upstream sent unexpected FastCGI " - "request id high byte: %d", ch); - return NGX_ERROR; - } - state = ngx_http_fastcgi_st_request_id_lo; - break; - - case ngx_http_fastcgi_st_request_id_lo: - if (ch != 1) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, - "upstream sent unexpected FastCGI " - "request id low byte: %d", ch); - return NGX_ERROR; - } - state = ngx_http_fastcgi_st_content_length_hi; - break; - - case ngx_http_fastcgi_st_content_length_hi: - ctx->length = ch << 8; - state = ngx_http_fastcgi_st_content_length_lo; - break; - - case ngx_http_fastcgi_st_content_length_lo: - ctx->length |= (size_t) ch; - state = ngx_http_fastcgi_st_padding_length; - break; - - case ngx_http_fastcgi_st_padding_length: - ctx->padding = (size_t) ch; - state = ngx_http_fastcgi_st_reserved; - break; - - case ngx_http_fastcgi_st_reserved: - state = ngx_http_fastcgi_st_data; - - b->pos = p + 1; - ctx->state = state; - - return NGX_OK; - - /* suppress warning */ - case ngx_http_fastcgi_st_data: - case ngx_http_fastcgi_st_padding: - break; - } - } - - ctx->state = state; - - return NGX_AGAIN; -} - - -static ngx_int_t -ngx_http_upstream_check_fastcgi_parse(ngx_http_upstream_check_peer_t *peer) -{ - ngx_int_t rc; - ngx_flag_t done; - ngx_uint_t type, code, code_n; - ngx_http_upstream_check_ctx_t *ctx; - ngx_http_upstream_check_srv_conf_t *ucscf; - - ucscf = peer->conf; - ctx = peer->check_data; - - if ((ctx->recv.last - ctx->recv.pos) <= 0) { - return NGX_AGAIN; - } - - done = 0; - - for ( ;; ) { - - if (ctx->state < ngx_http_fastcgi_st_data) { - rc = ngx_http_upstream_check_fastcgi_process_record(ctx, - &ctx->recv, &ctx->status); - - type = ctx->status.code; - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "fastcgi_parse rc: [%i], type: [%ui]", rc, type); - - if (rc == NGX_AGAIN) { - return rc; - } - - if (rc == NGX_ERROR) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, - "check fastcgi parse status line error with peer: %V", - &peer->check_peer_addr->name); - - return rc; - } - - if (type != NGX_HTTP_FASTCGI_STDOUT - && type != NGX_HTTP_FASTCGI_STDERR) - { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, - "check fastcgi sent unexpected FastCGI record: %d", type); - - return NGX_ERROR; - } - - if (type == NGX_HTTP_FASTCGI_STDOUT && ctx->length == 0) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, - "check fastcgi prematurely closed FastCGI stdout"); - - return NGX_ERROR; - } - } - - if (ctx->state == ngx_http_fastcgi_st_padding) { - - if (ctx->recv.pos + ctx->padding < ctx->recv.last) { - ctx->status.code = ngx_http_fastcgi_st_version; - ctx->recv.pos += ctx->padding; - - continue; - } - - if (ctx->recv.pos + ctx->padding == ctx->recv.last) { - ctx->status.code = ngx_http_fastcgi_st_version; - ctx->recv.pos = ctx->recv.last; - - return NGX_AGAIN; - } - - ctx->padding -= ctx->recv.last - ctx->recv.pos; - ctx->recv.pos = ctx->recv.last; - - return NGX_AGAIN; - } - - if (ctx->status.code == NGX_HTTP_FASTCGI_STDERR) { - - ngx_log_error(NGX_LOG_WARN, ngx_cycle->log, 0, - "fastcgi check error"); - - return NGX_ERROR; - } - - /* ctx->status.code == NGX_HTTP_FASTCGI_STDOUT */ - - if (ctx->recv.pos + ctx->length < ctx->recv.last) { - ctx->recv.last = ctx->recv.pos + ctx->length; - } else { - return NGX_ERROR; - } - - ctx->status.code = 0; - - for ( ;; ) { - rc = ngx_http_upstream_check_parse_fastcgi_status(ctx, - &ctx->recv, - &ctx->status); - ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0, - "fastcgi http parse status line rc: %i ", rc); - - if (rc == NGX_ERROR) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, - "fastcgi http parse status line error with peer: %V ", - &peer->check_peer_addr->name); - return NGX_ERROR; - } - - if (rc == NGX_AGAIN) { - break; - } - - if (rc == NGX_DONE) { - done = 1; - ngx_log_error(NGX_LOG_DEBUG, ngx_cycle->log, 0, - "fastcgi http parse status: %i", - ctx->status.code); - break; - } - - /* rc = NGX_OK */ - } - - if (ucscf->code.status_alive == 0 || done == 0) { - return NGX_OK; - } - - code = ctx->status.code; - - if (code >= 200 && code < 300) { - code_n = NGX_CHECK_HTTP_2XX; - } else if (code >= 300 && code < 400) { - code_n = NGX_CHECK_HTTP_3XX; - } else if (code >= 400 && code < 500) { - code_n = NGX_CHECK_HTTP_4XX; - } else if (code >= 500 && code < 600) { - code_n = NGX_CHECK_HTTP_5XX; - } else { - code_n = NGX_CHECK_HTTP_ERR; - } - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "fastcgi http_parse: code_n: %ui, conf: %ui", - code_n, ucscf->code.status_alive); - - if (code_n & ucscf->code.status_alive) { - return NGX_OK; - } else { - return NGX_ERROR; - } - - } - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_upstream_check_parse_fastcgi_status(ngx_http_upstream_check_ctx_t *ctx, - ngx_buf_t *b, ngx_http_status_t *status) -{ - u_char c, ch, *p, *name_s, *name_e; - ngx_flag_t find; - - enum { - sw_start = 0, - sw_name, - sw_space_before_value, - sw_value, - sw_space_after_value, - sw_ignore_line, - sw_almost_done, - sw_header_almost_done - } state; - - /* the last '\0' is not needed because string is zero terminated */ - - static u_char lowcase[] = - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0-\0\0" "0123456789\0\0\0\0\0\0" - "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0\0" - "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; - - status->count = 0; - status->code = 0; - find = 0; - name_s = name_e = NULL; - state = sw_start; - - for (p = b->pos; p < b->last; p++) { - ch = *p; - - switch (state) { - - /* first char */ - case sw_start: - - switch (ch) { - case CR: - state = sw_header_almost_done; - break; - case LF: - goto header_done; - default: - state = sw_name; - - c = lowcase[ch]; - - if (c) { - name_s = p; - break; - } - - if (ch == '\0') { - return NGX_ERROR; - } - - - break; - } - - break; - - /* header name */ - case sw_name: - c = lowcase[ch]; - - if (c) { - break; - } - - if (ch == ':') { - name_e = p; -#if (NGX_DEBUG) - ngx_str_t name; - name.data = name_s; - name.len = name_e - name_s; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "fastcgi header: %V", &name); -#endif - state = sw_space_before_value; - - if (ngx_strncasecmp(name_s, (u_char *) "status", - name_e - name_s) - == 0) - { - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "find status header"); - - find = 1; - } - - break; - } - - if (ch == CR) { - state = sw_almost_done; - break; - } - - if (ch == LF) { - goto done; - } - - /* IIS may send the duplicate "HTTP/1.1 ..." lines */ - if (ch == '\0') { - return NGX_ERROR; - } - - break; - - /* space* before header value */ - case sw_space_before_value: - switch (ch) { - case ' ': - break; - case CR: - state = sw_almost_done; - break; - case LF: - goto done; - case '\0': - return NGX_ERROR; - default: - state = sw_value; - if (find) { - if (ch < '1' || ch > '9') { - return NGX_ERROR; - } - - status->code = status->code * 10 + ch - '0'; - if (status->count++ != 0) { - return NGX_ERROR; - } - } - - break; - } - - break; - - /* header value */ - case sw_value: - - if (find) { - if (ch < '0' || ch > '9') { - return NGX_ERROR; - } - - status->code = status->code * 10 + ch - '0'; - - if (++status->count == 3) { - return NGX_DONE; - } - } - - switch (ch) { - case ' ': - state = sw_space_after_value; - break; - case CR: - state = sw_almost_done; - break; - case LF: - goto done; - case '\0': - return NGX_ERROR; - } - - break; - - /* space* before end of header line */ - case sw_space_after_value: - switch (ch) { - case ' ': - break; - case CR: - state = sw_almost_done; - break; - case LF: - state = sw_start; - break; - case '\0': - return NGX_ERROR; - default: - state = sw_value; - break; - } - break; - - /* ignore header line */ - case sw_ignore_line: - switch (ch) { - case LF: - state = sw_start; - break; - default: - break; - } - break; - - /* end of header line */ - case sw_almost_done: - switch (ch) { - case LF: - goto done; - case CR: - break; - default: - return NGX_ERROR; - } - break; - - /* end of header */ - case sw_header_almost_done: - switch (ch) { - case LF: - goto header_done; - default: - return NGX_ERROR; - } - } - } - - b->pos = p; - ctx->state = state; - - return NGX_AGAIN; - -done: - - b->pos = p + 1; - ctx->state = sw_start; - - return NGX_OK; - -header_done: - - b->pos = p + 1; - ctx->state = sw_start; - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_upstream_check_parse_status_line(ngx_http_upstream_check_ctx_t *ctx, - ngx_buf_t *b, ngx_http_status_t *status) -{ - u_char ch, *p; - enum { - sw_start = 0, - sw_H, - sw_HT, - sw_HTT, - sw_HTTP, - sw_first_major_digit, - sw_major_digit, - sw_first_minor_digit, - sw_minor_digit, - sw_status, - sw_space_after_status, - sw_status_text, - sw_almost_done - } state; - - state = ctx->state; - - for (p = b->pos; p < b->last; p++) { - ch = *p; - - switch (state) { - - /* "HTTP/" */ - case sw_start: - if (ch != 'H') { - return NGX_ERROR; - } - - state = sw_H; - break; - - case sw_H: - if (ch != 'T') { - return NGX_ERROR; - } - - state = sw_HT; - break; - - case sw_HT: - if (ch != 'T') { - return NGX_ERROR; - } - - state = sw_HTT; - break; - - case sw_HTT: - if (ch != 'P') { - return NGX_ERROR; - } - - state = sw_HTTP; - break; - - case sw_HTTP: - if (ch != '/') { - return NGX_ERROR; - } - - state = sw_first_major_digit; - break; - - /* the first digit of major HTTP version */ - case sw_first_major_digit: - if (ch < '1' || ch > '9') { - return NGX_ERROR; - } - - state = sw_major_digit; - break; - - /* the major HTTP version or dot */ - case sw_major_digit: - if (ch == '.') { - state = sw_first_minor_digit; - break; - } - - if (ch < '0' || ch > '9') { - return NGX_ERROR; - } - - break; - - /* the first digit of minor HTTP version */ - case sw_first_minor_digit: - if (ch < '0' || ch > '9') { - return NGX_ERROR; - } - - state = sw_minor_digit; - break; - - /* the minor HTTP version or the end of the request line */ - case sw_minor_digit: - if (ch == ' ') { - state = sw_status; - break; - } - - if (ch < '0' || ch > '9') { - return NGX_ERROR; - } - - break; - - /* HTTP status code */ - case sw_status: - if (ch == ' ') { - break; - } - - if (ch < '0' || ch > '9') { - return NGX_ERROR; - } - - status->code = status->code * 10 + ch - '0'; - - if (++status->count == 3) { - state = sw_space_after_status; - status->start = p - 2; - } - - break; - - /* space or end of line */ - case sw_space_after_status: - switch (ch) { - case ' ': - state = sw_status_text; - break; - case '.': /* IIS may send 403.1, 403.2, etc */ - state = sw_status_text; - break; - case CR: - state = sw_almost_done; - break; - case LF: - goto done; - default: - return NGX_ERROR; - } - break; - - /* any text until end of line */ - case sw_status_text: - switch (ch) { - case CR: - state = sw_almost_done; - - break; - case LF: - goto done; - } - break; - - /* end of status line */ - case sw_almost_done: - status->end = p - 1; - if (ch == LF) { - goto done; - } else { - return NGX_ERROR; - } - } - } - - b->pos = p; - ctx->state = state; - - return NGX_AGAIN; - -done: - - b->pos = p + 1; - - if (status->end == NULL) { - status->end = p; - } - - ctx->state = sw_start; - - return NGX_OK; -} - - -static void -ngx_http_upstream_check_http_reinit(ngx_http_upstream_check_peer_t *peer) -{ - ngx_http_upstream_check_ctx_t *ctx; - - ctx = peer->check_data; - - ctx->send.pos = ctx->send.start; - ctx->send.last = ctx->send.end; - - ctx->recv.pos = ctx->recv.last = ctx->recv.start; - - ctx->state = 0; - - ngx_memzero(&ctx->status, sizeof(ngx_http_status_t)); -} - - -static ngx_int_t -ngx_http_upstream_check_ssl_hello_init(ngx_http_upstream_check_peer_t *peer) -{ - ngx_http_upstream_check_ctx_t *ctx; - ngx_http_upstream_check_srv_conf_t *ucscf; - - ctx = peer->check_data; - ucscf = peer->conf; - - ctx->send.start = ctx->send.pos = (u_char *)ucscf->send.data; - ctx->send.end = ctx->send.last = ctx->send.start + ucscf->send.len; - - ctx->recv.start = ctx->recv.pos = NULL; - ctx->recv.end = ctx->recv.last = NULL; - - return NGX_OK; -} - - -/* a rough check of server ssl_hello responses */ -static ngx_int_t -ngx_http_upstream_check_ssl_hello_parse(ngx_http_upstream_check_peer_t *peer) -{ - size_t size; - ngx_ssl_server_hello_t *resp; - ngx_http_upstream_check_ctx_t *ctx; - - ctx = peer->check_data; - - size = ctx->recv.last - ctx->recv.pos; - if (size < sizeof(ngx_ssl_server_hello_t)) { - return NGX_AGAIN; - } - - resp = (ngx_ssl_server_hello_t *) ctx->recv.pos; - - ngx_log_debug7(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "http check ssl_parse, type: %ud, version: %ud.%ud, " - "length: %ud, handshanke_type: %ud, hello_version: %ud.%ud", - resp->msg_type, resp->version.major, resp->version.minor, - ntohs(resp->length), resp->handshake_type, - resp->hello_version.major, resp->hello_version.minor); - - if (resp->msg_type != NGX_SSL_HANDSHAKE) { - return NGX_ERROR; - } - - if (resp->handshake_type != NGX_SSL_SERVER_HELLO) { - return NGX_ERROR; - } - - return NGX_OK; -} - - -static void -ngx_http_upstream_check_ssl_hello_reinit(ngx_http_upstream_check_peer_t *peer) -{ - ngx_http_upstream_check_ctx_t *ctx; - - ctx = peer->check_data; - - ctx->send.pos = ctx->send.start; - ctx->send.last = ctx->send.end; - - ctx->recv.pos = ctx->recv.last = ctx->recv.start; -} - - -static ngx_int_t -ngx_http_upstream_check_mysql_init(ngx_http_upstream_check_peer_t *peer) -{ - ngx_http_upstream_check_ctx_t *ctx; - ngx_http_upstream_check_srv_conf_t *ucscf; - - ctx = peer->check_data; - ucscf = peer->conf; - - ctx->send.start = ctx->send.pos = (u_char *)ucscf->send.data; - ctx->send.end = ctx->send.last = ctx->send.start + ucscf->send.len; - - ctx->recv.start = ctx->recv.pos = NULL; - ctx->recv.end = ctx->recv.last = NULL; - - return NGX_OK; -} - - -/* a rough check of mysql greeting responses */ -static ngx_int_t -ngx_http_upstream_check_mysql_parse(ngx_http_upstream_check_peer_t *peer) -{ - size_t size; - ngx_mysql_handshake_init_t *handshake; - ngx_http_upstream_check_ctx_t *ctx; - - ctx = peer->check_data; - - size = ctx->recv.last - ctx->recv.pos; - if (size < sizeof(ngx_mysql_handshake_init_t)) { - return NGX_AGAIN; - } - - handshake = (ngx_mysql_handshake_init_t *) ctx->recv.pos; - - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "mysql_parse: packet_number=%ud, protocol=%ud, server=%s", - handshake->packet_number, handshake->protocol_version, - handshake->others); - - /* The mysql greeting packet's serial number always begins with 0. */ - if (handshake->packet_number != 0x00) { - return NGX_ERROR; - } - - return NGX_OK; -} - - -static void -ngx_http_upstream_check_mysql_reinit(ngx_http_upstream_check_peer_t *peer) -{ - ngx_http_upstream_check_ctx_t *ctx; - - ctx = peer->check_data; - - ctx->send.pos = ctx->send.start; - ctx->send.last = ctx->send.end; - - ctx->recv.pos = ctx->recv.last = ctx->recv.start; -} - - -static ngx_int_t -ngx_http_upstream_check_ajp_init(ngx_http_upstream_check_peer_t *peer) -{ - ngx_http_upstream_check_ctx_t *ctx; - ngx_http_upstream_check_srv_conf_t *ucscf; - - ctx = peer->check_data; - ucscf = peer->conf; - - ctx->send.start = ctx->send.pos = (u_char *)ucscf->send.data; - ctx->send.end = ctx->send.last = ctx->send.start + ucscf->send.len; - - ctx->recv.start = ctx->recv.pos = NULL; - ctx->recv.end = ctx->recv.last = NULL; - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_upstream_check_ajp_parse(ngx_http_upstream_check_peer_t *peer) -{ - size_t size; - u_char *p; - ngx_http_upstream_check_ctx_t *ctx; - - ctx = peer->check_data; - - size = ctx->recv.last - ctx->recv.pos; - if (size < sizeof(ngx_ajp_cpong_packet)) { - return NGX_AGAIN; - } - - p = ctx->recv.pos; - -#if (NGX_DEBUG) - { - ngx_ajp_raw_packet_t *ajp; - - ajp = (ngx_ajp_raw_packet_t *) p; - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "ajp_parse: preamble=0x%uxd, length=0x%uxd, type=0x%uxd", - ntohs(ajp->preamble), ntohs(ajp->length), ajp->type); - } -#endif - - if (ngx_memcmp(ngx_ajp_cpong_packet, p, sizeof(ngx_ajp_cpong_packet)) == 0) - { - return NGX_OK; - } else { - return NGX_ERROR; - } -} - - -static void -ngx_http_upstream_check_ajp_reinit(ngx_http_upstream_check_peer_t *peer) -{ - ngx_http_upstream_check_ctx_t *ctx; - - ctx = peer->check_data; - - ctx->send.pos = ctx->send.start; - ctx->send.last = ctx->send.end; - - ctx->recv.pos = ctx->recv.last = ctx->recv.start; -} - - -static void -ngx_http_upstream_check_status_update(ngx_http_upstream_check_peer_t *peer, - ngx_int_t result) -{ - ngx_http_upstream_check_srv_conf_t *ucscf; - - ucscf = peer->conf; - - if (result) { - peer->shm->rise_count++; - peer->shm->fall_count = 0; - if (peer->shm->down && peer->shm->rise_count >= ucscf->rise_count) { - peer->shm->down = 0; - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, - "enable check peer: %V ", - &peer->check_peer_addr->name); - } - } else { - peer->shm->rise_count = 0; - peer->shm->fall_count++; - if (!peer->shm->down && peer->shm->fall_count >= ucscf->fall_count) { - peer->shm->down = 1; - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, - "disable check peer: %V ", - &peer->check_peer_addr->name); - } - } - - peer->shm->access_time = ngx_current_msec; -} - - -static void -ngx_http_upstream_check_clean_event(ngx_http_upstream_check_peer_t *peer) -{ - ngx_connection_t *c; - ngx_http_upstream_check_srv_conf_t *ucscf; - ngx_check_conf_t *cf; - - c = peer->pc.connection; - ucscf = peer->conf; - cf = ucscf->check_type_conf; - - if (c) { - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, - "http check clean event: index:%i, fd: %d", - peer->index, c->fd); - if (c->error == 0 && - cf->need_keepalive && - (c->requests < ucscf->check_keepalive_requests)) - { - c->write->handler = ngx_http_upstream_check_dummy_handler; - c->read->handler = ngx_http_upstream_check_discard_handler; - } else { - ngx_close_connection(c); - peer->pc.connection = NULL; - } - } - - if (peer->check_timeout_ev.timer_set) { - ngx_del_timer(&peer->check_timeout_ev); - } - - peer->state = NGX_HTTP_CHECK_ALL_DONE; - - if (peer->check_data != NULL && peer->reinit) { - peer->reinit(peer); - } - - peer->shm->owner = NGX_INVALID_PID; -} - - -static void -ngx_http_upstream_check_timeout_handler(ngx_event_t *event) -{ - ngx_http_upstream_check_peer_t *peer; - - if (ngx_http_upstream_check_need_exit()) { - return; - } - - peer = event->data; - peer->pc.connection->error = 1; - - ngx_log_error(NGX_LOG_ERR, event->log, 0, - "check time out with peer: %V ", - &peer->check_peer_addr->name); - - ngx_http_upstream_check_status_update(peer, 0); - ngx_http_upstream_check_clean_event(peer); -} - - -static void -ngx_http_upstream_check_finish_handler(ngx_event_t *event) -{ - if (ngx_http_upstream_check_need_exit()) { - return; - } -} - - -static ngx_int_t -ngx_http_upstream_check_need_exit() -{ - if (ngx_terminate || ngx_exiting || ngx_quit) { - ngx_http_upstream_check_clear_all_events(); - return 1; - } - - return 0; -} - - -static void -ngx_http_upstream_check_clear_all_events() -{ - ngx_uint_t i; - ngx_connection_t *c; - ngx_http_upstream_check_peer_t *peer; - ngx_http_upstream_check_peers_t *peers; - - static ngx_flag_t has_cleared = 0; - - if (has_cleared || check_peers_ctx == NULL) { - return; - } - - ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0, - "clear all the events on %P ", ngx_pid); - - has_cleared = 1; - - peers = check_peers_ctx; - - peer = peers->peers.elts; - for (i = 0; i < peers->peers.nelts; i++) { - - if (peer[i].check_ev.timer_set) { - ngx_del_timer(&peer[i].check_ev); - } - - if (peer[i].check_timeout_ev.timer_set) { - ngx_del_timer(&peer[i].check_timeout_ev); - } - - c = peer[i].pc.connection; - if (c) { - ngx_close_connection(c); - peer[i].pc.connection = NULL; - } - - if (peer[i].pool != NULL) { - ngx_destroy_pool(peer[i].pool); - peer[i].pool = NULL; - } - } -} - - -static ngx_int_t -ngx_http_upstream_check_status_handler(ngx_http_request_t *r) -{ - size_t buffer_size; - ngx_int_t rc; - ngx_buf_t *b; - ngx_chain_t out; - ngx_http_upstream_check_peers_t *peers; - ngx_http_upstream_check_loc_conf_t *uclcf; - ngx_http_upstream_check_status_ctx_t *ctx; - - if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) { - return NGX_HTTP_NOT_ALLOWED; - } - - rc = ngx_http_discard_request_body(r); - - if (rc != NGX_OK) { - return rc; - } - - uclcf = ngx_http_get_module_loc_conf(r, ngx_http_upstream_check_module); - - ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_check_status_ctx_t)); - if (ctx == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - ngx_http_upstream_check_status_parse_args(r, ctx); - - if (ctx->format == NULL) { - ctx->format = uclcf->format; - } - - r->headers_out.content_type = ctx->format->content_type; - - if (r->method == NGX_HTTP_HEAD) { - r->headers_out.status = NGX_HTTP_OK; - - rc = ngx_http_send_header(r); - - if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { - return rc; - } - } - - peers = check_peers_ctx; - if (peers == NULL) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "http upstream check module can not find any check " - "server, make sure you've added the check servers"); - - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - /* 1/4 pagesize for each record */ - buffer_size = peers->peers.nelts * ngx_pagesize / 4; - buffer_size = ngx_align(buffer_size, ngx_pagesize) + ngx_pagesize; - - b = ngx_create_temp_buf(r->pool, buffer_size); - if (b == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - out.buf = b; - out.next = NULL; - - ctx->format->output(b, peers, ctx->flag); - - r->headers_out.status = NGX_HTTP_OK; - r->headers_out.content_length_n = b->last - b->pos; - - if (r->headers_out.content_length_n == 0) { - r->header_only = 1; - } - - b->last_buf = 1; - - rc = ngx_http_send_header(r); - - if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { - return rc; - } - - return ngx_http_output_filter(r, &out); -} - - -static void -ngx_http_upstream_check_status_parse_args(ngx_http_request_t *r, - ngx_http_upstream_check_status_ctx_t *ctx) -{ - ngx_str_t value; - ngx_uint_t i; - ngx_check_status_command_t *command; - - if (r->args.len == 0) { - return; - } - - for (i = 0; /* void */ ; i++) { - - command = &ngx_check_status_commands[i]; - - if (command->name.len == 0) { - break; - } - - if (ngx_http_arg(r, command->name.data, command->name.len, &value) - == NGX_OK) { - - if (command->handler(ctx, &value) != NGX_OK) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "http upstream check, bad argument: \"%V\"", - &value); - } - } - } - - ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, - "http upstream check, flag: \"%ui\"", ctx->flag); -} - - -static ngx_int_t -ngx_http_upstream_check_status_command_format( - ngx_http_upstream_check_status_ctx_t *ctx, ngx_str_t *value) -{ - ctx->format = ngx_http_get_check_status_format_conf(value); - if (ctx->format == NULL) { - return NGX_ERROR; - } - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_upstream_check_status_command_status( - ngx_http_upstream_check_status_ctx_t *ctx, ngx_str_t *value) -{ - if (value->len == (sizeof("down") - 1) - && ngx_strncasecmp(value->data, (u_char *) "down", value->len) == 0) { - - ctx->flag |= NGX_CHECK_STATUS_DOWN; - - } else if (value->len == (sizeof("up") - 1) - && ngx_strncasecmp(value->data, (u_char *) "up", value->len) - == 0) { - - ctx->flag |= NGX_CHECK_STATUS_UP; - - } else { - return NGX_ERROR; - } - - return NGX_OK; -} - - -static void -ngx_http_upstream_check_status_html_format(ngx_buf_t *b, - ngx_http_upstream_check_peers_t *peers, ngx_uint_t flag) -{ - ngx_uint_t i, count; - ngx_http_upstream_check_peer_t *peer; - - peer = peers->peers.elts; - - count = 0; - - for (i = 0; i < peers->peers.nelts; i++) { - - if (flag & NGX_CHECK_STATUS_DOWN) { - - if (!peer[i].shm->down) { - continue; - } - - } else if (flag & NGX_CHECK_STATUS_UP) { - - if (peer[i].shm->down) { - continue; - } - } - - count++; - } - - b->last = ngx_snprintf(b->last, b->end - b->last, - "\n" - "\n" - "\n" - " Nginx http upstream check status\n" - "\n" - "\n" - "

Nginx http upstream check status

\n" - "

Check upstream server number: %ui, generation: %ui

\n" - "\n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n", - count, ngx_http_upstream_check_shm_generation); - - for (i = 0; i < peers->peers.nelts; i++) { - - if (flag & NGX_CHECK_STATUS_DOWN) { - - if (!peer[i].shm->down) { - continue; - } - - } else if (flag & NGX_CHECK_STATUS_UP) { - - if (peer[i].shm->down) { - continue; - } - } - - b->last = ngx_snprintf(b->last, b->end - b->last, - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n", - peer[i].shm->down ? " bgcolor=\"#FF0000\"" : "", - i, - peer[i].upstream_name, - &peer[i].peer_addr->name, - peer[i].shm->down ? "down" : "up", - peer[i].shm->rise_count, - peer[i].shm->fall_count, - &peer[i].conf->check_type_conf->name, - peer[i].conf->port); - } - - b->last = ngx_snprintf(b->last, b->end - b->last, - "
IndexUpstreamNameStatusRise countsFall countsCheck typeCheck port
%ui%V%V%s%ui%ui%V%ui
\n" - "\n" - "\n"); -} - - -static void -ngx_http_upstream_check_status_csv_format(ngx_buf_t *b, - ngx_http_upstream_check_peers_t *peers, ngx_uint_t flag) -{ - ngx_uint_t i; - ngx_http_upstream_check_peer_t *peer; - - peer = peers->peers.elts; - for (i = 0; i < peers->peers.nelts; i++) { - - if (flag & NGX_CHECK_STATUS_DOWN) { - - if (!peer[i].shm->down) { - continue; - } - - } else if (flag & NGX_CHECK_STATUS_UP) { - - if (peer[i].shm->down) { - continue; - } - } - - b->last = ngx_snprintf(b->last, b->end - b->last, - "%ui,%V,%V,%s,%ui,%ui,%V,%ui\n", - i, - peer[i].upstream_name, - &peer[i].peer_addr->name, - peer[i].shm->down ? "down" : "up", - peer[i].shm->rise_count, - peer[i].shm->fall_count, - &peer[i].conf->check_type_conf->name, - peer[i].conf->port); - } -} - - -static void -ngx_http_upstream_check_status_json_format(ngx_buf_t *b, - ngx_http_upstream_check_peers_t *peers, ngx_uint_t flag) -{ - ngx_uint_t count, i, last; - ngx_http_upstream_check_peer_t *peer; - - peer = peers->peers.elts; - - count = 0; - - for (i = 0; i < peers->peers.nelts; i++) { - - if (flag & NGX_CHECK_STATUS_DOWN) { - - if (!peer[i].shm->down) { - continue; - } - - } else if (flag & NGX_CHECK_STATUS_UP) { - - if (peer[i].shm->down) { - continue; - } - } - - count++; - } - - b->last = ngx_snprintf(b->last, b->end - b->last, - "{\"servers\": {\n" - " \"total\": %ui,\n" - " \"generation\": %ui,\n" - " \"server\": [\n", - count, - ngx_http_upstream_check_shm_generation); - - last = peers->peers.nelts - 1; - for (i = 0; i < peers->peers.nelts; i++) { - - if (flag & NGX_CHECK_STATUS_DOWN) { - - if (!peer[i].shm->down) { - continue; - } - - } else if (flag & NGX_CHECK_STATUS_UP) { - - if (peer[i].shm->down) { - continue; - } - } - - b->last = ngx_snprintf(b->last, b->end - b->last, - " {\"index\": %ui, " - "\"upstream\": \"%V\", " - "\"name\": \"%V\", " - "\"status\": \"%s\", " - "\"rise\": %ui, " - "\"fall\": %ui, " - "\"type\": \"%V\", " - "\"port\": %ui}" - "%s\n", - i, - peer[i].upstream_name, - &peer[i].peer_addr->name, - peer[i].shm->down ? "down" : "up", - peer[i].shm->rise_count, - peer[i].shm->fall_count, - &peer[i].conf->check_type_conf->name, - peer[i].conf->port, - (i == last) ? "" : ","); - } - - b->last = ngx_snprintf(b->last, b->end - b->last, - " ]\n"); - - b->last = ngx_snprintf(b->last, b->end - b->last, - "}}\n"); -} - - -static ngx_check_conf_t * -ngx_http_get_check_type_conf(ngx_str_t *str) -{ - ngx_uint_t i; - - for (i = 0; /* void */ ; i++) { - - if (ngx_check_types[i].type == 0) { - break; - } - - if (str->len != ngx_check_types[i].name.len) { - continue; - } - - if (ngx_strncmp(str->data, ngx_check_types[i].name.data, - str->len) == 0) - { - return &ngx_check_types[i]; - } - } - - return NULL; -} - - -static char * -ngx_http_upstream_check(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_str_t *value, s; - ngx_uint_t i, port, rise, fall, default_down; - ngx_msec_t interval, timeout; - ngx_http_upstream_check_srv_conf_t *ucscf; - - /* default values */ - port = 0; - rise = 2; - fall = 5; - interval = 30000; - timeout = 1000; - default_down = 1; - - value = cf->args->elts; - - ucscf = ngx_http_conf_get_module_srv_conf(cf, - ngx_http_upstream_check_module); - if (ucscf == NULL) { - return NGX_CONF_ERROR; - } - - for (i = 1; i < cf->args->nelts; i++) { - - if (ngx_strncmp(value[i].data, "type=", 5) == 0) { - s.len = value[i].len - 5; - s.data = value[i].data + 5; - - ucscf->check_type_conf = ngx_http_get_check_type_conf(&s); - - if (ucscf->check_type_conf == NULL) { - goto invalid_check_parameter; - } - - continue; - } - - if (ngx_strncmp(value[i].data, "port=", 5) == 0) { - s.len = value[i].len - 5; - s.data = value[i].data + 5; - - port = ngx_atoi(s.data, s.len); - if (port == (ngx_uint_t) NGX_ERROR || port == 0) { - goto invalid_check_parameter; - } - - continue; - } - - if (ngx_strncmp(value[i].data, "interval=", 9) == 0) { - s.len = value[i].len - 9; - s.data = value[i].data + 9; - - interval = ngx_atoi(s.data, s.len); - if (interval == (ngx_msec_t) NGX_ERROR || interval == 0) { - goto invalid_check_parameter; - } - - continue; - } - - if (ngx_strncmp(value[i].data, "timeout=", 8) == 0) { - s.len = value[i].len - 8; - s.data = value[i].data + 8; - - timeout = ngx_atoi(s.data, s.len); - if (timeout == (ngx_msec_t) NGX_ERROR || timeout == 0) { - goto invalid_check_parameter; - } - - continue; - } - - if (ngx_strncmp(value[i].data, "rise=", 5) == 0) { - s.len = value[i].len - 5; - s.data = value[i].data + 5; - - rise = ngx_atoi(s.data, s.len); - if (rise == (ngx_uint_t) NGX_ERROR || rise == 0) { - goto invalid_check_parameter; - } - - continue; - } - - if (ngx_strncmp(value[i].data, "fall=", 5) == 0) { - s.len = value[i].len - 5; - s.data = value[i].data + 5; - - fall = ngx_atoi(s.data, s.len); - if (fall == (ngx_uint_t) NGX_ERROR || fall == 0) { - goto invalid_check_parameter; - } - - continue; - } - - if (ngx_strncmp(value[i].data, "default_down=", 13) == 0) { - s.len = value[i].len - 13; - s.data = value[i].data + 13; - - if (ngx_strcasecmp(s.data, (u_char *) "true") == 0) { - default_down = 1; - } else if (ngx_strcasecmp(s.data, (u_char *) "false") == 0) { - default_down = 0; - } else { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid value \"%s\", " - "it must be \"true\" or \"false\"", - value[i].data); - return NGX_CONF_ERROR; - } - - continue; - } - - goto invalid_check_parameter; - } - - ucscf->port = port; - ucscf->check_interval = interval; - ucscf->check_timeout = timeout; - ucscf->fall_count = fall; - ucscf->rise_count = rise; - ucscf->default_down = default_down; - - if (ucscf->check_type_conf == NGX_CONF_UNSET_PTR) { - ngx_str_set(&s, "tcp"); - ucscf->check_type_conf = ngx_http_get_check_type_conf(&s); - } - - return NGX_CONF_OK; - -invalid_check_parameter: - - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid parameter \"%V\"", &value[i]); - - return NGX_CONF_ERROR; -} - - -static char * -ngx_http_upstream_check_keepalive_requests(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf) -{ - ngx_str_t *value; - ngx_http_upstream_check_srv_conf_t *ucscf; - ngx_uint_t requests; - - value = cf->args->elts; - - ucscf = ngx_http_conf_get_module_srv_conf(cf, - ngx_http_upstream_check_module); - - requests = ngx_atoi(value[1].data, value[1].len); - if (requests == (ngx_uint_t) NGX_ERROR || requests == 0) { - return "invalid value"; - } - - ucscf->check_keepalive_requests = requests; - - return NGX_CONF_OK; -} - - -static char * -ngx_http_upstream_check_http_send(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf) -{ - ngx_str_t *value; - ngx_http_upstream_check_srv_conf_t *ucscf; - - value = cf->args->elts; - - ucscf = ngx_http_conf_get_module_srv_conf(cf, - ngx_http_upstream_check_module); - - ucscf->send = value[1]; - - return NGX_CONF_OK; -} - - -static char * -ngx_http_upstream_check_fastcgi_params(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf) -{ - ngx_str_t *value, *k, *v; - ngx_http_upstream_check_srv_conf_t *ucscf; - - value = cf->args->elts; - - ucscf = ngx_http_conf_get_module_srv_conf(cf, - ngx_http_upstream_check_module); - - k = ngx_array_push(ucscf->fastcgi_params); - if (k == NULL) { - return NGX_CONF_ERROR; - } - - v = ngx_array_push(ucscf->fastcgi_params); - if (v == NULL) { - return NGX_CONF_ERROR; - } - - *k = value[1]; - *v = value[2]; - - return NGX_CONF_OK; -} - - -static char * -ngx_http_upstream_check_http_expect_alive(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf) -{ - ngx_str_t *value; - ngx_uint_t bit, i, m; - ngx_conf_bitmask_t *mask; - ngx_http_upstream_check_srv_conf_t *ucscf; - - value = cf->args->elts; - mask = ngx_check_http_expect_alive_masks; - - ucscf = ngx_http_conf_get_module_srv_conf(cf, - ngx_http_upstream_check_module); - bit = ucscf->code.status_alive; - - for (i = 1; i < cf->args->nelts; i++) { - for (m = 0; mask[m].name.len != 0; m++) { - - if (mask[m].name.len != value[i].len - || ngx_strcasecmp(mask[m].name.data, value[i].data) != 0) - { - continue; - } - - if (bit & mask[m].mask) { - ngx_conf_log_error(NGX_LOG_WARN, cf, 0, - "duplicate value \"%s\"", value[i].data); - - } else { - bit |= mask[m].mask; - } - - break; - } - - if (mask[m].name.len == 0) { - ngx_conf_log_error(NGX_LOG_WARN, cf, 0, - "invalid value \"%s\"", value[i].data); - - return NGX_CONF_ERROR; - } - } - - ucscf->code.status_alive = bit; - - return NGX_CONF_OK; -} - - -static char * -ngx_http_upstream_check_shm_size(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_str_t *value; - ngx_http_upstream_check_main_conf_t *ucmcf; - - ucmcf = ngx_http_conf_get_module_main_conf(cf, - ngx_http_upstream_check_module); - if (ucmcf->check_shm_size) { - return "is duplicate"; - } - - value = cf->args->elts; - - ucmcf->check_shm_size = ngx_parse_size(&value[1]); - if (ucmcf->check_shm_size == (size_t) NGX_ERROR) { - return "invalid value"; - } - - return NGX_CONF_OK; -} - - -static ngx_check_status_conf_t * -ngx_http_get_check_status_format_conf(ngx_str_t *str) -{ - ngx_uint_t i; - - for (i = 0; /* void */ ; i++) { - - if (ngx_check_status_formats[i].format.len == 0) { - break; - } - - if (str->len != ngx_check_status_formats[i].format.len) { - continue; - } - - if (ngx_strncmp(str->data, ngx_check_status_formats[i].format.data, - str->len) == 0) - { - return &ngx_check_status_formats[i]; - } - } - - return NULL; -} - - -static char * -ngx_http_upstream_check_status(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_str_t *value; - ngx_http_core_loc_conf_t *clcf; - ngx_http_upstream_check_loc_conf_t *uclcf; - - value = cf->args->elts; - - clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); - - clcf->handler = ngx_http_upstream_check_status_handler; - - if (cf->args->nelts == 2) { - uclcf = ngx_http_conf_get_module_loc_conf(cf, - ngx_http_upstream_check_module); - - uclcf->format = ngx_http_get_check_status_format_conf(&value[1]); - if (uclcf->format == NULL) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid check format \"%V\"", &value[1]); - - return NGX_CONF_ERROR; - } - } - - return NGX_CONF_OK; -} - - -static void * -ngx_http_upstream_check_create_main_conf(ngx_conf_t *cf) -{ - ngx_http_upstream_check_main_conf_t *ucmcf; - - ucmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_check_main_conf_t)); - if (ucmcf == NULL) { - return NULL; - } - - ucmcf->peers = ngx_pcalloc(cf->pool, - sizeof(ngx_http_upstream_check_peers_t)); - if (ucmcf->peers == NULL) { - return NULL; - } - - ucmcf->peers->checksum = 0; - - if (ngx_array_init(&ucmcf->peers->peers, cf->pool, 16, - sizeof(ngx_http_upstream_check_peer_t)) != NGX_OK) - { - return NULL; - } - - return ucmcf; -} - - -static ngx_buf_t * -ngx_http_upstream_check_create_fastcgi_request(ngx_pool_t *pool, - ngx_str_t *params, ngx_uint_t num) -{ - size_t size, len, padding; - ngx_buf_t *b; - ngx_str_t *k, *v; - ngx_uint_t i, j; - ngx_http_fastcgi_header_t *h; - - len = 0; - for (i = 0, j = 0; i < num; i++, j = i * 2) { - k = ¶ms[j]; - v = ¶ms[j + 1]; - - len += 1 + k->len + ((v->len > 127) ? 4 : 1) + v->len; - } - - padding = 8 - len % 8; - padding = (padding == 8) ? 0 : padding; - - size = sizeof(ngx_http_fastcgi_header_t) - + sizeof(ngx_http_fastcgi_begin_request_t) - - + sizeof(ngx_http_fastcgi_header_t) /* NGX_HTTP_FASTCGI_PARAMS */ - + len + padding - + sizeof(ngx_http_fastcgi_header_t) /* NGX_HTTP_FASTCGI_PARAMS */ - - + sizeof(ngx_http_fastcgi_header_t); /* NGX_HTTP_FASTCGI_STDIN */ - - - b = ngx_create_temp_buf(pool, size); - if (b == NULL) { - return NULL; - } - - ngx_http_fastcgi_request_start.br.flags = 0; - - ngx_memcpy(b->pos, &ngx_http_fastcgi_request_start, - sizeof(ngx_http_fastcgi_request_start_t)); - - h = (ngx_http_fastcgi_header_t *) - (b->pos + sizeof(ngx_http_fastcgi_header_t) - + sizeof(ngx_http_fastcgi_begin_request_t)); - - h->content_length_hi = (u_char) ((len >> 8) & 0xff); - h->content_length_lo = (u_char) (len & 0xff); - h->padding_length = (u_char) padding; - h->reserved = 0; - - b->last = b->pos + sizeof(ngx_http_fastcgi_header_t) - + sizeof(ngx_http_fastcgi_begin_request_t) - + sizeof(ngx_http_fastcgi_header_t); - - for (i = 0, j = 0; i < num; i++, j = i * 2) { - k = ¶ms[j]; - v = ¶ms[j + 1]; - - if (k->len > 127) { - *b->last++ = (u_char) (((k->len >> 24) & 0x7f) | 0x80); - *b->last++ = (u_char) ((k->len >> 16) & 0xff); - *b->last++ = (u_char) ((k->len >> 8) & 0xff); - *b->last++ = (u_char) (k->len & 0xff); - - } else { - *b->last++ = (u_char) k->len; - } - - if (v->len > 127) { - *b->last++ = (u_char) (((v->len >> 24) & 0x7f) | 0x80); - *b->last++ = (u_char) ((v->len >> 16) & 0xff); - *b->last++ = (u_char) ((v->len >> 8) & 0xff); - *b->last++ = (u_char) (v->len & 0xff); - - } else { - *b->last++ = (u_char) v->len; - } - - b->last = ngx_copy(b->last, k->data, k->len); - b->last = ngx_copy(b->last, v->data, v->len); - } - - if (padding) { - ngx_memzero(b->last, padding); - b->last += padding; - } - - h = (ngx_http_fastcgi_header_t *) b->last; - b->last += sizeof(ngx_http_fastcgi_header_t); - - h->version = 1; - h->type = NGX_HTTP_FASTCGI_PARAMS; - h->request_id_hi = 0; - h->request_id_lo = 1; - h->content_length_hi = 0; - h->content_length_lo = 0; - h->padding_length = 0; - h->reserved = 0; - - h = (ngx_http_fastcgi_header_t *) b->last; - b->last += sizeof(ngx_http_fastcgi_header_t); - - return b; -} - - -static char * -ngx_http_upstream_check_init_main_conf(ngx_conf_t *cf, void *conf) -{ - ngx_buf_t *b; - ngx_uint_t i; - ngx_http_upstream_srv_conf_t **uscfp; - ngx_http_upstream_main_conf_t *umcf; - - umcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_upstream_module); - - b = ngx_http_upstream_check_create_fastcgi_request(cf->pool, - fastcgi_default_params, - sizeof(fastcgi_default_params) / sizeof(ngx_str_t) / 2); - - if (b == NULL) { - return NGX_CONF_ERROR; - } - - fastcgi_default_request.data = b->pos; - fastcgi_default_request.len = b->last - b->pos; - - uscfp = umcf->upstreams.elts; - - for (i = 0; i < umcf->upstreams.nelts; i++) { - - if (ngx_http_upstream_check_init_srv_conf(cf, uscfp[i]) != NGX_OK) { - return NGX_CONF_ERROR; - } - } - - return ngx_http_upstream_check_init_shm(cf, conf); -} - - -static void * -ngx_http_upstream_check_create_srv_conf(ngx_conf_t *cf) -{ - ngx_http_upstream_check_srv_conf_t *ucscf; - - ucscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_check_srv_conf_t)); - if (ucscf == NULL) { - return NULL; - } - - ucscf->fastcgi_params = ngx_array_create(cf->pool, 2 * 4, sizeof(ngx_str_t)); - if (ucscf->fastcgi_params == NULL) { - return NULL; - } - - ucscf->port = NGX_CONF_UNSET_UINT; - ucscf->fall_count = NGX_CONF_UNSET_UINT; - ucscf->rise_count = NGX_CONF_UNSET_UINT; - ucscf->check_timeout = NGX_CONF_UNSET_MSEC; - ucscf->check_keepalive_requests = NGX_CONF_UNSET_UINT; - ucscf->check_type_conf = NGX_CONF_UNSET_PTR; - - return ucscf; -} - - -static void * -ngx_http_upstream_check_create_loc_conf(ngx_conf_t *cf) -{ - ngx_http_upstream_check_loc_conf_t *uclcf; - - uclcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_check_loc_conf_t)); - if (uclcf == NULL) { - return NULL; - } - - uclcf->format = NGX_CONF_UNSET_PTR; - - return uclcf; -} - - -static char * -ngx_http_upstream_check_init_srv_conf(ngx_conf_t *cf, void *conf) -{ - ngx_str_t s; - ngx_buf_t *b; - ngx_check_conf_t *check; - ngx_http_upstream_srv_conf_t *us = conf; - ngx_http_upstream_check_srv_conf_t *ucscf; - - if (us->srv_conf == NULL) { - return NGX_CONF_OK; - } - - ucscf = ngx_http_conf_upstream_srv_conf(us, ngx_http_upstream_check_module); - - if (ucscf->port == NGX_CONF_UNSET_UINT) { - ucscf->port = 0; - } - - if (ucscf->fall_count == NGX_CONF_UNSET_UINT) { - ucscf->fall_count = 2; - } - - if (ucscf->rise_count == NGX_CONF_UNSET_UINT) { - ucscf->rise_count = 5; - } - - if (ucscf->check_interval == NGX_CONF_UNSET_MSEC) { - ucscf->check_interval = 0; - } - - if (ucscf->check_timeout == NGX_CONF_UNSET_MSEC) { - ucscf->check_timeout = 1000; - } - - if (ucscf->check_keepalive_requests == NGX_CONF_UNSET_UINT) { - ucscf->check_keepalive_requests = 1; - } - - if (ucscf->check_type_conf == NGX_CONF_UNSET_PTR) { - ucscf->check_type_conf = NULL; - } - - check = ucscf->check_type_conf; - - if (check) { - if (ucscf->send.len == 0) { - ngx_str_set(&s, "fastcgi"); - - if (check == ngx_http_get_check_type_conf(&s)) { - - if (ucscf->fastcgi_params->nelts == 0) { - ucscf->send.data = fastcgi_default_request.data; - ucscf->send.len = fastcgi_default_request.len; - - } else { - b = ngx_http_upstream_check_create_fastcgi_request( - cf->pool, ucscf->fastcgi_params->elts, - ucscf->fastcgi_params->nelts / 2); - if (b == NULL) { - return NGX_CONF_ERROR; - } - - ucscf->send.data = b->pos; - ucscf->send.len = b->last - b->pos; - } - } else { - ucscf->send.data = check->default_send.data; - ucscf->send.len = check->default_send.len; - } - } - - - if (ucscf->code.status_alive == 0) { - ucscf->code.status_alive = check->default_status_alive; - } - } - - return NGX_CONF_OK; -} - - -static char * -ngx_http_upstream_check_merge_loc_conf(ngx_conf_t *cf, void *parent, - void *child) -{ - ngx_str_t format = ngx_string("html"); - ngx_http_upstream_check_loc_conf_t *prev = parent; - ngx_http_upstream_check_loc_conf_t *conf = child; - - ngx_conf_merge_ptr_value(conf->format, prev->format, - ngx_http_get_check_status_format_conf(&format)); - - return NGX_CONF_OK; -} - - -static char * -ngx_http_upstream_check_init_shm(ngx_conf_t *cf, void *conf) -{ - ngx_str_t *shm_name; - ngx_uint_t shm_size; - ngx_shm_zone_t *shm_zone; - ngx_http_upstream_check_main_conf_t *ucmcf = conf; - - if (ucmcf->peers->peers.nelts > 0) { - - ngx_http_upstream_check_shm_generation++; - - shm_name = &ucmcf->peers->check_shm_name; - - ngx_http_upstream_check_get_shm_name(shm_name, cf->pool, - ngx_http_upstream_check_shm_generation); - - /* The default check shared memory size is 1M */ - shm_size = 1 * 1024 * 1024; - - shm_size = shm_size < ucmcf->check_shm_size ? - ucmcf->check_shm_size : shm_size; - - shm_zone = ngx_shared_memory_add(cf, shm_name, shm_size, - &ngx_http_upstream_check_module); - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0, - "http upstream check, upsteam:%V, shm_zone size:%ui", - shm_name, shm_size); - - shm_zone->data = cf->pool; - check_peers_ctx = ucmcf->peers; - - shm_zone->init = ngx_http_upstream_check_init_shm_zone; - } - else { - check_peers_ctx = NULL; - } - - return NGX_CONF_OK; -} - - -static ngx_int_t -ngx_http_upstream_check_get_shm_name(ngx_str_t *shm_name, ngx_pool_t *pool, - ngx_uint_t generation) -{ - u_char *last; - - shm_name->data = ngx_palloc(pool, SHM_NAME_LEN); - if (shm_name->data == NULL) { - return NGX_ERROR; - } - - last = ngx_snprintf(shm_name->data, SHM_NAME_LEN, "%s#%ui", - "ngx_http_upstream_check", generation); - - shm_name->len = last - shm_name->data; - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_upstream_check_init_shm_zone(ngx_shm_zone_t *shm_zone, void *data) -{ - size_t size; - ngx_str_t oshm_name; - ngx_int_t rc; - ngx_uint_t i, same, number; - ngx_pool_t *pool; - ngx_shm_zone_t *oshm_zone; - ngx_slab_pool_t *shpool; - ngx_http_upstream_check_peer_t *peer; - ngx_http_upstream_check_peers_t *peers; - ngx_http_upstream_check_srv_conf_t *ucscf; - ngx_http_upstream_check_peer_shm_t *peer_shm, *opeer_shm; - ngx_http_upstream_check_peers_shm_t *peers_shm, *opeers_shm; - - opeers_shm = NULL; - peers_shm = NULL; - ngx_str_null(&oshm_name); - - same = 0; - peers = check_peers_ctx; - if (peers == NULL) { - return NGX_OK; - } - - number = peers->peers.nelts; - if (number == 0) { - return NGX_OK; - } - - pool = shm_zone->data; - if (pool == NULL) { - pool = ngx_cycle->pool; - } - - shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; - - if (data) { - opeers_shm = data; - - if ((opeers_shm->number == number) - && (opeers_shm->checksum == peers->checksum)) { - - peers_shm = data; - same = 1; - } - } - - if (!same) { - - if (ngx_http_upstream_check_shm_generation > 1) { - - ngx_http_upstream_check_get_shm_name(&oshm_name, - pool, ngx_http_upstream_check_shm_generation - 1); - - /* The global variable ngx_cycle still points to the old one */ - oshm_zone = ngx_shared_memory_find((ngx_cycle_t *) ngx_cycle, - &oshm_name, - &ngx_http_upstream_check_module); - - if (oshm_zone) { - opeers_shm = oshm_zone->data; - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, shm_zone->shm.log, 0, - "http upstream check, find oshm_zone:%p, " - "opeers_shm: %p", - oshm_zone, opeers_shm); - } - } - - size = sizeof(*peers_shm) + - (number - 1) * sizeof(ngx_http_upstream_check_peer_shm_t); - - peers_shm = ngx_slab_alloc(shpool, size); - - if (peers_shm == NULL) { - goto failure; - } - - ngx_memzero(peers_shm, size); - } - - peers_shm->generation = ngx_http_upstream_check_shm_generation; - peers_shm->checksum = peers->checksum; - peers_shm->number = number; - - peer = peers->peers.elts; - - for (i = 0; i < number; i++) { - - peer_shm = &peers_shm->peers[i]; - - /* - * This function may be triggered before the old stale - * work process exits. The owner may stick to the old - * pid. - */ - peer_shm->owner = NGX_INVALID_PID; - - if (same) { - continue; - } - - peer_shm->socklen = peer[i].peer_addr->socklen; - peer_shm->sockaddr = ngx_slab_alloc(shpool, peer_shm->socklen); - if (peer_shm->sockaddr == NULL) { - goto failure; - } - - ngx_memcpy(peer_shm->sockaddr, peer[i].peer_addr->sockaddr, - peer_shm->socklen); - - if (opeers_shm) { - - opeer_shm = ngx_http_upstream_check_find_shm_peer(opeers_shm, - peer[i].peer_addr); - if (opeer_shm) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, shm_zone->shm.log, 0, - "http upstream check, inherit opeer: %V ", - &peer[i].peer_addr->name); - - rc = ngx_http_upstream_check_init_shm_peer(peer_shm, opeer_shm, - 0, pool, &peer[i].peer_addr->name); - if (rc != NGX_OK) { - return NGX_ERROR; - } - - continue; - } - } - - ucscf = peer[i].conf; - rc = ngx_http_upstream_check_init_shm_peer(peer_shm, NULL, - ucscf->default_down, pool, - &peer[i].peer_addr->name); - if (rc != NGX_OK) { - return NGX_ERROR; - } - } - - peers->peers_shm = peers_shm; - shm_zone->data = peers_shm; - - return NGX_OK; - -failure: - ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0, - "http upstream check_shm_size is too small, " - "you should specify a larger size."); - return NGX_ERROR; -} - - -static ngx_shm_zone_t * -ngx_shared_memory_find(ngx_cycle_t *cycle, ngx_str_t *name, void *tag) -{ - ngx_uint_t i; - ngx_shm_zone_t *shm_zone; - ngx_list_part_t *part; - - part = (ngx_list_part_t *) &(cycle->shared_memory.part); - shm_zone = part->elts; - - for (i = 0; /* void */ ; i++) { - - if (i >= part->nelts) { - if (part->next == NULL) { - break; - } - part = part->next; - shm_zone = part->elts; - i = 0; - } - - if (name->len != shm_zone[i].shm.name.len) { - continue; - } - - if (ngx_strncmp(name->data, shm_zone[i].shm.name.data, name->len) != 0) - { - continue; - } - - if (tag != shm_zone[i].tag) { - continue; - } - - return &shm_zone[i]; - } - - return NULL; -} - - -static ngx_http_upstream_check_peer_shm_t * -ngx_http_upstream_check_find_shm_peer(ngx_http_upstream_check_peers_shm_t *p, - ngx_addr_t *addr) -{ - ngx_uint_t i; - ngx_http_upstream_check_peer_shm_t *peer_shm; - - for (i = 0; i < p->number; i++) { - - peer_shm = &p->peers[i]; - - if (addr->socklen != peer_shm->socklen) { - continue; - } - - if (ngx_memcmp(addr->sockaddr, peer_shm->sockaddr, addr->socklen) == 0) { - return peer_shm; - } - } - - return NULL; -} - - -static ngx_int_t -ngx_http_upstream_check_init_shm_peer(ngx_http_upstream_check_peer_shm_t *psh, - ngx_http_upstream_check_peer_shm_t *opsh, ngx_uint_t init_down, - ngx_pool_t *pool, ngx_str_t *name) -{ - u_char *file; - - if (opsh) { - psh->access_time = opsh->access_time; - psh->access_count = opsh->access_count; - - psh->fall_count = opsh->fall_count; - psh->rise_count = opsh->rise_count; - psh->busyness = opsh->busyness; - - psh->down = opsh->down; - - } else { - psh->access_time = 0; - psh->access_count = 0; - - psh->fall_count = 0; - psh->rise_count = 0; - psh->busyness = 0; - - psh->down = init_down; - } - -#if (NGX_HAVE_ATOMIC_OPS) - - file = NULL; - -#else - - file = ngx_pnalloc(pool, ngx_cycle->lock_file.len + name->len); - if (file == NULL) { - return NGX_ERROR; - } - - (void) ngx_sprintf(file, "%V%V%Z", &ngx_cycle->lock_file, name); - -#endif - -#if (nginx_version >= 1002000) - if (ngx_shmtx_create(&psh->mutex, &psh->lock, file) != NGX_OK) { -#else - if (ngx_shmtx_create(&psh->mutex, (void *) &psh->lock, file) != NGX_OK) { -#endif - return NGX_ERROR; - } - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_upstream_check_init_process(ngx_cycle_t *cycle) -{ - ngx_http_upstream_check_main_conf_t *ucmcf; - - if (ngx_process != NGX_PROCESS_WORKER) { - return NGX_OK; - } - - ucmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_upstream_check_module); - if (ucmcf == NULL) { - return NGX_OK; - } - - return ngx_http_upstream_check_add_timers(cycle); -} diff --git a/src/detect/ngx_http_upstream_check.h b/src/detect/ngx_http_upstream_check.h deleted file mode 100644 index b08b396..0000000 --- a/src/detect/ngx_http_upstream_check.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef _NGX_HTTP_UPSTREAM_CHECK_MODELE_H_INCLUDED_ -#define _NGX_HTTP_UPSTREAM_CHECK_MODELE_H_INCLUDED_ - - -#include -#include -#include - -ngx_uint_t ngx_http_upstream_check_add_peer(ngx_conf_t *cf, - ngx_http_upstream_srv_conf_t *us, ngx_addr_t *peer); - -ngx_uint_t ngx_http_upstream_check_peer_down(ngx_uint_t index); - -void ngx_http_upstream_check_get_peer(ngx_uint_t index); -void ngx_http_upstream_check_free_peer(ngx_uint_t index); - - -#endif //_NGX_HTTP_UPSTREAM_CHECK_MODELE_H_INCLUDED_ - -- 2.34.1