├── TimeServerPlus ├── src │ ├── contrib │ │ ├── threadpool.cpp │ │ ├── config.h │ │ ├── logger.cpp │ │ ├── utility.h │ │ ├── threadpool.h │ │ ├── config.cpp │ │ ├── logger.h │ │ └── utility.cpp │ ├── TimeServerPlus.config │ ├── modules │ │ ├── Makefile │ │ ├── load-module.cpp │ │ ├── load-module.h │ │ ├── module_time.h │ │ ├── module_basic.h │ │ ├── module_basic.cpp │ │ └── module_time.cpp │ ├── Makefile │ ├── include │ │ └── type.h │ ├── TimeServerPlus.h │ ├── core │ │ ├── core.h │ │ ├── response.h │ │ ├── request.h │ │ ├── request.cpp │ │ ├── core.cpp │ │ └── response.cpp │ └── TimeServerPlus.cpp ├── README └── test │ └── test.cpp ├── README.md ├── .gitignore └── time-server.c /TimeServerPlus/src/contrib/threadpool.cpp: -------------------------------------------------------------------------------- 1 | #include "threadpool.h" 2 | -------------------------------------------------------------------------------- /TimeServerPlus/src/TimeServerPlus.config: -------------------------------------------------------------------------------- 1 | PORT 8668 2 | DOCROOT /home/yping 3 | INDEX index.html 4 | SERVERSTRING TimeServerPlus(TSP)/0.1.171007(cpp) 5 | LOG TimeServerPlus.log 6 | DAEMON 1 7 | IPRECORD 1 8 | -------------------------------------------------------------------------------- /TimeServerPlus/README: -------------------------------------------------------------------------------- 1 | #TimeServerPlus 2 | 3 | 基于 epoll 的时间服务器升级版(功能模块化) 4 | 5 | 想法来自 [ypingcn/TimeServer](https://github.com/ypingcn/TimeServer) 6 | 7 | #编译 8 | 9 | cd src 10 | 11 | make 12 | 13 | #运行 14 | 15 | ./main TimeServerPlus.config 16 | 17 | ( Usage: ./main ) 18 | 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # time_server 2 | 时间服务器(通过访问网页来返回当前服务器时间) 3 | 4 | ## 编译 5 | 6 | ``` gcc time-server.c -o time-server -lpthread``` 7 | 8 | ## 服务器端 9 | 10 | 运行 ``` time-server ``` 11 | 12 | ## 客户端 13 | 14 | 本地调试访问 ``` 127.0.0.1:8600 ``` ,访问远程服务端请将``` 127.0.0.1```替换成服务器的 IP 地址。 15 | 16 | 页面将会显示类似于``` Now: 2017-09-24 12:34:56 ```的信息。 -------------------------------------------------------------------------------- /TimeServerPlus/src/modules/Makefile: -------------------------------------------------------------------------------- 1 | CC = g++ 2 | CXXFLAGS += --std=c++11 --shared -fPIC -O3 3 | LIBS = -lpthread 4 | MODULE_SRC = $(shell echo *.cpp) 5 | MODULE_OBJ = $(MODULE_SRC:%.cpp=%.o) 6 | MODULE_SO_NAME = libtspmodules.so.$(shell grep TSP_MODULE_SONAME load-module.h | awk '{print $$3}') 7 | OTHER_MODULE_SO = 8 | 9 | all: 10 | $(CC) $(CXXFLAGS) $(MODULE_SRC) $(OTHER_MODULE_SO) -o $(MODULE_SO_NAME) $(LIBS) 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | # Log file 35 | *.log 36 | -------------------------------------------------------------------------------- /TimeServerPlus/src/modules/load-module.cpp: -------------------------------------------------------------------------------- 1 | #include "load-module.h" 2 | 3 | #include "module_basic.h" 4 | #include "module_time.h" 5 | 6 | ResponseVectorType TSPModuleManager::response = install_modules(); 7 | 8 | ResponseVectorType install_modules() { 9 | ResponseVectorType res; 10 | install_basic_modules(res); 11 | install_time_modules(res); 12 | sort(res.begin(), res.end(), 13 | [](TSPBasicResponse *a, TSPBasicResponse *b) -> bool { 14 | return a->get_priority() > b->get_priority(); 15 | }); 16 | return res; 17 | } 18 | -------------------------------------------------------------------------------- /TimeServerPlus/src/modules/load-module.h: -------------------------------------------------------------------------------- 1 | #ifndef TSP_LOAD_MODULE_H 2 | #define TSP_LOAD_MODULE_H 3 | 4 | #define TSP_MODULE_MAJOR 0 5 | #define TSP_MODULE_MINOR 1 6 | #define TSP_MODULE_PATCH 0 7 | #define TSP_MODULE_SONAME 0.1 8 | 9 | #include "../core/response.h" 10 | #include "../include/type.h" 11 | 12 | #include 13 | 14 | class TSPBasicResponse; 15 | 16 | #define ResponseVectorType std::vector 17 | 18 | class TSPModuleManager { 19 | public: 20 | static ResponseVectorType get() { return response; } 21 | 22 | private: 23 | static ResponseVectorType response; 24 | }; 25 | 26 | ResponseVectorType install_modules(); 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /TimeServerPlus/src/Makefile: -------------------------------------------------------------------------------- 1 | CC = g++ 2 | CXXFLAGS += --std=c++11 -O3 3 | LIBS = -lpthread 4 | SRC = $(shell echo core/*.cpp contrib/*.cpp) 5 | SRC_OBJ = $(SRC:%.cpp=%.o) 6 | MODULE_SO = libtspmodules.so.$(shell grep TSP_MODULE_SONAME modules/load-module.h | awk '{print $$3}') 7 | OTHER_MODULE_SO = 8 | FINAL_EXEC_NAME = main.out 9 | 10 | all: copyso 11 | $(CC) $(CXXFLAGS) TimeServerPlus.cpp $(SRC) $(MODULE_SO) $(MODULE_OTHER_SO) -o $(FINAL_EXEC_NAME) $(LIBS) 12 | 13 | copyso: checkso 14 | cd modules; cp $(MODULE_SO) ../; cd .. 15 | 16 | checkso: 17 | cd modules; if [ ! -f $(MODULE_SO) ]; then make; fi; cd ..; 18 | 19 | .PHONY: clean 20 | clean: 21 | -rm $(FINAL_EXEC_NAME) 22 | 23 | .PHONY: cleano 24 | cleano: 25 | -rm $(SRC_OBJ) 26 | -------------------------------------------------------------------------------- /TimeServerPlus/src/include/type.h: -------------------------------------------------------------------------------- 1 | #ifndef TSP_TYPE_H 2 | #define TSP_TYPE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using std::cout; 10 | using std::endl; 11 | using std::regex; 12 | using std::string; 13 | using std::map; 14 | 15 | #define MAX_BACKLOG 200 16 | #define MAX_EVENT_SIZE 1024 17 | #define KILO 1024 18 | #define BUFF_SIZE 1024 * KILO 19 | 20 | #define TSP_RN "\r\n" 21 | 22 | #define TSP_RESPONSE_OK 200 23 | #define TSP_RESPONSE_BAD_REQUEST 400 24 | #define TSP_RESPONSE_FORBIDDEN 403 25 | #define TSP_RESPONSE_NOT_FOUND 404 26 | #define TSP_RESPONSE_INTERNAL_SERVER_ERROR 500 27 | #define TSP_RESPONSE_NOIMPLEMENTED 501 28 | #define TSP_RESPONSE_HTTP_VERSION_NOT_SUPPORTED 505 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /TimeServerPlus/src/TimeServerPlus.h: -------------------------------------------------------------------------------- 1 | #ifndef TIME_SERVER_PLUS 2 | #define TIME_SERVER_PLUS 3 | 4 | #include "contrib/config.h" 5 | #include "contrib/logger.h" 6 | #include "contrib/utility.h" 7 | #include "core/core.h" 8 | #include "core/request.h" 9 | #include "include/type.h" 10 | #include "modules/load-module.h" 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | int32_t tsp_server_thread_num = 0; 18 | pthread_mutex_t tsp_server_thread_num_mutex = PTHREAD_MUTEX_INITIALIZER; 19 | 20 | int tsp_server_init(int port); 21 | void tsp_server_event_circles(int server_fd); 22 | void *tsp_server_thread_function(void *param); 23 | 24 | int tsp_server_thread_num_add(); 25 | int tsp_server_thread_num_del(); 26 | int32_t tsp_server_thread_num_get(); 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /TimeServerPlus/src/contrib/config.h: -------------------------------------------------------------------------------- 1 | #ifndef TSP_CONFIG 2 | #define TSP_CONFIG 3 | 4 | #include "../include/type.h" 5 | 6 | class TSPConfig { 7 | public: 8 | TSPConfig(const TSPConfig &) = delete; 9 | TSPConfig &operator=(const TSPConfig &) = delete; 10 | 11 | static TSPConfig *instance() { 12 | if (config == nullptr) { 13 | pthread_mutex_lock(&lock); 14 | if (config == nullptr) 15 | config = new TSPConfig(); 16 | pthread_mutex_unlock(&lock); 17 | } 18 | return config; 19 | } 20 | int parse(const string path); 21 | int get(const string key, string &value); 22 | int exist(const string key, const string value); 23 | 24 | private: 25 | TSPConfig() { 26 | data.clear(); 27 | data.insert(std::make_pair("LOG", "TimeServerPlus.log")); 28 | }; 29 | ~TSPConfig() = default; 30 | 31 | static pthread_mutex_t lock; 32 | static TSPConfig *config; 33 | map data; 34 | }; 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /TimeServerPlus/src/core/core.h: -------------------------------------------------------------------------------- 1 | #ifndef TSP_CORE 2 | #define TSP_CORE 3 | 4 | #include "../contrib/logger.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | int tsp_socket(int domain, int type, int protocol); 17 | int tsp_socket_nonblocking(int sockfd); 18 | int tsp_socket_reuseaddr(int sockfd); 19 | void tsp_socket_nodelay(int sockfd); 20 | void tsp_socket_set_timeout(int sockfd, int sec, int usec); 21 | void tsp_socket_bind(int sockfd, const struct sockaddr *addr, socklen_t len); 22 | void tsp_socket_listen(int sockfd, int backlog); 23 | int tsp_socket_accept(int sockfd, struct sockaddr *addr, socklen_t *len); 24 | 25 | int tsp_epoll_create(int size); 26 | void tsp_epoll_ctl(int epollfd, int op, int fd, struct epoll_event *event); 27 | int tsp_epoll_wait(int epollfd, struct epoll_event *events, int maxevents, 28 | int timeout); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /TimeServerPlus/src/contrib/logger.cpp: -------------------------------------------------------------------------------- 1 | #include "logger.h" 2 | #include "config.h" 3 | #include "utility.h" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | TSPLogger *TSPLogger::logger = nullptr; 10 | pthread_mutex_t TSPLogger::lock = PTHREAD_MUTEX_INITIALIZER; 11 | 12 | void TSPLogger::log(const char *level, const char *fmt, va_list args) { 13 | char buff[1024]; 14 | string now; 15 | TSPUtilTime::now(now); 16 | pthread_t pid = pthread_self(); 17 | int siz = snprintf(buff, 1024, "[%s][pid:%u] %s : ", level, (unsigned int)pid, 18 | now.c_str()); 19 | siz += vsnprintf(buff + siz, 1024 - siz, fmt, args); 20 | if (siz == 1024) { 21 | buff[1023] = '\n'; 22 | } else { 23 | buff[siz] = '\n'; 24 | siz++; 25 | buff[siz] = '\0'; 26 | } 27 | string log_file_name; 28 | if (TSPConfig::instance()->get("LOG", log_file_name) != -1) { 29 | int fd = open(log_file_name.data(), O_CREAT | O_RDWR | O_APPEND, 30 | S_IRUSR | S_IWUSR); 31 | TSPUtilIO::basic_write(fd, buff, siz); 32 | close(fd); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /TimeServerPlus/src/contrib/utility.h: -------------------------------------------------------------------------------- 1 | #ifndef TSP_UTILITY 2 | #define TSP_UTILITY 3 | 4 | #include "../include/type.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | enum ResultCode { TSP_OK = 0, TSP_ERROR = -1, TSP_AGAIN = -2 }; 12 | 13 | class TSPUtilTime { 14 | public: 15 | static int tostring(time_t t, string &res, const char *fmt = "%F %X"); 16 | static int now(string &res); 17 | }; 18 | 19 | class TSPUtilFile { 20 | public: 21 | static int exist(const char *path); 22 | static int is_directory(const char *path); 23 | static int size(const char *path, off_t &size); 24 | static int last_modify(const char *path, string &res); 25 | static int last_access(const char *path, string &res); 26 | static int last_change(const char *path, string &res); 27 | }; 28 | 29 | class TSPUtilMemory { 30 | public: 31 | static void basic_free(void *p); 32 | static void *basic_malloc(size_t size); 33 | }; 34 | 35 | class TSPUtilIO { 36 | public: 37 | static int basic_write(int fd, char *buf, uint32_t cnt); 38 | static int basic_read(int fd, char *buf, uint32_t cnt); 39 | }; 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /TimeServerPlus/src/contrib/threadpool.h: -------------------------------------------------------------------------------- 1 | #ifndef TSP_THREADPOOL 2 | #define TSP_THREADPOOL 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | using std::vector; 12 | 13 | class TSPThreadPoolManager { 14 | public: 15 | TSPThreadPoolManager(vector &t) : threads(t) {} 16 | ~TSPThreadPoolManager() { 17 | for (size_t i = 0; i < threads.size(); i++) { 18 | if (threads[i].joinable()) 19 | threads[i].join(); 20 | } 21 | } 22 | 23 | private: 24 | TSPThreadPoolManager(const TSPThreadPoolManager &) = delete; 25 | TSPThreadPoolManager &operator=(const TSPThreadPoolManager &) = delete; 26 | vector &threads; 27 | }; 28 | 29 | class TSPThreadPool { 30 | public: 31 | typedef std::function task_t; 32 | 33 | explicit TSPThreadPool(int n = 0); 34 | ~TSPThreadPool(); 35 | 36 | private: 37 | TSPThreadPool(const TSPThreadPool &) = delete; 38 | TSPThreadPool &operator=(const TSPThreadPool &) = delete; 39 | 40 | std::atomic stop; 41 | 42 | std::queue tasks; 43 | std::vector threads; 44 | TSPThreadPoolManager tpm; 45 | }; 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /TimeServerPlus/src/contrib/config.cpp: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | #include "logger.h" 3 | 4 | #include 5 | #include 6 | 7 | TSPConfig *TSPConfig::config = nullptr; 8 | pthread_mutex_t TSPConfig::lock = PTHREAD_MUTEX_INITIALIZER; 9 | 10 | int TSPConfig::parse(const string path) { 11 | std::fstream config_file(path, std::fstream::in); 12 | if (!config_file) { 13 | cout << "config error" << endl; 14 | 15 | config_file.close(); 16 | return -1; 17 | } 18 | 19 | string line, key, value; 20 | config->data.clear(); 21 | while (getline(config_file, line)) { 22 | std::stringstream stream(line); 23 | stream >> key >> value; 24 | if (key != "" && value != "" && 25 | config->data.find("key") == config->data.end()) 26 | config->data.insert(make_pair(key, value)); 27 | } 28 | config_file.close(); 29 | return 0; 30 | } 31 | 32 | int TSPConfig::get(const string key, string &value) { 33 | map::const_iterator it = config->data.find(key); 34 | if (it == data.end()) { 35 | cout << "no exist key:" << key << endl; 36 | return -1; 37 | } 38 | value = it->second; 39 | return 0; 40 | } 41 | 42 | int TSPConfig::exist(const string key, const string value) { 43 | map::const_iterator it = config->data.find(key); 44 | if (it == data.end()) { 45 | cout << "no exist key:" << key << endl; 46 | return -1; 47 | } 48 | return it->second == value; 49 | } 50 | -------------------------------------------------------------------------------- /TimeServerPlus/test/test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | int main(int argc, char const *argv[]) { 11 | if (argc != 2) { 12 | cout << "usage: " << argv[0] << " " << endl; 13 | return -1; 14 | } 15 | 16 | int sockfd; 17 | if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) 18 | cout << "socket error" << endl; 19 | 20 | struct sockaddr_in server; 21 | bzero(&server, sizeof(server)); 22 | server.sin_family = AF_INET; 23 | server.sin_port = htons(8668); 24 | 25 | if (inet_pton(sockfd, argv[1], &server.sin_addr)) 26 | cout << "something wrong in IP address" << endl; 27 | 28 | if (connect(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0) { 29 | cout << "connect error" << endl; 30 | } else { 31 | cout << "send begin" << endl; 32 | char header[] = "GET /time HTTP/1.1\r\n\r\n"; 33 | write(sockfd, &header, sizeof(header)); 34 | cout << "send end" << endl; 35 | cout << "read begin" << endl; 36 | int n = 0, nread = 0; 37 | char result[204800]; 38 | while ((n = read(sockfd, result + nread, sizeof(result))) > 0) { 39 | nread += n; 40 | } 41 | result[nread] = '\0'; 42 | cout << "read end" << endl; 43 | cout << "result: ----" << endl; 44 | cout << result << endl; 45 | } 46 | 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /TimeServerPlus/src/contrib/logger.h: -------------------------------------------------------------------------------- 1 | #ifndef TSP_LOGGER 2 | #define TSP_LOGGER 3 | 4 | #include 5 | #include 6 | 7 | #define level_log(level) \ 8 | va_list args; \ 9 | va_start(args, fmt); \ 10 | log(level, fmt, args); \ 11 | va_end(args); 12 | 13 | enum class TSPLogLevel { INFO, ALERT, WARN, ERROR }; 14 | 15 | class TSPLogger { 16 | 17 | public: 18 | TSPLogger(const TSPLogger &) = delete; 19 | TSPLogger &operator=(const TSPLogger &) = delete; 20 | 21 | void info(const char *fmt, ...) { level_log("INFO"); } 22 | void alert(const char *fmt, ...) { level_log("ALERT"); } 23 | void warn(const char *fmt, ...) { level_log("WARN"); } 24 | void error(const char *fmt, ...) { level_log("ERROR"); } 25 | 26 | static TSPLogger *instance() { 27 | if (logger == nullptr) { 28 | pthread_mutex_lock(&lock); 29 | if (logger == nullptr) 30 | logger = new TSPLogger(); 31 | pthread_mutex_unlock(&lock); 32 | } 33 | return logger; 34 | } 35 | 36 | private: 37 | TSPLogger() = default; 38 | ~TSPLogger() = default; 39 | void log(const char *level, const char *fmt, va_list args); 40 | 41 | static TSPLogger *logger; 42 | static pthread_mutex_t lock; 43 | }; 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /TimeServerPlus/src/modules/module_time.h: -------------------------------------------------------------------------------- 1 | #ifndef TSP_MODULE_TIME_H 2 | #define TSP_MODULE_TIME_H 3 | 4 | #include "../contrib/utility.h" 5 | #include "../core/response.h" 6 | #include "../include/type.h" 7 | #include "load-module.h" 8 | 9 | class TSPTimeLocaltimeResponse : public TSPBasicResponse { 10 | public: 11 | TSPTimeLocaltimeResponse(int _priority, TSPResponsePatternType _type) 12 | : TSPBasicResponse(_priority, _type) {} 13 | ~TSPTimeLocaltimeResponse() {} 14 | 15 | int handle(const TSPRequest &req) final; 16 | }; 17 | 18 | class TSPTimeFileCtimeResponse : public TSPBasicResponse { 19 | public: 20 | TSPTimeFileCtimeResponse(int _priority, TSPResponsePatternType _type) 21 | : TSPBasicResponse(_priority, _type) {} 22 | ~TSPTimeFileCtimeResponse() {} 23 | 24 | int handle(const TSPRequest &req) final; 25 | }; 26 | 27 | class TSPTimeFileAtimeResponse : public TSPBasicResponse { 28 | public: 29 | TSPTimeFileAtimeResponse(int _priority, TSPResponsePatternType _type) 30 | : TSPBasicResponse(_priority, _type) {} 31 | ~TSPTimeFileAtimeResponse() {} 32 | 33 | int handle(const TSPRequest &req) final; 34 | }; 35 | 36 | class TSPTimeFileMtimeResponse : public TSPBasicResponse { 37 | public: 38 | TSPTimeFileMtimeResponse(int _priority, TSPResponsePatternType _type) 39 | : TSPBasicResponse(_priority, _type) {} 40 | ~TSPTimeFileMtimeResponse() {} 41 | 42 | int handle(const TSPRequest &req) final; 43 | }; 44 | 45 | void install_time_modules(ResponseVectorType &t); 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /TimeServerPlus/src/core/response.h: -------------------------------------------------------------------------------- 1 | #ifndef TSP_RESPONSE_H 2 | #define TSP_RESPONSE_H 3 | 4 | #include "../contrib/config.h" 5 | #include "../contrib/utility.h" 6 | #include "../include/type.h" 7 | #include "../modules/load-module.h" 8 | #include "request.h" 9 | 10 | #include 11 | #include 12 | 13 | void tsp_response_headers_end(int sockfd); 14 | void tsp_response_date(int sockfd); 15 | void tsp_response_expires(int sockfd); 16 | void tsp_response_server_name(int sockfd); 17 | void tsp_response_content_length(off_t size, int sockfd); 18 | 19 | void tsp_response_ok(int sockfd); 20 | void tsp_response_bad_request(int sockfd); 21 | void tsp_response_forbidden(int sockfd); 22 | void tsp_response_not_found(int sockfd); 23 | void tsp_response_internal_server_error(int sockfd); 24 | void tsp_response_not_implemented(int sockfd); 25 | void tsp_response_http_version_not_supported(int sockfd); 26 | 27 | typedef struct _TSPResponsePatternType { 28 | regex url_pattern; 29 | string method; 30 | string version; 31 | } TSPResponsePatternType; 32 | 33 | class TSPRequest; 34 | 35 | #define MAX_RESPONSE_PRIORITY 200 36 | #define DEFAULT_RESPONSE_PRIORITY 100 37 | #define MIN_RESPONSE_PRIORITY 0 38 | 39 | class TSPBasicResponse { 40 | public: 41 | explicit TSPBasicResponse(int _priority, TSPResponsePatternType _pattern) 42 | : priority(_priority), pattern(_pattern){}; 43 | virtual ~TSPBasicResponse() = default; 44 | TSPBasicResponse(const TSPBasicResponse &) = default; 45 | TSPBasicResponse &operator=(const TSPBasicResponse &) = default; 46 | 47 | int get_priority() { return priority; } 48 | int match(const TSPRequest &req); 49 | virtual int handle(const TSPRequest &req) = 0; 50 | 51 | private: 52 | int priority = DEFAULT_RESPONSE_PRIORITY; 53 | TSPResponsePatternType pattern; 54 | }; 55 | 56 | void tsp_response(const TSPRequest &req); 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /TimeServerPlus/src/core/request.h: -------------------------------------------------------------------------------- 1 | #ifndef TSP_REQUEST_H 2 | #define TSP_REQUEST_H 3 | 4 | #include "../contrib/logger.h" 5 | #include "../include/type.h" 6 | #include "response.h" 7 | 8 | #include 9 | #include 10 | 11 | typedef map TSPRequestArgsType; 12 | typedef map TSPRequestHeadersType; 13 | #define new_header(key, value) std::make_pair((key), (value)) 14 | #define new_arg(key, value) std::make_pair((key), (value)) 15 | 16 | class TSPRequest { 17 | public: 18 | explicit TSPRequest(int fd) : sockfd(fd){}; 19 | ~TSPRequest() { close(sockfd); }; 20 | TSPRequest(const TSPRequest &) = delete; 21 | TSPRequest &operator=(const TSPRequest &) = delete; 22 | 23 | int parse_from_string(const string &raw_request); 24 | 25 | string get_method() const { return method; } 26 | string get_url() const { return url; } 27 | string get_version() const { return version; } 28 | string get_body() const { return body; } 29 | int get_sockfd() const { return sockfd; } 30 | 31 | string get_args(const string &key) const; 32 | int exist_args(const string &key, const string &value) const; 33 | string get_headers(const string &key) const; 34 | int exist_headers(const string &key, const string &value) const; 35 | 36 | void debug() { 37 | for (auto i : args) 38 | cout << i.first << "#" << i.second << endl; 39 | for (auto i : headers) 40 | cout << i.first << "#" << i.second << endl; 41 | } 42 | 43 | private: 44 | string method; 45 | string url; 46 | string version; 47 | TSPRequestArgsType args; 48 | TSPRequestHeadersType headers; 49 | string body; 50 | int sockfd; 51 | }; 52 | 53 | int parse_args(const string &raw_string, TSPRequestArgsType &args); 54 | int parse_headers(const string &raw_string, TSPRequestHeadersType &headers); 55 | 56 | void tsp_request_handle(const TSPRequest &req); 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /TimeServerPlus/src/modules/module_basic.h: -------------------------------------------------------------------------------- 1 | #ifndef TSP_MODULE_BASIC_H 2 | #define TSP_MODULE_BASIC_H 3 | 4 | #include "../contrib/config.h" 5 | #include "../contrib/logger.h" 6 | #include "../core/response.h" 7 | #include "../include/type.h" 8 | #include "load-module.h" 9 | 10 | #include 11 | #include 12 | 13 | class TSPBasicGetResponse : public TSPBasicResponse { 14 | public: 15 | TSPBasicGetResponse(int _priority, TSPResponsePatternType _pattern) 16 | : TSPBasicResponse(_priority, _pattern) {} 17 | ~TSPBasicGetResponse(){}; 18 | 19 | int handle(const TSPRequest &req) final; 20 | }; 21 | 22 | class TSPBasicHeadResponse : public TSPBasicResponse { 23 | public: 24 | TSPBasicHeadResponse(int _priority, TSPResponsePatternType _pattern) 25 | : TSPBasicResponse(_priority, _pattern) {} 26 | ~TSPBasicHeadResponse(){}; 27 | 28 | int handle(const TSPRequest &req) final; 29 | }; 30 | 31 | class TSPBasicOptionsResponse : public TSPBasicResponse { 32 | public: 33 | TSPBasicOptionsResponse(int _priority, TSPResponsePatternType _pattern) 34 | : TSPBasicResponse(_priority, _pattern) {} 35 | ~TSPBasicOptionsResponse(){}; 36 | 37 | int handle(const TSPRequest &req) final; 38 | }; 39 | 40 | class TSPBasicPostResponse : public TSPBasicResponse { 41 | public: 42 | TSPBasicPostResponse(int _priority, TSPResponsePatternType _pattern) 43 | : TSPBasicResponse(_priority, _pattern) {} 44 | ~TSPBasicPostResponse(){}; 45 | 46 | int handle(const TSPRequest &req) final; 47 | }; 48 | 49 | class TSPBasicPutResponse : public TSPBasicResponse { 50 | public: 51 | TSPBasicPutResponse(int _priority, TSPResponsePatternType _pattern) 52 | : TSPBasicResponse(_priority, _pattern) {} 53 | ~TSPBasicPutResponse(){}; 54 | 55 | int handle(const TSPRequest &req) final; 56 | }; 57 | 58 | class TSPBasicDeleteResponse : public TSPBasicResponse { 59 | public: 60 | TSPBasicDeleteResponse(int _priority, TSPResponsePatternType _pattern) 61 | : TSPBasicResponse(_priority, _pattern) {} 62 | ~TSPBasicDeleteResponse(){}; 63 | 64 | int handle(const TSPRequest &req) final; 65 | }; 66 | 67 | void install_basic_modules(ResponseVectorType &t); 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /TimeServerPlus/src/contrib/utility.cpp: -------------------------------------------------------------------------------- 1 | #include "utility.h" 2 | #include "logger.h" 3 | 4 | #include 5 | #include 6 | 7 | int TSPUtilTime::tostring(time_t t, string &res, const char *fmt) { 8 | struct tm *time_tm = localtime(&t); 9 | char buff[128]; 10 | strftime(buff, sizeof(buff), fmt, time_tm); 11 | res = string(buff); 12 | return 0; 13 | } 14 | 15 | int TSPUtilTime::now(string &res) { 16 | time_t t = time(NULL); 17 | return tostring(t, res, "%F %X"); 18 | } 19 | 20 | int TSPUtilFile::is_directory(const char *path) { 21 | int dir = open(path, O_DIRECTORY); 22 | close(dir); 23 | return dir == -1 ? -1 : 0; 24 | } 25 | 26 | int TSPUtilFile::exist(const char *path) { 27 | int res = open(path, O_RDONLY | O_NOFOLLOW), dir = open(path, O_DIRECTORY); 28 | if (dir != -1) 29 | res = -1; 30 | close(dir); 31 | close(res); 32 | return res == -1 ? -1 : 0; 33 | } 34 | 35 | int TSPUtilFile::size(const char *path, off_t &size) { 36 | struct stat tmp; 37 | int res = stat(path, &tmp); 38 | if (res == -1) { 39 | size = 0; 40 | return -1; 41 | } 42 | size = tmp.st_size; 43 | return 0; 44 | } 45 | 46 | int TSPUtilFile::last_modify(const char *path, string &res) { 47 | struct stat tmp; 48 | int state = stat(path, &tmp); 49 | if (state == -1) { 50 | res = ""; 51 | return -1; 52 | } 53 | TSPUtilTime::tostring(tmp.st_mtime, res); 54 | return 0; 55 | } 56 | 57 | int TSPUtilFile::last_access(const char *path, string &res) { 58 | struct stat tmp; 59 | int state = stat(path, &tmp); 60 | if (state == -1) { 61 | res = ""; 62 | return -1; 63 | } 64 | TSPUtilTime::tostring(tmp.st_atime, res); 65 | return 0; 66 | } 67 | 68 | int TSPUtilFile::last_change(const char *path, string &res) { 69 | struct stat tmp; 70 | int state = stat(path, &tmp); 71 | if (state == -1) { 72 | res = ""; 73 | return -1; 74 | } 75 | TSPUtilTime::tostring(tmp.st_ctime, res); 76 | return 0; 77 | } 78 | 79 | void TSPUtilMemory::basic_free(void *p) { free(p); } 80 | 81 | void *TSPUtilMemory::basic_malloc(size_t size) { 82 | void *res = malloc(size); 83 | if (res == NULL) { 84 | TSPLogger::instance()->error("basic_malloc error [%s]", strerror(errno)); 85 | exit(-1); 86 | } 87 | return res; 88 | } 89 | 90 | int TSPUtilIO::basic_write(int fd, char *buf, uint32_t cnt) { 91 | while (true) { 92 | int n = write(fd, buf, cnt); 93 | if (n >= 0) 94 | return n; 95 | int err = errno; 96 | switch (err) { 97 | case EINTR: 98 | break; 99 | case EAGAIN: 100 | return TSP_AGAIN; 101 | default: 102 | return TSP_ERROR; 103 | } 104 | } 105 | return TSP_OK; 106 | } 107 | 108 | int TSPUtilIO::basic_read(int fd, char *buf, uint32_t cnt) { 109 | while (true) { 110 | int n = read(fd, buf, cnt); 111 | if (n >= 0) 112 | return n; 113 | int err = errno; 114 | switch (err) { 115 | case EINTR: 116 | break; 117 | case EAGAIN: 118 | return TSP_AGAIN; 119 | default: 120 | return TSP_ERROR; 121 | } 122 | } 123 | return TSP_OK; 124 | } 125 | -------------------------------------------------------------------------------- /TimeServerPlus/src/core/request.cpp: -------------------------------------------------------------------------------- 1 | #include "request.h" 2 | 3 | int TSPRequest::parse_from_string(const string &raw_request) { 4 | if (raw_request.empty()) { 5 | TSPLogger::instance()->error("headers parse error empty raw_request [%s]", 6 | strerror(errno)); 7 | return -1; 8 | } 9 | 10 | string rn("\r\n"), rnrn("\r\n\r\n"); 11 | 12 | string method, url, version, body; 13 | TSPRequestArgsType args; 14 | TSPRequestHeadersType headers; 15 | 16 | size_t pre = 0, nxt = 0, rnsize = 2; 17 | 18 | if ((nxt = raw_request.find(rn, pre)) != string::npos) { 19 | string line(raw_request.substr(pre, nxt - pre)); 20 | cout << line << endl; 21 | std::stringstream s(line); 22 | s >> method; 23 | s >> url; 24 | s >> version; 25 | 26 | if (version.find("HTTP", 0) == string::npos) 27 | return -1; 28 | 29 | string url_line(url); 30 | if (url_line.find("..", 0) != string::npos) 31 | url_line = "/"; 32 | 33 | if (parse_args(url_line, args) == -1) 34 | return -1; 35 | 36 | pre = nxt; 37 | } else { 38 | TSPLogger::instance()->error( 39 | "headers parse error raw_request without '\r\n' [%s]", strerror(errno)); 40 | return -1; 41 | } 42 | 43 | size_t headers_end_pos = 0; 44 | 45 | if ((headers_end_pos = raw_request.find(rnrn, pre)) != string::npos) { 46 | string header_line; 47 | nxt = raw_request.find(rn, pre + rnsize); 48 | while (nxt <= headers_end_pos) { 49 | header_line = raw_request.substr(pre + rnsize, nxt - pre - rnsize); 50 | if (parse_headers(header_line, headers) == -1) 51 | return -1; 52 | pre = nxt; 53 | nxt = raw_request.find(rn, pre + rnsize); 54 | } 55 | } 56 | 57 | body = raw_request.substr(headers_end_pos + rnsize + rnsize, 58 | raw_request.size() - rnsize - rnsize); 59 | 60 | this->method = method; 61 | this->url = url; 62 | this->version = version; 63 | this->body = body; 64 | 65 | this->args = args; 66 | this->headers = headers; 67 | 68 | return 0; 69 | } 70 | 71 | int parse_args(const string &raw_string, TSPRequestArgsType &args) { 72 | if (raw_string.empty()) 73 | return -1; 74 | size_t begin = raw_string.find('?', 0); 75 | 76 | if (begin != string::npos) { 77 | begin++; 78 | size_t i = begin, j = begin; 79 | string key, value; 80 | 81 | size_t next = raw_string.find("&&", begin); 82 | while (next != string::npos) { 83 | while (raw_string[j] != '=') 84 | j++; 85 | 86 | key = raw_string.substr(i, j - i); 87 | 88 | j++; 89 | i = j; 90 | 91 | j = next; 92 | 93 | value = raw_string.substr(i, j - i); 94 | args.insert(new_arg(key, value)); 95 | 96 | i = j = next + 2; 97 | next = raw_string.find("&&", i); 98 | } 99 | 100 | while (raw_string[j] != '=' && j < raw_string.size()) 101 | j++; 102 | 103 | if (j == raw_string.size()) 104 | return -1; 105 | 106 | key = raw_string.substr(i, j - i); 107 | 108 | j++; 109 | i = j; 110 | 111 | j = raw_string.size(); 112 | 113 | value = raw_string.substr(i, j - i); 114 | args.insert(new_arg(key, value)); 115 | } 116 | return 0; 117 | } 118 | 119 | int parse_headers(const string &raw_string, TSPRequestHeadersType &headers) { 120 | if (raw_string.empty()) 121 | return -1; 122 | 123 | size_t i = 0, j = 0; 124 | 125 | while (isblank(raw_string[j])) 126 | j++; 127 | i = j; 128 | 129 | while (!isblank(raw_string[j]) && raw_string[j] != ':') 130 | j++; 131 | 132 | string key = raw_string.substr(i, j - i); 133 | 134 | while (!isblank(raw_string[j])) 135 | j++; 136 | 137 | i = j; 138 | 139 | while (j != raw_string.size()) 140 | j++; 141 | 142 | string value = raw_string.substr(i, j - i); 143 | 144 | headers.insert(new_header(key, value)); 145 | 146 | return 0; 147 | } 148 | 149 | void tsp_request_handle(const TSPRequest &req) { tsp_response(req); } 150 | -------------------------------------------------------------------------------- /TimeServerPlus/src/core/core.cpp: -------------------------------------------------------------------------------- 1 | #include "core.h" 2 | 3 | int tsp_socket(int domain, int type, int protocol) { 4 | int fd = socket(domain, type, protocol); 5 | if (fd == -1) { 6 | TSPLogger::instance()->error("socket init error [%s]", strerror(errno)); 7 | exit(-1); 8 | } 9 | return fd; 10 | } 11 | 12 | int tsp_socket_nonblocking(int sockfd) { 13 | int f = fcntl(sockfd, F_GETFL, 0); 14 | if (f < 0) { 15 | TSPLogger::instance()->error("socket nonblocking GETFL error [%s] %d ", 16 | sockfd, strerror(errno)); 17 | exit(-1); 18 | } 19 | f |= O_NONBLOCK; 20 | int res = fcntl(sockfd, F_SETFL, f); 21 | if (res < 0) { 22 | TSPLogger::instance()->error("socket nonblocking SETFL error %d [%s]", 23 | sockfd, strerror(errno)); 24 | exit(-1); 25 | } 26 | } 27 | 28 | int tsp_socket_reuseaddr(int sockfd) { 29 | int reuse_on = -1; 30 | int res = 31 | setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse_on, sizeof(reuse_on)); 32 | if (res < 0) { 33 | TSPLogger::instance()->error("socket reuseraddr setting error %d [%s]", 34 | sockfd, strerror(errno)); 35 | exit(-1); 36 | } 37 | } 38 | 39 | void tsp_socket_nodelay(int sockfd) { 40 | int nodelay = 1; 41 | int res = 42 | setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &nodelay, sizeof(nodelay)); 43 | if (res == -1) { 44 | TSPLogger::instance()->error("socket nodelay setting error %d [%s]", sockfd, 45 | strerror(errno)); 46 | exit(-1); 47 | } 48 | } 49 | 50 | void tsp_socket_set_timeout(int sockfd, int sec, int usec) { 51 | struct timeval val = {sec, usec}; 52 | int res = setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &val, sizeof(val)); 53 | if (res == -1) { 54 | TSPLogger::instance()->error("socket timeout setting error %d [%s]", sockfd, 55 | strerror(errno)); 56 | exit(-1); 57 | } 58 | } 59 | void tsp_socket_bind(int sockfd, const struct sockaddr *addr, socklen_t len) { 60 | if (bind(sockfd, addr, len) == -1) { 61 | TSPLogger::instance()->error("socket bind error [%s]", strerror(errno)); 62 | exit(-1); 63 | } 64 | } 65 | 66 | void tsp_socket_listen(int sockfd, int backlog) { 67 | if (listen(sockfd, backlog) == -1) { 68 | TSPLogger::instance()->error("socket listen error [%s]", strerror(errno)); 69 | exit(-1); 70 | } 71 | } 72 | 73 | int tsp_socket_accept(int sockfd, struct sockaddr *addr, socklen_t *len) { 74 | int new_sockfd = 0; 75 | while (true) { 76 | new_sockfd = accept(sockfd, addr, len); 77 | if (new_sockfd > 0) 78 | return new_sockfd; 79 | if (new_sockfd == -1) { 80 | if (errno != EAGAIN && errno != EINTR && errno != EPROTO && 81 | errno != ECONNABORTED) { 82 | TSPLogger::instance()->error("socket accept error [%s]", 83 | strerror(errno)); 84 | exit(-1); 85 | } 86 | } 87 | } 88 | } 89 | 90 | int tsp_epoll_create(int size) { 91 | int epollfd = epoll_create(size); 92 | if (epollfd == -1) { 93 | TSPLogger::instance()->error("epoll create error size-%d [%s]", size, 94 | strerror(errno)); 95 | exit(-1); 96 | } 97 | return epollfd; 98 | } 99 | 100 | void tsp_epoll_ctl(int epollfd, int op, int fd, struct epoll_event *event) { 101 | if (epoll_ctl(epollfd, op, fd, event) == -1) { 102 | TSPLogger::instance()->error("epoll ctl error %d of %d [%s]", epollfd, fd, 103 | strerror(errno)); 104 | exit(-1); 105 | } 106 | } 107 | 108 | int tsp_epoll_wait(int epollfd, struct epoll_event *events, int maxevents, 109 | int timeout) { 110 | int num = epoll_wait(epollfd, events, maxevents, timeout); 111 | while (num == -1) { 112 | if (errno != EINTR) { 113 | TSPLogger::instance()->error("epoll wait error %d [%s]", epollfd, 114 | strerror(errno)); 115 | exit(-1); 116 | } 117 | num = epoll_wait(epollfd, events, maxevents, timeout); 118 | } 119 | return num; 120 | } 121 | -------------------------------------------------------------------------------- /TimeServerPlus/src/core/response.cpp: -------------------------------------------------------------------------------- 1 | #include "response.h" 2 | 3 | void tsp_response_headers_end(int sockfd) { 4 | char status[10] = TSP_RN; 5 | write(sockfd, status, strlen(status)); 6 | } 7 | 8 | void tsp_response_date(int sockfd) { 9 | time_t now = time(nullptr); 10 | struct tm *gmt = gmtime(&now); 11 | 12 | string wdays[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; 13 | string mons[] = {"Jan", "Feb", "Mar", "Apr", "May", "June", 14 | "July", "Aug", "Sept", "Oct", "Nov", "Dec"}; 15 | 16 | char status[1024]; 17 | 18 | snprintf(status, sizeof(status), "Date: %s, %d %s %4d %02d:%02d:%02d GMT\r\n", 19 | wdays[gmt->tm_wday].data(), gmt->tm_mday, mons[gmt->tm_mon].data(), 20 | gmt->tm_year + 1900, gmt->tm_hour, gmt->tm_min, gmt->tm_sec); 21 | 22 | write(sockfd, status, strlen(status)); 23 | } 24 | 25 | void tsp_response_expires(int sockfd) {} 26 | 27 | void tsp_response_server_name(int sockfd) { 28 | string name; 29 | if (TSPConfig::instance()->get("SERVERSTRING", name) == -1) 30 | name = "TimeServerPlus(TSP)/0.1.171007(cpp)"; 31 | char status[1024]; 32 | snprintf(status, sizeof(status), "Server: %s\r\n", name.data()); 33 | write(sockfd, status, strlen(status)); 34 | } 35 | 36 | void tsp_response_content_length(off_t size, int sockfd) { 37 | char status[1024]; 38 | snprintf(status, sizeof(status), "Content-Length: %d\r\n", (int)size); 39 | write(sockfd, status, strlen(status)); 40 | } 41 | 42 | void tsp_response_ok(int sockfd) { 43 | char status[1024]; 44 | snprintf(status, sizeof(status), "HTTP/1.1 %d %s\r\n", TSP_RESPONSE_OK, "OK"); 45 | write(sockfd, status, strlen(status)); 46 | } 47 | 48 | void tsp_response_bad_request(int sockfd) { 49 | char status[1024]; 50 | snprintf(status, sizeof(status), "HTTP/1.1 %d %s\r\n", 51 | TSP_RESPONSE_BAD_REQUEST, "Bad Request"); 52 | printf("%s\n", status); 53 | write(sockfd, status, strlen(status)); 54 | } 55 | 56 | void tsp_response_forbidden(int sockfd) { 57 | char status[1024]; 58 | snprintf(status, sizeof(status), "HTTP/1.1 %d %s\r\n", TSP_RESPONSE_FORBIDDEN, 59 | "Forbidden"); 60 | write(sockfd, status, strlen(status)); 61 | } 62 | 63 | void tsp_response_not_found(int sockfd) { 64 | char status[1024]; 65 | snprintf(status, sizeof(status), "HTTP/1.1 %d %s\r\n", TSP_RESPONSE_NOT_FOUND, 66 | "Not Found"); 67 | write(sockfd, status, strlen(status)); 68 | } 69 | 70 | void tsp_response_internal_server_error(int sockfd) { 71 | char status[1024]; 72 | snprintf(status, sizeof(status), "HTTP/1.1 %d %s\r\n", 73 | TSP_RESPONSE_INTERNAL_SERVER_ERROR, "Internal Server Error"); 74 | write(sockfd, status, strlen(status)); 75 | } 76 | 77 | void tsp_response_not_implemented(int sockfd) { 78 | char status[1024]; 79 | snprintf(status, sizeof(status), "HTTP/1.1 %d %s\r\n", 80 | TSP_RESPONSE_NOIMPLEMENTED, "Not implemented"); 81 | write(sockfd, status, strlen(status)); 82 | } 83 | 84 | void tsp_response_http_version_not_supported(int sockfd) { 85 | char status[1024]; 86 | snprintf(status, sizeof(status), "HTTP/1.1 %d %s\r\n", 87 | TSP_RESPONSE_HTTP_VERSION_NOT_SUPPORTED, 88 | "Http Version Not Supported"); 89 | write(sockfd, status, strlen(status)); 90 | } 91 | 92 | int TSPBasicResponse::match(const TSPRequest &req) { 93 | string url = req.get_url(); 94 | string method = req.get_method(); 95 | string version = req.get_version(); 96 | 97 | if (!std::regex_match(url, this->pattern.url_pattern)) 98 | return -1; 99 | if (this->pattern.method != "" && method != this->pattern.method) 100 | return -1; 101 | if (this->pattern.version == string("") || 102 | this->pattern.version == string()) { 103 | if (version != string("HTTP/1.1")) 104 | return -1; 105 | } 106 | if (this->pattern.version != version) 107 | return -1; 108 | return 0; 109 | } 110 | 111 | void tsp_response(const TSPRequest &req) { 112 | bool match = false; 113 | 114 | for (TSPBasicResponse *i : TSPModuleManager::get()) { 115 | if (i->match(req) == 0) { 116 | i->handle(req); 117 | match = true; 118 | break; 119 | } 120 | } 121 | 122 | if (!match) { 123 | int sockfd = req.get_sockfd(); 124 | if (req.get_version() != "HTTP/1.1") { 125 | tsp_response_http_version_not_supported(sockfd); 126 | tsp_response_server_name(sockfd); 127 | tsp_response_headers_end(sockfd); 128 | } else { 129 | tsp_response_not_implemented(sockfd); 130 | tsp_response_server_name(sockfd); 131 | tsp_response_headers_end(sockfd); 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /time-server.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define SERVER_STRING "Server: time-server/0.1.170924(c)\r\n" 12 | 13 | int SHOW_HEADER_DETAIL = 0; 14 | 15 | void error_exit(const char *s) { 16 | perror(s); 17 | exit(1); 18 | } 19 | 20 | int init(uint16_t port) { 21 | int httpd = socket(AF_INET, SOCK_STREAM, 0); 22 | if (httpd == -1) 23 | error_exit("socket init failed in init\n"); 24 | 25 | struct sockaddr_in name; 26 | memset(&name, 0, sizeof(name)); 27 | name.sin_family = AF_INET; 28 | name.sin_port = htons(port); 29 | name.sin_addr.s_addr = htonl(INADDR_ANY); 30 | 31 | int reuse_on = 1; 32 | if (setsockopt(httpd, SOL_SOCKET, SO_REUSEADDR, &reuse_on, sizeof(reuse_on)) < 33 | 0) 34 | error_exit("setsocketopt failed in init\n"); 35 | if (bind(httpd, (struct sockaddr *)&name, sizeof(name)) < 0) 36 | error_exit("bind failed in init\n"); 37 | 38 | if (listen(httpd, 1000) < 0) 39 | error_exit("listen failed\n"); 40 | 41 | printf("listen port %d success!!\n", port); 42 | 43 | return httpd; 44 | } 45 | 46 | int get_socket_line(int sockfd, char *buf, int size) { 47 | int i = 0; 48 | char in = '\0'; 49 | int len; 50 | while (i < size - 1 && in != '\n') { 51 | len = recv(sockfd, &in, 1, 0); 52 | if (len > 0) { 53 | if (in == '\r') { 54 | len = recv(sockfd, &in, 1, MSG_PEEK); 55 | if (len > 0 && in == '\n') 56 | recv(sockfd, &in, 1, 0); 57 | else 58 | in = '\n'; 59 | } 60 | buf[i] = in; 61 | i++; 62 | } else 63 | in = '\n'; 64 | } 65 | buf[i] = '\0'; 66 | return i; 67 | } 68 | 69 | void service(int sockfd) { 70 | char buf[1024]; 71 | 72 | sprintf(buf, "HTTP/1.0 200 OK\r\n"); 73 | send(sockfd, buf, strlen(buf), 0); 74 | sprintf(buf, SERVER_STRING); 75 | send(sockfd, buf, strlen(buf), 0); 76 | sprintf(buf, "Content-Type: text/html\r\n"); 77 | send(sockfd, buf, strlen(buf), 0); 78 | sprintf(buf, "\r\n"); 79 | send(sockfd, buf, strlen(buf), 0); 80 | 81 | struct tm *now; 82 | time_t timer = time(NULL); 83 | now = localtime(&timer); 84 | strftime(buf, sizeof(buf), "

Now: %F %X

", now); 85 | send(sockfd, buf, strlen(buf), 0); 86 | } 87 | 88 | void refuse_to_service(int sockfd) { 89 | char buf[1024]; 90 | 91 | sprintf(buf, "HTTP/1.0 403 Forbidden\r\n"); 92 | send(sockfd, buf, strlen(buf), 0); 93 | sprintf(buf, SERVER_STRING); 94 | send(sockfd, buf, strlen(buf), 0); 95 | sprintf(buf, "Content-Type: text/html\r\n"); 96 | send(sockfd, buf, strlen(buf), 0); 97 | sprintf(buf, "\r\n"); 98 | send(sockfd, buf, strlen(buf), 0); 99 | sprintf(buf, "

Refuse

"); 100 | send(sockfd, buf, strlen(buf), 0); 101 | } 102 | 103 | void accept_request(void *arg) { 104 | 105 | int client_socket = (intptr_t)arg; 106 | 107 | char headers[512]; 108 | char method[20], path[512]; 109 | get_socket_line(client_socket, headers, sizeof(headers)); 110 | 111 | int i = 0; 112 | while (!isspace(headers[i]) && (unsigned)(i) < sizeof(method) - 1) { 113 | method[i] = headers[i]; 114 | i++; 115 | } 116 | method[i] = '\0'; 117 | i++; 118 | while (!isspace(headers[i]) && (unsigned)(i) < sizeof(path) - 1) { 119 | path[i - strlen(method) - 1] = headers[i]; 120 | i++; 121 | } 122 | path[i] = '\0'; 123 | 124 | printf("sockfd %d handling...\n", client_socket); 125 | printf("method is '%s' and path is '%s'\n", method, path); 126 | 127 | char buf[255]; 128 | int len = get_socket_line(client_socket, buf, sizeof(buf)); 129 | while (len > 0 && strcmp(buf, "\n")) { 130 | if (SHOW_HEADER_DETAIL) 131 | printf("(%d)##: %s", client_socket, buf); 132 | len = get_socket_line(client_socket, buf, sizeof(buf)); 133 | } 134 | 135 | if (strcasecmp(method, "GET") == 0) 136 | service(client_socket); 137 | else 138 | refuse_to_service(client_socket); 139 | 140 | close(client_socket); 141 | } 142 | 143 | int main(int argc, char const *argv[]) { 144 | uint16_t port = 8600; 145 | int server_socket = -1; 146 | 147 | server_socket = init(port); 148 | printf("running ...\n"); 149 | 150 | int client_socket = -1; 151 | struct sockaddr_in client_name; 152 | socklen_t client_name_len = sizeof(client_name); 153 | pthread_t new_pthread; 154 | 155 | while (1) { 156 | client_socket = accept(server_socket, (struct sockaddr *)&client_name, 157 | &client_name_len); 158 | if (client_socket == -1) 159 | error_exit("accept failed\n"); 160 | if (pthread_create(&new_pthread, NULL, (void *)accept_request, 161 | (void *)(intptr_t)client_socket) < 0) 162 | error_exit("pthread_create failed\n"); 163 | } 164 | 165 | close(server_socket); 166 | return 0; 167 | } 168 | -------------------------------------------------------------------------------- /TimeServerPlus/src/modules/module_basic.cpp: -------------------------------------------------------------------------------- 1 | #include "module_basic.h" 2 | 3 | // curl 127.0.0.1:8668 4 | int TSPBasicGetResponse::handle(const TSPRequest &req) { 5 | int client_sockfd = req.get_sockfd(); 6 | 7 | string path, index; 8 | TSPConfig::instance()->get("DOCROOT", path); 9 | string file = path + req.get_url(); 10 | if (req.get_url() == "/") 11 | if (TSPConfig::instance()->get("INDEX", index) != -1) 12 | file.append(index); 13 | 14 | if (TSPUtilFile::is_directory(file.data()) == 0) { 15 | string index; 16 | TSPConfig::instance()->get("INDEX", index); 17 | if (file[file.length() - 1] == '/') 18 | file.append(index); 19 | else 20 | file.append("/" + index); 21 | } 22 | 23 | if (TSPUtilFile::exist(file.data()) == 0) { 24 | int fd = open(file.data(), O_RDONLY); 25 | off_t size = 0; 26 | TSPUtilFile::size(file.data(), size); 27 | off_t nwrite = 0; 28 | tsp_response_ok(client_sockfd); 29 | tsp_response_server_name(client_sockfd); 30 | tsp_response_content_length(size, client_sockfd); 31 | tsp_response_headers_end(client_sockfd); 32 | sendfile(client_sockfd, fd, &nwrite, size); 33 | while (nwrite < size) { 34 | sendfile(client_sockfd, fd, &nwrite, size); 35 | } 36 | close(fd); 37 | } else { 38 | tsp_response_not_found(client_sockfd); 39 | tsp_response_server_name(client_sockfd); 40 | tsp_response_headers_end(client_sockfd); 41 | } 42 | } 43 | 44 | // curl 127.0.0.1:8668 -I 45 | int TSPBasicHeadResponse::handle(const TSPRequest &req) { 46 | int client_sockfd = req.get_sockfd(); 47 | 48 | string path, index; 49 | TSPConfig::instance()->get("DOCROOT", path); 50 | string file = path + req.get_url(); 51 | if (req.get_url() == "/") 52 | if (TSPConfig::instance()->get("INDEX", index) != -1) 53 | file.append(index); 54 | 55 | if (TSPUtilFile::is_directory(file.data()) == 0) { 56 | string index; 57 | TSPConfig::instance()->get("INDEX", index); 58 | if (file[file.length() - 1] == '/') 59 | file.append(index); 60 | else 61 | file.append("/" + index); 62 | } 63 | 64 | if (TSPUtilFile::exist(file.data()) == 0) { 65 | int fd = open(file.data(), O_RDONLY); 66 | off_t size = 0; 67 | TSPUtilFile::size(file.data(), size); 68 | tsp_response_ok(client_sockfd); 69 | tsp_response_server_name(client_sockfd); 70 | tsp_response_content_length(size, client_sockfd); 71 | tsp_response_headers_end(client_sockfd); 72 | close(fd); 73 | } else { 74 | tsp_response_not_found(client_sockfd); 75 | tsp_response_server_name(client_sockfd); 76 | tsp_response_headers_end(client_sockfd); 77 | } 78 | } 79 | 80 | // curl -X OPTIONS 127.0.0.1:8668 -i 81 | int TSPBasicOptionsResponse::handle(const TSPRequest &req) { 82 | int client_sockfd = req.get_sockfd(); 83 | char allow[1024] = "Allow: OPTIONS, GET, HEAD\r\n"; 84 | tsp_response_ok(client_sockfd); 85 | write(client_sockfd, allow, strlen(allow)); 86 | tsp_response_date(client_sockfd); 87 | tsp_response_server_name(client_sockfd); 88 | tsp_response_content_length((off_t)0, client_sockfd); 89 | tsp_response_headers_end(client_sockfd); 90 | } 91 | 92 | // curl -X POST 127.0.0.1:8668 -i 93 | int TSPBasicPostResponse::handle(const TSPRequest &req) { 94 | int client_sockfd = req.get_sockfd(); 95 | 96 | tsp_response_not_implemented(client_sockfd); 97 | tsp_response_date(client_sockfd); 98 | tsp_response_server_name(client_sockfd); 99 | tsp_response_content_length((off_t)0, client_sockfd); 100 | tsp_response_headers_end(client_sockfd); 101 | } 102 | 103 | // curl -X PUT 127.0.0.1:8668 -i -d "body" 104 | int TSPBasicPutResponse::handle(const TSPRequest &req) { 105 | int client_sockfd = req.get_sockfd(); 106 | 107 | tsp_response_not_implemented(client_sockfd); 108 | tsp_response_date(client_sockfd); 109 | tsp_response_server_name(client_sockfd); 110 | tsp_response_content_length((off_t)0, client_sockfd); 111 | tsp_response_headers_end(client_sockfd); 112 | } 113 | 114 | // curl -X DELETE 127.0.0.1:8668 -i 115 | int TSPBasicDeleteResponse::handle(const TSPRequest &req) { 116 | int client_sockfd = req.get_sockfd(); 117 | 118 | tsp_response_not_implemented(client_sockfd); 119 | tsp_response_date(client_sockfd); 120 | tsp_response_server_name(client_sockfd); 121 | tsp_response_content_length((off_t)0, client_sockfd); 122 | tsp_response_headers_end(client_sockfd); 123 | } 124 | 125 | void install_basic_modules(ResponseVectorType &t) { 126 | t.push_back(new TSPBasicGetResponse(MIN_RESPONSE_PRIORITY, 127 | {regex("^.*$"), "GET", "HTTP/1.1"})); 128 | t.push_back(new TSPBasicHeadResponse(MIN_RESPONSE_PRIORITY, 129 | {regex("^.*$"), "HEAD", "HTTP/1.1"})); 130 | t.push_back(new TSPBasicOptionsResponse( 131 | MIN_RESPONSE_PRIORITY, {regex("^.*$"), "OPTIONS", "HTTP/1.1"})); 132 | t.push_back(new TSPBasicPostResponse(MIN_RESPONSE_PRIORITY, 133 | {regex("^.*$"), "POST", "HTTP/1.1"})); 134 | t.push_back(new TSPBasicPutResponse(MIN_RESPONSE_PRIORITY, 135 | {regex("^.*$"), "PUT", "HTTP/1.1"})); 136 | t.push_back(new TSPBasicDeleteResponse( 137 | MIN_RESPONSE_PRIORITY, {regex("^.*$"), "DELETE", "HTTP/1.1"})); 138 | } 139 | -------------------------------------------------------------------------------- /TimeServerPlus/src/modules/module_time.cpp: -------------------------------------------------------------------------------- 1 | #include "module_time.h" 2 | 3 | int TSPTimeLocaltimeResponse::handle(const TSPRequest &req) { 4 | int sockfd = req.get_sockfd(); 5 | string file = req.get_url(); 6 | 7 | tsp_response_ok(sockfd); 8 | tsp_response_headers_end(sockfd); 9 | 10 | char body[1024]; 11 | struct tm *now; 12 | time_t timer = time(NULL); 13 | now = localtime(&timer); 14 | strftime(body, sizeof(body), "

Now: %F %X

\n", now); 15 | 16 | write(sockfd, body, strlen(body)); 17 | } 18 | 19 | int TSPTimeFileCtimeResponse::handle(const TSPRequest &req) { 20 | int client_sockfd = req.get_sockfd(); 21 | 22 | string path, index; 23 | TSPConfig::instance()->get("DOCROOT", path); 24 | string file = path + req.get_url(); 25 | file = file.substr(0, file.find_first_of("?")); 26 | if (req.get_url() == "/") 27 | if (TSPConfig::instance()->get("INDEX", index) != -1) 28 | file.append(index); 29 | 30 | if (TSPUtilFile::is_directory(file.data()) == 0) { 31 | string index; 32 | TSPConfig::instance()->get("INDEX", index); 33 | if (file[file.length() - 1] == '/') 34 | file.append(index); 35 | else 36 | file.append("/" + index); 37 | } 38 | 39 | if (TSPUtilFile::exist(file.data()) == 0) { 40 | string res; 41 | TSPUtilFile::last_change(file.data(), res); 42 | res = "

" + res + "

"; 43 | off_t size = 0; 44 | size = res.length(); 45 | tsp_response_ok(client_sockfd); 46 | tsp_response_server_name(client_sockfd); 47 | tsp_response_content_length(size, client_sockfd); 48 | tsp_response_headers_end(client_sockfd); 49 | TSPUtilIO::basic_write(client_sockfd, const_cast(res.c_str()), 50 | res.length()); 51 | } else { 52 | tsp_response_not_found(client_sockfd); 53 | tsp_response_server_name(client_sockfd); 54 | tsp_response_headers_end(client_sockfd); 55 | } 56 | } 57 | 58 | int TSPTimeFileAtimeResponse::handle(const TSPRequest &req) { 59 | int client_sockfd = req.get_sockfd(); 60 | 61 | string path, index; 62 | TSPConfig::instance()->get("DOCROOT", path); 63 | string file = path + req.get_url(); 64 | file = file.substr(0, file.find_first_of("?")); 65 | if (req.get_url() == "/") 66 | if (TSPConfig::instance()->get("INDEX", index) != -1) 67 | file.append(index); 68 | 69 | if (TSPUtilFile::is_directory(file.data()) == 0) { 70 | string index; 71 | TSPConfig::instance()->get("INDEX", index); 72 | if (file[file.length() - 1] == '/') 73 | file.append(index); 74 | else 75 | file.append("/" + index); 76 | } 77 | 78 | if (TSPUtilFile::exist(file.data()) == 0) { 79 | string res; 80 | TSPUtilFile::last_access(file.data(), res); 81 | res = "

" + res + "

"; 82 | off_t size = 0; 83 | size = res.length(); 84 | tsp_response_ok(client_sockfd); 85 | tsp_response_server_name(client_sockfd); 86 | tsp_response_content_length(size, client_sockfd); 87 | tsp_response_headers_end(client_sockfd); 88 | TSPUtilIO::basic_write(client_sockfd, const_cast(res.c_str()), 89 | res.length()); 90 | } else { 91 | tsp_response_not_found(client_sockfd); 92 | tsp_response_server_name(client_sockfd); 93 | tsp_response_headers_end(client_sockfd); 94 | } 95 | } 96 | 97 | int TSPTimeFileMtimeResponse::handle(const TSPRequest &req) { 98 | int client_sockfd = req.get_sockfd(); 99 | 100 | string path, index; 101 | TSPConfig::instance()->get("DOCROOT", path); 102 | string file = path + req.get_url(); 103 | file = file.substr(0, file.find_first_of("?")); 104 | if (req.get_url() == "/") 105 | if (TSPConfig::instance()->get("INDEX", index) != -1) 106 | file.append(index); 107 | 108 | if (TSPUtilFile::is_directory(file.data()) == 0) { 109 | string index; 110 | TSPConfig::instance()->get("INDEX", index); 111 | if (file[file.length() - 1] == '/') 112 | file.append(index); 113 | else 114 | file.append("/" + index); 115 | } 116 | 117 | if (TSPUtilFile::exist(file.data()) == 0) { 118 | string res; 119 | TSPUtilFile::last_modify(file.data(), res); 120 | res = "

" + res + "

"; 121 | off_t size = 0; 122 | size = res.length(); 123 | tsp_response_ok(client_sockfd); 124 | tsp_response_server_name(client_sockfd); 125 | tsp_response_content_length(size, client_sockfd); 126 | tsp_response_headers_end(client_sockfd); 127 | TSPUtilIO::basic_write(client_sockfd, const_cast(res.c_str()), 128 | res.length()); 129 | } else { 130 | tsp_response_not_found(client_sockfd); 131 | tsp_response_server_name(client_sockfd); 132 | tsp_response_headers_end(client_sockfd); 133 | } 134 | } 135 | 136 | void install_time_modules(ResponseVectorType &t) { 137 | t.push_back(new TSPTimeFileCtimeResponse( 138 | DEFAULT_RESPONSE_PRIORITY, {regex("^.*?ctime=1$"), "GET", "HTTP/1.1"})); 139 | t.push_back(new TSPTimeFileAtimeResponse( 140 | DEFAULT_RESPONSE_PRIORITY, {regex("^.*?atime=1$"), "GET", "HTTP/1.1"})); 141 | t.push_back(new TSPTimeFileMtimeResponse( 142 | DEFAULT_RESPONSE_PRIORITY, {regex("^.*?mtime=1$"), "GET", "HTTP/1.1"})); 143 | t.push_back(new TSPTimeLocaltimeResponse( 144 | DEFAULT_RESPONSE_PRIORITY, 145 | {regex("^.*?localtime=1$"), "GET", "HTTP/1.1"})); 146 | } 147 | -------------------------------------------------------------------------------- /TimeServerPlus/src/TimeServerPlus.cpp: -------------------------------------------------------------------------------- 1 | #include "TimeServerPlus.h" 2 | 3 | int main(int argc, char const *argv[]) { 4 | if (argc != 2) { 5 | cout << "Usage: " << argv[0] << " " << endl; 6 | exit(-1); 7 | } 8 | if (TSPUtilFile::exist(argv[1]) == -1) { 9 | TSPLogger::instance()->error("config file not exist [%s]", strerror(errno)); 10 | exit(-1); 11 | } 12 | if (TSPConfig::instance()->parse(argv[1]) == -1) { 13 | TSPLogger::instance()->error("config file parse error [%s]", 14 | strerror(errno)); 15 | exit(-1); 16 | } 17 | 18 | if (TSPConfig::instance()->exist("DAEMON", "1") == 1) { 19 | if (daemon(1, 0) < 0) { 20 | std::cerr << "DAEMON ERROR" << '\n'; 21 | } 22 | } 23 | 24 | // signal(SIGINT, SIG_IGN); 25 | // signal(SIGHUP, SIG_IGN); 26 | // signal(SIGQUIT, SIG_IGN); 27 | // signal(SIGPIPE, SIG_IGN); 28 | // signal(SIGTTOU, SIG_IGN); 29 | // signal(SIGTTIN, SIG_IGN); 30 | 31 | string port; 32 | if (TSPConfig::instance()->get("PORT", port) == -1 || port == "") 33 | port = "8600"; 34 | cout << "TSP Running .. port :" << port << endl; 35 | 36 | int server_socket_fd = tsp_server_init(stoi(port)); 37 | tsp_server_event_circles(server_socket_fd); 38 | return 0; 39 | } 40 | 41 | int tsp_server_init(int port) { 42 | int server_socket_fd = tsp_socket(AF_INET, SOCK_STREAM, 0); 43 | tsp_socket_nonblocking(server_socket_fd); 44 | tsp_socket_reuseaddr(server_socket_fd); 45 | 46 | struct sockaddr_in server_addr; 47 | bzero(&server_addr, sizeof(server_addr)); 48 | server_addr.sin_family = AF_INET; 49 | server_addr.sin_port = htons(port); 50 | server_addr.sin_addr.s_addr = htonl(INADDR_ANY); 51 | 52 | tsp_socket_bind(server_socket_fd, (struct sockaddr *)&server_addr, 53 | sizeof(server_addr)); 54 | tsp_socket_listen(server_socket_fd, MAX_BACKLOG); 55 | 56 | return server_socket_fd; 57 | } 58 | 59 | void tsp_server_event_circles(int server_fd) { 60 | int epollfd = tsp_epoll_create(MAX_EVENT_SIZE); 61 | 62 | struct epoll_event e; 63 | e.events = EPOLLIN; 64 | e.data.fd = server_fd; 65 | 66 | tsp_epoll_ctl(epollfd, EPOLL_CTL_ADD, server_fd, &e); 67 | 68 | pthread_attr_t pthread_attr_detach; 69 | pthread_attr_init(&pthread_attr_detach); 70 | pthread_attr_setdetachstate(&pthread_attr_detach, PTHREAD_CREATE_DETACHED); 71 | 72 | struct epoll_event ev[MAX_EVENT_SIZE]; 73 | int client_socket_fd; 74 | 75 | while (true) { 76 | 77 | int num = tsp_epoll_wait(epollfd, ev, MAX_EVENT_SIZE, -1); 78 | 79 | if (num == -1 && errno == EINTR) 80 | continue; 81 | 82 | struct sockaddr_in client_addr; 83 | socklen_t addrlen; 84 | 85 | for (int i = 0; i != num; i++) { 86 | if (ev[i].data.fd == server_fd) { 87 | client_socket_fd = tsp_socket_accept( 88 | server_fd, (struct sockaddr *)&client_addr, &addrlen); 89 | tsp_socket_nonblocking(client_socket_fd); 90 | e.events = EPOLLIN | EPOLLET; 91 | e.data.fd = client_socket_fd; 92 | tsp_epoll_ctl(epollfd, EPOLL_CTL_ADD, client_socket_fd, &e); 93 | 94 | } else { 95 | e.data.fd = ev[i].data.fd; 96 | tsp_epoll_ctl(epollfd, EPOLL_CTL_DEL, ev[i].data.fd, &e); 97 | 98 | if (TSPConfig::instance()->exist("IPRECORD", "1") == 1) { 99 | struct sockaddr_in in_addr; 100 | socklen_t len = sizeof(in_addr); 101 | bzero(&in_addr, len); 102 | if (getpeername(ev[i].data.fd, (sockaddr *)&in_addr, &len) != -1) { 103 | TSPLogger::instance()->info("visitor's IP is %s [IPRECORD]", 104 | inet_ntoa(in_addr.sin_addr)); 105 | } 106 | } 107 | 108 | pthread_t tid; 109 | pthread_create(&tid, &pthread_attr_detach, &tsp_server_thread_function, 110 | (void *)(intptr_t)ev[i].data.fd); 111 | } 112 | } 113 | } 114 | 115 | pthread_attr_destroy(&pthread_attr_detach); 116 | close(server_fd); 117 | } 118 | 119 | void *tsp_server_thread_function(void *param) { 120 | tsp_server_thread_num_add(); 121 | pthread_t thread_id = pthread_self(); 122 | cout << "Thread " << (unsigned int)thread_id << " Running..." << endl; 123 | 124 | int client_socket_fd = (intptr_t)param; 125 | 126 | struct epoll_event e, ev[2]; 127 | e.events = EPOLLIN | EPOLLET; 128 | e.data.fd = client_socket_fd; 129 | 130 | int thread_epollfd = tsp_epoll_create(2); 131 | tsp_epoll_ctl(thread_epollfd, EPOLL_CTL_ADD, client_socket_fd, &e); 132 | 133 | tsp_socket_nodelay(client_socket_fd); 134 | tsp_socket_set_timeout(client_socket_fd, 60, 0); 135 | 136 | char *buff = (char *)TSPUtilMemory::basic_malloc(BUFF_SIZE); 137 | bzero(buff, BUFF_SIZE); 138 | 139 | TSPRequest req(client_socket_fd); 140 | 141 | BEGIN: 142 | int32_t nread = 0, n = 0; 143 | int nfds = 0; 144 | 145 | for (;;) { 146 | n = read(client_socket_fd, buff + nread, BUFF_SIZE - 1); 147 | if (n > 0) 148 | nread += n; 149 | else if (n == 0) 150 | break; 151 | else if (n == -1 && errno == EINTR) 152 | continue; 153 | else if (n == -1 && errno == EAGAIN) 154 | break; 155 | else if (n == -1 && errno == EWOULDBLOCK) { 156 | TSPLogger::instance()->error( 157 | "thread function error : read socket timeout [%s]", strerror(errno)); 158 | goto OUT; 159 | } else { 160 | TSPLogger::instance()->error( 161 | "thread function error : read other error [%s]", strerror(errno)); 162 | break; 163 | } 164 | } 165 | 166 | if (nread != 0) { 167 | string raw_request(buff, buff + nread); 168 | 169 | if (req.parse_from_string(raw_request) == -1) { 170 | TSPLogger::instance()->error( 171 | "thread function error : request parse fail [%s]", strerror(errno)); 172 | tsp_response_bad_request(client_socket_fd); 173 | tsp_response_headers_end(client_socket_fd); 174 | goto BEGIN; 175 | } else { 176 | tsp_request_handle(req); 177 | } 178 | 179 | nfds = tsp_epoll_wait(thread_epollfd, ev, 2, 1000); 180 | if (0 == nfds) // timeout 181 | goto OUT; 182 | for (int i = 0; i < nfds; i++) { 183 | if (ev[i].data.fd == client_socket_fd) 184 | goto BEGIN; 185 | else 186 | goto OUT; 187 | } 188 | } 189 | 190 | OUT: 191 | close(thread_epollfd); 192 | TSPUtilMemory::basic_free(buff); 193 | tsp_server_thread_num_del(); 194 | printf("Thread %u exit\n", (unsigned int)thread_id); 195 | } 196 | 197 | int tsp_server_thread_num_add() { 198 | pthread_mutex_lock(&tsp_server_thread_num_mutex); 199 | tsp_server_thread_num++; 200 | pthread_mutex_unlock(&tsp_server_thread_num_mutex); 201 | return 0; 202 | } 203 | int tsp_server_thread_num_del() { 204 | int res = 0; 205 | pthread_mutex_lock(&tsp_server_thread_num_mutex); 206 | if (tsp_server_thread_num < 0) 207 | res = -1; 208 | else 209 | tsp_server_thread_num--; 210 | pthread_mutex_unlock(&tsp_server_thread_num_mutex); 211 | return res; 212 | } 213 | int32_t tsp_server_thread_num_get() { 214 | int32_t res; 215 | pthread_mutex_lock(&tsp_server_thread_num_mutex); 216 | res = tsp_server_thread_num; 217 | pthread_mutex_unlock(&tsp_server_thread_num_mutex); 218 | return res; 219 | } 220 | --------------------------------------------------------------------------------