├── half_sync_half_reactor ├── .root ├── logging │ ├── date.o │ ├── logging.o │ ├── logstream.o │ ├── timestamp.o │ ├── timezone.o │ ├── logging_unittest.o │ ├── logging_unittest.out │ ├── logging_unittest.cpp │ ├── Makefile │ ├── timezone.h │ ├── timestamp.cpp │ ├── current_thread.h │ ├── date.h │ ├── date.cpp │ ├── timestamp.h │ ├── logging.h │ ├── logstream.cpp │ ├── logstream.h │ ├── logging.cpp │ └── timezone.cpp ├── database │ ├── database_service.out │ ├── Makefile │ └── database_service.cpp ├── commont │ ├── stringutils_test.cpp │ ├── sigslot.cc │ ├── stringutils.h │ ├── constructormagic.h │ ├── commont.h │ └── sigslot.h ├── event.h ├── Makefile ├── json │ ├── settings.h │ └── json.h ├── event.cpp ├── thread │ ├── criticalsection.h │ ├── criticalsection.cpp │ └── thread_pool.h ├── ipaddress.h ├── socketaddress.h ├── userfactory.h ├── http_conn.h ├── web_server.cpp ├── socketaddress.cpp ├── ipaddress.cpp └── http_conn.cpp ├── screenshoot └── WechatIMG4863.jpeg ├── .gitignore └── README.md /half_sync_half_reactor/.root: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /screenshoot/WechatIMG4863.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Abson/HTTPServer/HEAD/screenshoot/WechatIMG4863.jpeg -------------------------------------------------------------------------------- /half_sync_half_reactor/logging/date.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Abson/HTTPServer/HEAD/half_sync_half_reactor/logging/date.o -------------------------------------------------------------------------------- /half_sync_half_reactor/logging/logging.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Abson/HTTPServer/HEAD/half_sync_half_reactor/logging/logging.o -------------------------------------------------------------------------------- /half_sync_half_reactor/logging/logstream.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Abson/HTTPServer/HEAD/half_sync_half_reactor/logging/logstream.o -------------------------------------------------------------------------------- /half_sync_half_reactor/logging/timestamp.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Abson/HTTPServer/HEAD/half_sync_half_reactor/logging/timestamp.o -------------------------------------------------------------------------------- /half_sync_half_reactor/logging/timezone.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Abson/HTTPServer/HEAD/half_sync_half_reactor/logging/timezone.o -------------------------------------------------------------------------------- /half_sync_half_reactor/logging/logging_unittest.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Abson/HTTPServer/HEAD/half_sync_half_reactor/logging/logging_unittest.o -------------------------------------------------------------------------------- /half_sync_half_reactor/database/database_service.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Abson/HTTPServer/HEAD/half_sync_half_reactor/database/database_service.out -------------------------------------------------------------------------------- /half_sync_half_reactor/logging/logging_unittest.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Abson/HTTPServer/HEAD/half_sync_half_reactor/logging/logging_unittest.out -------------------------------------------------------------------------------- /half_sync_half_reactor/database/Makefile: -------------------------------------------------------------------------------- 1 | database: database_service.cpp 2 | clang++ -g -std=c++11 `mysql_config --cflags --libs` database_service.cpp -o database_service.out 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | half_sync_half_reactor/logging/logging.o 3 | half_sync_half_reactor/logging/logging_unittest.o 4 | half_sync_half_reactor/logging/logging_unittest.out 5 | half_sync_half_reactor/logging/timezone.o 6 | half_sync_half_reactor/logging/logging.o 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### HTTPServer 2 | 利用 C++ 编写的 HTTP 服务器,使用线程池 + Reactor 模式 3 | 4 | ### 运行前更改 5 | 需要到 http_conn.cpp 第 6 行,更改 doc_root 为自己服务器的文件路径,默认为 /home/parallels/Desktop 6 | 7 | ### 如何运行? 8 | $:cd half_sync_half_reactor 9 | 10 | $:make 11 | 12 | $:./webserver.out x.x.x.x:x (自己的ip地址和端口号) 13 | 14 | ### 运行结果 15 | ![](https://github.com/Abson/HTTPServer/blob/master/screenshoot/WechatIMG4863.jpeg) 16 | 17 | ### Feature 18 | 目前还写的比较low... 19 | 20 | 1、目前 accept、Read、Write 方法都在主线程中通过 IO multiplexing 进行,后期应该改进为放在线程池中进行,避免阻塞主线程,加强主线程处理连接时的实时性 21 | 22 | 2、添加 MySql 数据库的时候,加上一些个人信息接口之类 23 | -------------------------------------------------------------------------------- /half_sync_half_reactor/commont/stringutils_test.cpp: -------------------------------------------------------------------------------- 1 | #include "stringutils.h" 2 | #include 3 | 4 | const char* ok_string = "OK"; 5 | 6 | char write_buf[1024]; 7 | 8 | template 9 | bool AddResponse(const CTYPE* format, ...) { 10 | va_list args; 11 | va_start(args, format); 12 | size_t len = vsprintfn(write_buf, sizeof(write_buf), format, args); 13 | va_end(args); 14 | return true; 15 | } 16 | 17 | int main(int argc, const char* argv[]) 18 | { 19 | AddResponse("HTTP/1.1 %s %d %s \r\r", "fuck", 200, ok_string); 20 | std::cout << write_buf << std::endl; 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /half_sync_half_reactor/event.h: -------------------------------------------------------------------------------- 1 | #ifndef BASE_EVENT_H 2 | #define BASE_EVENT_H 3 | 4 | #include "commont/constructormagic.h" 5 | #include 6 | 7 | class Event { 8 | public: 9 | static const int kForever = -1; 10 | 11 | Event(bool manual_reset, bool initially_signaled); 12 | ~Event(); 13 | 14 | void Set(); 15 | void Reset(); 16 | 17 | bool Wait(int milliseconds); 18 | 19 | private: 20 | pthread_mutex_t event_mutex_; 21 | pthread_cond_t event_cond_; 22 | 23 | /*用户是否需要自行调用 Reset 方法 event_status_*/ 24 | const bool is_manual_reset_; 25 | 26 | bool event_status_; 27 | 28 | BASE_DISALLOW_COPY_AND_ASSIGN(Event); 29 | }; 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /half_sync_half_reactor/commont/sigslot.cc: -------------------------------------------------------------------------------- 1 | // sigslot.h: Signal/Slot classes 2 | // 3 | // Written by Sarah Thompson (sarah@telergy.com) 2002. 4 | // 5 | // License: Public domain. You are free to use this code however you like, with 6 | // the proviso that the author takes on no responsibility or liability for any 7 | // use. 8 | 9 | #include "rtc_base/sigslot.h" 10 | 11 | namespace sigslot { 12 | 13 | #ifdef _SIGSLOT_HAS_POSIX_THREADS 14 | 15 | pthread_mutex_t* multi_threaded_global::get_mutex() { 16 | static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER; 17 | return &g_mutex; 18 | } 19 | 20 | #endif // _SIGSLOT_HAS_POSIX_THREADS 21 | 22 | } // namespace sigslot 23 | -------------------------------------------------------------------------------- /half_sync_half_reactor/logging/logging_unittest.cpp: -------------------------------------------------------------------------------- 1 | #include "logging.h" 2 | #include "timezone.h" 3 | 4 | #include 5 | #include 6 | 7 | void* logInThread(void* arg) 8 | { 9 | LOG_INFO << "logInThread"; 10 | return nullptr; 11 | } 12 | 13 | int main(int argc, const char* argv[]) 14 | { 15 | getpid(); 16 | 17 | pthread_t thread; 18 | pthread_create(&thread, nullptr, logInThread, nullptr); 19 | pthread_join(thread, nullptr); 20 | 21 | sleep(1); 22 | base::TimeZone beijing(8*3600, "CST"); 23 | base::Logger::setTimezone(beijing); 24 | LOG_TRACE << "trace CST"; 25 | LOG_DEBUG << "debug CST"; 26 | LOG_INFO << "Hello CST"; 27 | LOG_WARN << "World CST"; 28 | LOG_ERROR << "Error CST"; 29 | 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /half_sync_half_reactor/logging/Makefile: -------------------------------------------------------------------------------- 1 | run: logging_unittest.o date.o logging.o logstream.o timestamp.o timezone.o 2 | clang++ -std=c++11 -pthread -g logging_unittest.o date.o logging.o logstream.o timestamp.o timezone.o -o logging_unittest.out 3 | 4 | logging_unittest.o : logging_unittest.cpp 5 | clang++ -std=c++11 -g -c logging_unittest.cpp 6 | 7 | date.o : date.cpp 8 | clang++ -std=c++11 -g -c date.cpp 9 | 10 | logging.o : logging.cpp 11 | clang++ -std=c++11 -g -c logging.cpp 12 | 13 | logstream.o : logstream.cpp 14 | clang++ -std=c++11 -g -c logstream.cpp 15 | 16 | timestamp.o : timestamp.cpp 17 | clang++ -std=c++11 -g -c timestamp.cpp 18 | 19 | timezone.o : timezone.cpp 20 | clang++ -std=c++11 -g -c timezone.cpp 21 | 22 | clean: 23 | rm *.o 24 | rm *out 25 | -------------------------------------------------------------------------------- /half_sync_half_reactor/Makefile: -------------------------------------------------------------------------------- 1 | run: web_server.o criticalsection.o event.o http_conn.o ipaddress.o socketaddress.o 2 | clang++ -std=c++11 -pthread -g criticalsection.o event.o http_conn.o ipaddress.o socketaddress.o web_server.o -o web_server.out 3 | 4 | web_server.o: web_server.cpp 5 | clang++ -std=c++11 -g -c web_server.cpp 6 | 7 | criticalsection.o: criticalsection.cpp 8 | clang++ -std=c++11 -g -c criticalsection.cpp 9 | 10 | event.o: event.cpp 11 | clang++ -std=c++11 -g -c event.cpp 12 | 13 | http_conn.o: http_conn.cpp 14 | clang++ -std=c++11 -g -c http_conn.cpp 15 | 16 | ipaddress.o: ipaddress.cpp 17 | clang++ -std=c++11 -g -c ipaddress.cpp 18 | 19 | socketaddress.o: socketaddress.cpp 20 | clang++ -std=c++11 -g -c socketaddress.cpp 21 | 22 | clean: 23 | rm *.o 24 | rm *out 25 | -------------------------------------------------------------------------------- /half_sync_half_reactor/json/settings.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // settings for crow 3 | // TODO - replace with runtime config. libucl? 4 | 5 | /* #ifdef - enables debug mode */ 6 | //#define CROW_ENABLE_DEBUG 7 | 8 | /* #ifdef - enables logging */ 9 | #define CROW_ENABLE_LOGGING 10 | 11 | /* #ifdef - enables ssl */ 12 | //#define CROW_ENABLE_SSL 13 | 14 | /* #define - specifies log level */ 15 | /* 16 | Debug = 0 17 | Info = 1 18 | Warning = 2 19 | Error = 3 20 | Critical = 4 21 | 22 | default to INFO 23 | */ 24 | #ifndef CROW_LOG_LEVEL 25 | #define CROW_LOG_LEVEL 1 26 | #endif 27 | 28 | 29 | // compiler flags 30 | #if __cplusplus >= 201402L 31 | #define CROW_CAN_USE_CPP14 32 | #endif 33 | 34 | #if defined(_MSC_VER) 35 | #if _MSC_VER < 1900 36 | #define CROW_MSVC_WORKAROUND 37 | #define constexpr const 38 | #define noexcept throw() 39 | #endif 40 | #endif 41 | -------------------------------------------------------------------------------- /half_sync_half_reactor/commont/stringutils.h: -------------------------------------------------------------------------------- 1 | #ifndef BASE_STRINGUTILS_H 2 | #define BASE_STRINGUTILS_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | template 9 | size_t vsprintfn(CTYPE* buffer, size_t buflen, const CTYPE* format, va_list args) { 10 | int len = vsnprintf(buffer, buflen, format, args); 11 | if (len < 0 || static_cast(len) >= buflen) { 12 | len = static_cast(buflen - 1); 13 | buffer[len] = 0; 14 | } 15 | return len; 16 | } 17 | 18 | template 19 | size_t sprintfn(CTYPE* buffer, size_t buflen, const CTYPE* format, ...); 20 | template 21 | size_t sprintfn(CTYPE* buffer, size_t buflen, const CTYPE* format, ...) { 22 | va_list args; 23 | va_start(args, format); 24 | size_t len = vsprintfn(buffer, buflen, format, args); 25 | va_end(args); 26 | return len; 27 | } 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /half_sync_half_reactor/logging/timezone.h: -------------------------------------------------------------------------------- 1 | #ifndef BASE_TIMEZONE_H 2 | #define BASE_TIMEZONE_H 3 | 4 | #include 5 | 6 | namespace base 7 | { 8 | 9 | class TimeZone 10 | { 11 | public: 12 | explicit TimeZone(const char* zonefile); 13 | TimeZone(int eastOfUtc, const char* tzname); 14 | TimeZone() {}; 15 | 16 | bool valid() const 17 | { 18 | return static_cast(data_); 19 | } 20 | 21 | struct tm toLocalTime(time_t secondsSinceEpoch) const; 22 | time_t fromLocalTime(const struct tm&) const; 23 | 24 | /* gmtime(3) */ 25 | static struct tm toUtcTime(time_t secondsSinceEpoch, bool yday = false); 26 | /* timegm(3) */ 27 | static time_t fromUtcTime(const struct tm&); 28 | static time_t fromUtcTime(int year, int month, int day, 29 | int hour, int minute, int seconds); 30 | 31 | struct Data; 32 | 33 | private: 34 | std::shared_ptr data_; 35 | }; 36 | 37 | } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /half_sync_half_reactor/commont/constructormagic.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2004 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #ifndef BASE_CONSTRUCTORMAGIC_H_ 12 | #define BASE_CONSTRUCTORMAGIC_H_ 13 | 14 | // Put this in the declarations for a class to be unassignable. 15 | #define BASE_DISALLOW_ASSIGN(TypeName) \ 16 | void operator=(const TypeName&) = delete 17 | 18 | // A macro to disallow the copy constructor and operator= functions. This should 19 | // be used in the declarations for a class. 20 | #define BASE_DISALLOW_COPY_AND_ASSIGN(TypeName) \ 21 | TypeName(const TypeName&) = delete; \ 22 | BASE_DISALLOW_ASSIGN(TypeName) 23 | 24 | // A macro to disallow all the implicit constructors, namely the default 25 | // constructor, copy constructor and operator= functions. 26 | // 27 | // This should be used in the declarations for a class that wants to prevent 28 | // anyone from instantiating it. This is especially useful for classes 29 | // containing only static methods. 30 | #define BASE_DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ 31 | TypeName() = delete; \ 32 | BASE_DISALLOW_COPY_AND_ASSIGN(TypeName) 33 | 34 | #endif // RTC_BASE_CONSTRUCTORMAGIC_H_ 35 | -------------------------------------------------------------------------------- /half_sync_half_reactor/logging/timestamp.cpp: -------------------------------------------------------------------------------- 1 | #include "timestamp.h" 2 | #include "../commont/stringutils.h" 3 | 4 | #include 5 | 6 | #include 7 | 8 | using namespace base; 9 | 10 | std::string Timestamp::toString() const 11 | { 12 | char buf[32] = {0}; 13 | int64_t seconds = microSecondsSinceEpoch_ / kMicroSecondsPerSecond; 14 | int64_t microseconds = microSecondsSinceEpoch_ % kMicroSecondsPerSecond; 15 | snprintf(buf, sizeof(buf)-1, "%" PRId64 ".%06" PRId64 "", seconds, microseconds); 16 | return buf; 17 | } 18 | 19 | std::string Timestamp::toFormattedString(bool showMicroseconds) const 20 | { 21 | char buf[64] = {0}; 22 | time_t seconds = static_cast(microSecondsSinceEpoch_ / kMicroSecondsPerSecond); 23 | struct tm tm_time; 24 | gmtime_r(&seconds, &tm_time); 25 | if (showMicroseconds) 26 | { 27 | int microseconds = static_cast(microSecondsSinceEpoch_ / kMicroSecondsPerSecond); 28 | sprintfn(buf, sizeof(buf), "%4d%02d%02d %02d:%02d:%02d.%06d", 29 | tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday, 30 | tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec, microseconds); 31 | } 32 | else 33 | { 34 | sprintfn(buf, sizeof(buf), "%4d%02d%02d %02d:%02d:%02d", 35 | tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday, 36 | tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec); 37 | } 38 | return buf; 39 | } 40 | 41 | Timestamp Timestamp::now() 42 | { 43 | struct timeval tv; 44 | gettimeofday(&tv, nullptr); 45 | int64_t seconds = tv.tv_sec; 46 | return Timestamp(seconds * kMicroSecondsPerSecond + tv.tv_usec); 47 | } 48 | -------------------------------------------------------------------------------- /half_sync_half_reactor/logging/current_thread.h: -------------------------------------------------------------------------------- 1 | #ifndef BASE_CURRENTTHREAD_H 2 | #define BASE_CURRENTTHREAD_H 3 | 4 | #include "timestamp.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace base 12 | { 13 | pid_t gettid() 14 | { 15 | return static_cast(::syscall(SYS_gettid)); 16 | } 17 | 18 | namespace CurrentThread 19 | { 20 | 21 | __thread int t_cachedTid = 0; 22 | __thread char t_tidString[32]; 23 | __thread int t_tidStringLength = 6; 24 | __thread const char* t_threadName = "unknown"; 25 | 26 | void cacheTid() 27 | { 28 | if (t_cachedTid == 0) 29 | { 30 | t_cachedTid = gettid(); 31 | t_tidStringLength = snprintf(t_tidString, sizeof(t_tidString), "%5d ", t_cachedTid); 32 | } 33 | } 34 | 35 | inline int tid() 36 | { 37 | if (__builtin_expect(t_cachedTid == 0, 0)) 38 | { 39 | cacheTid(); 40 | } 41 | return t_cachedTid; 42 | } 43 | 44 | inline const char* tidString() 45 | { 46 | return t_tidString; 47 | } 48 | 49 | inline int tidStringLength() 50 | { 51 | return t_tidStringLength; 52 | } 53 | 54 | inline const char* name() 55 | { 56 | return t_threadName; 57 | } 58 | 59 | bool isMainThread() 60 | { 61 | return tid() == ::getpid(); 62 | } 63 | 64 | void sleepUsec(int64_t usec) 65 | { 66 | struct timespec ts = {0, 0}; 67 | ts.tv_sec = static_cast(usec / Timestamp::kMicroSecondsPerSecond); 68 | ts.tv_nsec = static_cast(usec % Timestamp::kMicroSecondsPerSecond * 1000); 69 | ::nanosleep(&ts, nullptr); 70 | } 71 | } 72 | } 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /half_sync_half_reactor/logging/date.h: -------------------------------------------------------------------------------- 1 | #ifndef BASE_DATE_H 2 | #define BASE_DATE_H 3 | 4 | #include "../commont/constructormagic.h" 5 | 6 | #include 7 | 8 | namespace base 9 | { 10 | 11 | class Date 12 | { 13 | public: 14 | 15 | struct YearMonthDay 16 | { 17 | int year; 18 | int month; 19 | int day; 20 | }; 21 | 22 | static const int kDaysPerWeek = 7; 23 | static const int kJulianDayOf1970_01_01; 24 | 25 | Date() 26 | : julianDayNumber_(0) 27 | {} 28 | 29 | Date(int year, int month, int day); 30 | 31 | explicit Date(int julianDayNum) 32 | : julianDayNumber_(julianDayNum) 33 | {} 34 | 35 | explicit Date(const struct tm&); 36 | 37 | void swap(Date& that) 38 | { 39 | std::swap(julianDayNumber_, that.julianDayNumber_); 40 | } 41 | 42 | bool Valid() const { return julianDayNumber_ > 0; } 43 | 44 | std::string toIsoString() const; 45 | 46 | struct YearMonthDay yearMonthDay() const; 47 | 48 | int year() const 49 | { 50 | return yearMonthDay().year; 51 | } 52 | 53 | int month() const 54 | { 55 | return yearMonthDay().month; 56 | } 57 | 58 | int day() const 59 | { 60 | return yearMonthDay().day; 61 | } 62 | 63 | int weekDay() const 64 | { 65 | return (julianDayNumber_ + 1) % kDaysPerWeek; 66 | } 67 | 68 | int julianDayNumber() const { return julianDayNumber_; } 69 | 70 | private: 71 | int julianDayNumber_; 72 | 73 | BASE_DISALLOW_COPY_AND_ASSIGN(Date); 74 | }; 75 | 76 | inline bool operator<(Date x, Date y) 77 | { 78 | return x.julianDayNumber() < y.julianDayNumber(); 79 | } 80 | 81 | inline bool operator==(Date x, Date y) 82 | { 83 | return x.julianDayNumber() == y.julianDayNumber(); 84 | } 85 | 86 | } 87 | 88 | #endif 89 | -------------------------------------------------------------------------------- /half_sync_half_reactor/logging/date.cpp: -------------------------------------------------------------------------------- 1 | #include "date.h" 2 | 3 | namespace base 4 | { 5 | namespace detail 6 | { 7 | 8 | char require_32_bit_integer_at_least[sizeof(int) >= sizeof(int32_t) ? 1 : -1]; 9 | 10 | /* 公历转变为儒略日时间 */ 11 | int getJulianDayNumber(int year, int month, int day) 12 | { 13 | static_cast(require_32_bit_integer_at_least); 14 | int a = (14 - month) / 12; 15 | int y = year + 4800 - a; 16 | int m = month + 12 * a - 3; 17 | return day + (153*m + 2) / 5 + y*365 + y/4 - y/100 + y/400 - 32045; 18 | } 19 | 20 | /* 儒略日时间转变为公历时间 */ 21 | struct Date::YearMonthDay getYearMonthDay(int julianDayNumber) 22 | { 23 | int a = julianDayNumber + 32044; 24 | int b = (4 * a + 3) / 146097; 25 | int c = a - ((b * 146097) / 4); 26 | int d = (4 * c + 3) / 1461; 27 | int e = c - ((1461 * d) / 4); 28 | int m = (5 * e + 2) / 153; 29 | Date::YearMonthDay ymd; 30 | ymd.day = e - ((153 * m + 2) / 5) + 1; 31 | ymd.month = m + 3 - 12 * (m / 10); 32 | ymd.year = b * 100 + d - 4800 + (m / 10); 33 | return ymd; 34 | } 35 | } 36 | 37 | const int Date::kJulianDayOf1970_01_01 = detail::getJulianDayNumber(1970, 1, 1); 38 | } 39 | 40 | using namespace base; 41 | using namespace base::detail; 42 | 43 | Date::Date(int y, int m, int d) 44 | : julianDayNumber_(getJulianDayNumber(y, m, d)) 45 | {} 46 | 47 | Date::Date(const struct tm& t) 48 | : julianDayNumber_(getJulianDayNumber( 49 | t.tm_year + 1900, 50 | t.tm_mon + 1, 51 | t.tm_mday)) 52 | {} 53 | 54 | std::string Date::toIsoString() const 55 | { 56 | char buf[32]; 57 | YearMonthDay ymd(yearMonthDay()); 58 | snprintf(buf, sizeof(buf), "%4d-%02d-%02d", ymd.year, ymd.month, ymd.day); 59 | return buf; 60 | } 61 | 62 | Date::YearMonthDay Date::yearMonthDay() const 63 | { 64 | return getYearMonthDay(julianDayNumber_); 65 | } 66 | -------------------------------------------------------------------------------- /half_sync_half_reactor/event.cpp: -------------------------------------------------------------------------------- 1 | #include "event.h" 2 | #include 3 | #include 4 | 5 | Event::Event(bool manual_reset, bool initially_signaled) : 6 | is_manual_reset_(manual_reset), 7 | event_status_(initially_signaled) { 8 | 9 | assert(pthread_mutex_init(&event_mutex_, nullptr) == 0); 10 | assert(pthread_cond_init(&event_cond_, nullptr) == 0); 11 | } 12 | 13 | Event::~Event() { 14 | pthread_mutex_destroy(&event_mutex_); 15 | pthread_cond_destroy(&event_cond_); 16 | } 17 | 18 | void Event::Set() { 19 | pthread_mutex_lock(&event_mutex_); 20 | event_status_ = true; 21 | pthread_cond_broadcast(&event_cond_); 22 | pthread_mutex_unlock(&event_mutex_); 23 | } 24 | 25 | void Event::Reset() { 26 | pthread_mutex_lock(&event_mutex_); 27 | event_status_ = false; 28 | pthread_mutex_unlock(&event_mutex_); 29 | } 30 | 31 | bool Event::Wait(int milliseconds) { 32 | int error = 0; 33 | 34 | struct timespec ts; 35 | 36 | if (milliseconds != kForever) { 37 | struct timeval tv; 38 | gettimeofday(&tv, nullptr); 39 | 40 | ts.tv_sec = tv.tv_sec + (milliseconds / 1000); 41 | ts.tv_nsec = tv.tv_usec + (milliseconds % 1000); 42 | 43 | // Handl overflow 44 | if (ts.tv_nsec >= 1000000000) { 45 | ts.tv_sec++; 46 | ts.tv_nsec -= 1000000000; 47 | } 48 | } 49 | 50 | pthread_mutex_lock(&event_mutex_); 51 | if (milliseconds != kForever) { 52 | while(!event_status_ && error == 0) { 53 | error = pthread_cond_timedwait(&event_cond_, &event_mutex_, &ts); 54 | } 55 | } 56 | else { 57 | while(!event_status_ && error == 0) { 58 | error = pthread_cond_wait(&event_cond_, &event_mutex_); 59 | } 60 | } 61 | 62 | if (error == 0 && is_manual_reset_) { 63 | event_status_ = false; 64 | } 65 | 66 | pthread_mutex_unlock(&event_mutex_); 67 | 68 | return (error == 0); 69 | } 70 | -------------------------------------------------------------------------------- /half_sync_half_reactor/commont/commont.h: -------------------------------------------------------------------------------- 1 | #ifndef COMMONT_H 2 | #define COMMONT_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace base { 15 | 16 | static int SetNoBlocking(int fd) { 17 | int old_option = fcntl(fd, F_GETFL); 18 | int new_option = old_option | O_NONBLOCK; 19 | fcntl(fd, F_SETFL, new_option); 20 | return old_option; 21 | } 22 | 23 | static void AddFd(int epoll_fd, int fd, int one_shot = 0) { 24 | epoll_event event; 25 | event.data.fd = fd; 26 | event.events = EPOLLIN | EPOLLET | EPOLLHUP; 27 | if (one_shot) { 28 | event.events |= EPOLLONESHOT; 29 | } 30 | epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &event); 31 | SetNoBlocking(fd); 32 | } 33 | 34 | static void RemoveFd(int epoll_fd, int fd) { 35 | epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, 0); 36 | close(fd); 37 | std::cout << "remove sockf_fd: " << fd << std::endl; 38 | } 39 | 40 | static void AddSig(int sig, void(handler)(int), bool restart = true) { 41 | struct ::sigaction sa; 42 | memset(&sa, '\0', sizeof(sa)); 43 | sa.sa_handler = handler; 44 | if ( restart ) { 45 | sa.sa_flags |= SA_RESTART; 46 | } 47 | sigfillset(&sa.sa_mask); 48 | assert(::sigaction(sig, &sa, nullptr) != -1); 49 | } 50 | 51 | static void ModifyFd(int epoll_fd, int fd, int ev) { 52 | epoll_event event; 53 | event.data.fd = fd; 54 | event.events = ev | EPOLLET | EPOLLONESHOT | EPOLLRDHUP; 55 | epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &event); 56 | } 57 | 58 | static void ShowError(int connfd, const char* info) { 59 | printf("%s\n", info); 60 | send(connfd, info, strlen(info), 0); 61 | close(connfd); 62 | } 63 | } 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /half_sync_half_reactor/thread/criticalsection.h: -------------------------------------------------------------------------------- 1 | #ifndef CIRTICALSECTION_H 2 | #define CIRTICALSECTION_H 3 | 4 | #include 5 | 6 | #if defined (__clang__) && (!defined (SWIG)) 7 | #define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x)) 8 | #else 9 | #define THREAD_ANNOTATION_ATTRIBUTE__(x) 10 | #endif 11 | 12 | #define SCOPE_LOCKABLE THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable) 13 | 14 | #define EXCLUSIVE_LOCK_FUNCTION(...) \ 15 | THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__)) 16 | 17 | #define UNLOCK_FUNCTION(...) \ 18 | THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__)) 19 | 20 | #define EXCLUSIVE_TRYLOCK_FUNCTION(...) \ 21 | THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__)) 22 | 23 | class CriticalSection { 24 | public: 25 | CriticalSection(); 26 | ~CriticalSection(); 27 | 28 | void Enter() const EXCLUSIVE_LOCK_FUNCTION(); 29 | bool TryEnter() const EXCLUSIVE_TRYLOCK_FUNCTION(true); 30 | void Leave() const UNLOCK_FUNCTION(); 31 | private: 32 | bool CurrentThreadIsOwner() const; 33 | mutable pthread_mutex_t mutex_; 34 | mutable pthread_t thread_; 35 | mutable int recursion_count_; 36 | }; 37 | 38 | class SCOPE_LOCKABLE CritScope { 39 | public: 40 | explicit CritScope(const CriticalSection* cs) EXCLUSIVE_LOCK_FUNCTION(cs); 41 | ~CritScope() UNLOCK_FUNCTION(); 42 | 43 | private: 44 | const CriticalSection* const cs_; 45 | 46 | CritScope(const CritScope&) = delete; 47 | void operator=(const CritScope&) = delete; 48 | }; 49 | 50 | class TryCritScope { 51 | public: 52 | explicit TryCritScope(const CriticalSection* cs) EXCLUSIVE_LOCK_FUNCTION(cs); 53 | ~TryCritScope(); 54 | 55 | bool locked() const __attribute__((__warn_unused_result__)); 56 | 57 | private: 58 | const CriticalSection* const cs_; 59 | const bool locked_; 60 | mutable bool lock_was_called; 61 | 62 | TryCritScope(const CritScope&) = delete; 63 | void operator=(const TryCritScope&) = delete; 64 | }; 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /half_sync_half_reactor/ipaddress.h: -------------------------------------------------------------------------------- 1 | #ifndef BASE_IPADDRESS_H 2 | #define BASE_IPADDRESS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | class IPAddress { 11 | public: 12 | IPAddress() : family_(AF_UNSPEC) { 13 | memset(&u_, '\0', sizeof(u_)); 14 | } 15 | 16 | explicit IPAddress(const in_addr& ip4) : family_(AF_INET) { 17 | memset(&u_, '\0', sizeof(u_)); 18 | u_.ip4 = ip4; 19 | } 20 | 21 | explicit IPAddress(const in6_addr& ip6) : family_(AF_INET6) { 22 | memset(&u_, '\0', sizeof(u_)); 23 | u_.ip6 = ip6; 24 | } 25 | 26 | explicit IPAddress(uint32_t ip_in_host_byte_order) : family_(AF_INET) { 27 | memset(&u_, '\0', sizeof(u_)); 28 | u_.ip4.s_addr = htonl(ip_in_host_byte_order); 29 | } 30 | 31 | IPAddress(const IPAddress& other) : family_(other.family_) { 32 | memcpy(&u_, &other.u_, sizeof(u_)); 33 | } 34 | 35 | const IPAddress & operator=(const IPAddress& other) { 36 | family_ = other.family_; 37 | memcpy(&u_, &other.u_, sizeof(u_)); 38 | return *this; 39 | } 40 | 41 | int family() const { return family_; } 42 | 43 | in_addr ip4_address() const { return u_.ip4; } 44 | 45 | in6_addr ip6_address() const { return u_.ip6; } 46 | 47 | size_t Size() const; 48 | 49 | std::string ToString() const; 50 | 51 | std::string ToSensitiveString() const; 52 | 53 | bool IsNil() const; 54 | 55 | uint32_t v4AddressAsHostOrderInteger() const; 56 | 57 | bool operator==(const IPAddress& other) const; 58 | 59 | /*将一个ipv4地址转换成一个ipv6地址*/ 60 | IPAddress AsIPV6Address() const; 61 | 62 | virtual ~IPAddress() {} 63 | 64 | private: 65 | int family_; 66 | union { 67 | in_addr ip4; 68 | in6_addr ip6; 69 | } u_; 70 | }; 71 | 72 | bool IPFromString(const std::string& str, IPAddress* out); 73 | bool IPIsLoopback(const IPAddress& ip); 74 | bool IPIsAny(const IPAddress& ip); 75 | bool IPIsPrivateNetWork(const IPAddress& ip); 76 | bool IPIsUnspec(const IPAddress& ip); 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /half_sync_half_reactor/thread/criticalsection.cpp: -------------------------------------------------------------------------------- 1 | #include "criticalsection.h" 2 | #include 3 | 4 | CriticalSection::CriticalSection() { 5 | pthread_mutexattr_t attr; 6 | pthread_mutexattr_init(&attr); 7 | /*PTHREAD_MUTEX_RECURSIVE 如果一个线程对这种类型的互斥锁重复上锁,不会引起死锁。 8 | * 一个线程对这类互斥锁的多次重复上锁必须由这个线程来重复相同数量的解锁,这样才能解开这个互斥锁,别的线程才能得到这个互斥锁。 9 | *如果试图解锁一个由别的线程锁定的互斥锁将会返回一个错误代码。如果一个线程试图解锁已经被解锁的互斥锁也将会返回一个错误代码。 10 | **/ 11 | pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 12 | pthread_mutex_init(&mutex_, &attr); 13 | pthread_mutexattr_destroy(&attr); 14 | 15 | thread_ = 0; 16 | recursion_count_ = 0; 17 | } 18 | 19 | CriticalSection::~CriticalSection() { 20 | pthread_mutex_destroy(&mutex_); 21 | } 22 | 23 | bool CriticalSection::CurrentThreadIsOwner() const { 24 | return pthread_equal(thread_, pthread_self()); 25 | } 26 | 27 | void CriticalSection::Enter() const { 28 | pthread_mutex_lock(&mutex_); 29 | 30 | if (!recursion_count_) { 31 | assert(!thread_); 32 | thread_ = pthread_self(); 33 | } 34 | else { 35 | CurrentThreadIsOwner(); 36 | } 37 | ++recursion_count_; 38 | } 39 | 40 | bool CriticalSection::TryEnter() const { 41 | if ( pthread_mutex_trylock(&mutex_) != 0) { 42 | return false; 43 | } 44 | 45 | if (!recursion_count_) { 46 | assert(!thread_); 47 | thread_ = pthread_self(); 48 | } 49 | else { 50 | CurrentThreadIsOwner(); 51 | } 52 | ++recursion_count_; 53 | return true; 54 | } 55 | 56 | void CriticalSection::Leave() const { 57 | 58 | --recursion_count_; 59 | assert(recursion_count_ >= 0); 60 | if (!recursion_count_) 61 | thread_ = 0; 62 | 63 | pthread_mutex_unlock(&mutex_); 64 | } 65 | 66 | CritScope::CritScope(const CriticalSection* cs) : cs_(cs) { 67 | cs_->Enter(); 68 | } 69 | 70 | CritScope::~CritScope() { 71 | cs_->Leave(); 72 | } 73 | 74 | TryCritScope::TryCritScope(const CriticalSection* cs) : 75 | cs_(cs), 76 | locked_(cs_->TryEnter()) { 77 | lock_was_called = false; 78 | } 79 | 80 | bool TryCritScope::locked() const { 81 | lock_was_called = true; 82 | return locked_; 83 | } 84 | 85 | TryCritScope::~TryCritScope() { 86 | if (locked_) { 87 | cs_->Leave(); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /half_sync_half_reactor/socketaddress.h: -------------------------------------------------------------------------------- 1 | #ifndef BASE_SOCKETADDRESS_H 2 | #define BASE_SOCKETADDRESS_H 3 | 4 | #include "ipaddress.h" 5 | 6 | class SocketAddress { 7 | public: 8 | SocketAddress(); 9 | 10 | SocketAddress(const std::string& hostname, int port); 11 | 12 | SocketAddress(uint32_t ip_as_host_order_interger, int port); 13 | 14 | SocketAddress(const IPAddress& ip, int port); 15 | 16 | SocketAddress(const SocketAddress& addr); 17 | const SocketAddress & operator=(const SocketAddress& addr); 18 | 19 | void SetIP(const std::string& hostname); 20 | 21 | void SetIP(const IPAddress& ip); 22 | 23 | void SetIP(uint32_t ip_as_host_order_interger); 24 | 25 | void SetPort(int port); 26 | 27 | const std::string hostname() { return hostname_; } 28 | 29 | uint32_t ip() const; 30 | 31 | const IPAddress& ipaddr() const; 32 | 33 | int family() const { return ip_.family(); } 34 | 35 | uint16_t port() const { return port_; } 36 | 37 | /*Return the scope id associated with this address. Scope IDs are a 38 | *necessary addition to IPV6 link-local address. with different network 39 | *interface having different scope-ids for their link-local address. 40 | *IPv4 address do not have scope_ids and sockaddr_in structes do not have 41 | *a field for them.*/ 42 | int scope_id() const { return scope_id_; } 43 | void SetScopeID(int id) { scope_id_ = id; } 44 | 45 | void Clear(); 46 | 47 | bool IPIsLoopbackIP() const; 48 | 49 | bool IsPrivateIP() const; 50 | 51 | void ToSockAddr(sockaddr_in* saddr) const; 52 | 53 | bool FromSockAddr(const sockaddr_in& saddr); 54 | 55 | std::string HostAsURIString() const; 56 | 57 | std::string PortAsString() const; 58 | 59 | std::string ToString() const; 60 | 61 | friend std::ostream& operator<<(std::ostream& os, const SocketAddress& addr); 62 | 63 | bool EqualIPs(const SocketAddress& addr) const; 64 | 65 | bool EqualPorts(const SocketAddress& addr) const; 66 | 67 | bool operator==(const SocketAddress& addr) const; 68 | 69 | private: 70 | std::string hostname_; 71 | IPAddress ip_; 72 | uint16_t port_; 73 | int scope_id_; 74 | bool literal_; 75 | }; 76 | 77 | SocketAddress EmptySocketAddressWithFamily(int family); 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /half_sync_half_reactor/logging/timestamp.h: -------------------------------------------------------------------------------- 1 | #ifndef BASE_TIMESTAMP_H 2 | #define BASE_TIMESTAMP_H 3 | 4 | #include 5 | 6 | namespace base 7 | { 8 | 9 | class Timestamp 10 | { 11 | public: 12 | Timestamp() 13 | : microSecondsSinceEpoch_(0) 14 | { 15 | } 16 | 17 | explicit Timestamp(int64_t microSecondsSinceEpoch) 18 | : microSecondsSinceEpoch_(microSecondsSinceEpoch) 19 | { 20 | } 21 | 22 | void swap(Timestamp& that) 23 | { 24 | std::swap(microSecondsSinceEpoch_, that.microSecondsSinceEpoch_); 25 | } 26 | 27 | std::string toString() const; 28 | std::string toFormattedString(bool showMicroseconds = true) const; 29 | 30 | bool valid() const { return microSecondsSinceEpoch_ > 0; } 31 | 32 | int64_t microSecondsSinceEpoch() const { return microSecondsSinceEpoch_; } 33 | time_t secondsSinceEpoch() const 34 | { 35 | return static_cast(microSecondsSinceEpoch_ / kMicroSecondsPerSecond); 36 | } 37 | 38 | static Timestamp now(); 39 | static Timestamp Invalid() 40 | { 41 | return Timestamp(); 42 | } 43 | 44 | static Timestamp fromUnixTime(time_t t) 45 | { 46 | return fromUnixTime(t, 0); 47 | } 48 | 49 | static Timestamp fromUnixTime(time_t t, int microseconds) 50 | { 51 | return Timestamp(static_cast(t) * kMicroSecondsPerSecond + microseconds); 52 | } 53 | 54 | public: 55 | static constexpr int kMicroSecondsPerSecond = 1000 * 1000; 56 | 57 | private: 58 | int64_t microSecondsSinceEpoch_; 59 | }; 60 | 61 | inline bool operator<(Timestamp lhs, Timestamp rhs) 62 | { 63 | return lhs.microSecondsSinceEpoch() < rhs.microSecondsSinceEpoch(); 64 | } 65 | 66 | inline bool operator==(Timestamp lhs, Timestamp rhs) 67 | { 68 | return lhs.microSecondsSinceEpoch() == rhs.microSecondsSinceEpoch(); 69 | } 70 | 71 | inline double TimeDifference(Timestamp high, Timestamp low) 72 | { 73 | int64_t diff = high.microSecondsSinceEpoch() - low.microSecondsSinceEpoch(); 74 | return static_cast(diff) / Timestamp::kMicroSecondsPerSecond; 75 | } 76 | 77 | inline Timestamp addTime(Timestamp timestamp, double seconds) 78 | { 79 | int64_t delta = static_cast(seconds * Timestamp::kMicroSecondsPerSecond); 80 | return Timestamp(timestamp.microSecondsSinceEpoch() + delta); 81 | } 82 | 83 | } 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /half_sync_half_reactor/userfactory.h: -------------------------------------------------------------------------------- 1 | #ifndef USERFACTORY_H 2 | #define USERFACTORY_H 3 | 4 | #include 5 | #include 6 | #include "http_conn.h" 7 | #include "thread/criticalsection.h" 8 | #include "commont/constructormagic.h" 9 | #include 10 | 11 | template 12 | class Keyable 13 | { 14 | public: 15 | virtual void set_key(Key key) = 0; 16 | virtual Key key() const = 0; 17 | virtual ~Keyable() {} 18 | protected: 19 | Key key_; 20 | }; 21 | 22 | template 23 | class UserFactory : public std::enable_shared_from_this> 24 | { 25 | public: 26 | /*单例模式,no-thread-safe*/ 27 | static std::shared_ptr> Create() { 28 | if (!instance_) { 29 | instance_ = std::shared_ptr (new UserFactory); 30 | } 31 | return instance_; 32 | } 33 | 34 | std::shared_ptr Get(const Key& key); 35 | 36 | private: 37 | UserFactory() = default; // 让开发者必须使用 create 方法创建 38 | 39 | BASE_DISALLOW_COPY_AND_ASSIGN(UserFactory); 40 | 41 | private: 42 | static void DeleteUserCallback(const std::weak_ptr&weak_userfactory, T* user); 43 | 44 | /*外层没有必要调用 remove,因为套接字会重用*/ 45 | void RemoveUser(T* user); 46 | 47 | private: 48 | static std::shared_ptr> instance_; 49 | 50 | CriticalSection lock_; 51 | std::map> users_; 52 | }; 53 | 54 | template 55 | std::shared_ptr> UserFactory::instance_ = nullptr; 56 | 57 | template 58 | std::shared_ptr UserFactory::Get(const Key& key) 59 | { 60 | CritScope cs(&lock_); // 线程安全 61 | std::shared_ptr& user = users_[key]; 62 | if (!user) 63 | { 64 | // shared_from_this() 可以使引用计数器加1,防止 factory 先于 user 构析导致 core dump. 65 | // 必须强制把 shared_from_this() 转型为 weak_ptr, 才不会延长生命期. 66 | user = std::shared_ptr(new T, std::bind(&UserFactory::DeleteUserCallback, 67 | std::weak_ptr( this->shared_from_this() ), 68 | std::placeholders::_1)); 69 | 70 | user->set_key(key); 71 | } 72 | return user; 73 | } 74 | 75 | template 76 | void UserFactory::DeleteUserCallback(const std::weak_ptr&weak_userfactory, T* user) 77 | { 78 | std::cout << __func__ << ": delete user " << user << " key " << user->key() << std::endl; 79 | std::shared_ptr factory(weak_userfactory.lock()); 80 | if (factory) 81 | { 82 | factory->RemoveUser(user); 83 | } 84 | delete user; 85 | } 86 | 87 | template 88 | void UserFactory::RemoveUser(T* user) 89 | { 90 | if (user) 91 | { 92 | CritScope cs(&lock_); // 注意这里会存在资源竞争问题 93 | users_.erase(user->key()); 94 | } 95 | } 96 | 97 | #endif 98 | -------------------------------------------------------------------------------- /half_sync_half_reactor/thread/thread_pool.h: -------------------------------------------------------------------------------- 1 | #ifndef THREAD_POOL_H 2 | #define THREAD_POOL_H 3 | 4 | #include "criticalsection.h" 5 | #include "event.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | class RequestHandlerInterface { 13 | public: 14 | RequestHandlerInterface () {} 15 | virtual ~RequestHandlerInterface () {} 16 | 17 | virtual void Process() = 0; 18 | virtual bool Write() = 0; 19 | virtual bool Read() = 0; 20 | }; 21 | 22 | template 23 | class ThreadPool { 24 | public: 25 | ThreadPool(int thread_number = 8, int max_requests = 10000); 26 | ~ThreadPool(); 27 | 28 | /*往请求对了中添加任务*/ 29 | bool append(std::shared_ptr request); 30 | 31 | private: 32 | static void* Worker(void* arg); 33 | void Run(); 34 | 35 | private: 36 | int thread_number_; 37 | int max_requests_; 38 | std::unique_ptr event_; 39 | 40 | std::vector threads_; 41 | std::list>work_queue_; 42 | CriticalSection queue_lock_;/*保护请求队列的互斥锁*/ 43 | bool stop_; /*是否结束线程*/ 44 | }; 45 | 46 | template 47 | ThreadPool::ThreadPool(int thread_number, int max_requests) : 48 | thread_number_(thread_number), max_requests_(max_requests), 49 | stop_(false) 50 | { 51 | if (thread_number <= 0 || max_requests_ <= 0) { 52 | throw std::exception(); 53 | } 54 | 55 | threads_ = std::vector(thread_number_); 56 | 57 | event_.reset(new Event(false, false)); 58 | 59 | for (int i = 0; i < thread_number_; i++) 60 | { 61 | printf("create the %dth thread\n", i); 62 | pthread_t& tid = threads_[i]; 63 | if (pthread_create(&tid, NULL, Worker, this) != 0) { 64 | throw std::exception(); 65 | } 66 | if (pthread_detach(tid)) { 67 | throw std::exception(); 68 | } 69 | } 70 | 71 | } 72 | 73 | template 74 | ThreadPool::~ThreadPool() { 75 | stop_ = true; 76 | } 77 | 78 | template 79 | bool ThreadPool::append(std::shared_ptr request) 80 | { 81 | /*操作工作队列一定要加锁*/ 82 | { 83 | CritScope cs(&queue_lock_); 84 | if (work_queue_.size() > max_requests_) { 85 | return false; 86 | } 87 | work_queue_.push_back(request); 88 | } 89 | event_->Set(); 90 | return true; 91 | } 92 | 93 | template 94 | void ThreadPool::Run() 95 | { 96 | // one loop per thread 97 | while(!stop_) 98 | { 99 | event_->Wait(Event::kForever); 100 | std::shared_ptr request; 101 | /*利用线程的抢占模式*/ 102 | { 103 | CritScope cs(&queue_lock_); 104 | 105 | std::cout << "thread: " << pthread_self() << " start handle request!!!" << std::endl; 106 | 107 | if (work_queue_.empty()) 108 | continue; 109 | 110 | request = work_queue_.front(); 111 | work_queue_.pop_front(); 112 | } 113 | 114 | if (!request) 115 | continue; 116 | 117 | request->Process(); 118 | } 119 | } 120 | 121 | /*多线程运行方法*/ 122 | template 123 | void* ThreadPool::Worker(void* arg) { 124 | ThreadPool* pool = static_cast(arg); 125 | pool->Run(); 126 | return pool; 127 | } 128 | 129 | #endif 130 | -------------------------------------------------------------------------------- /half_sync_half_reactor/http_conn.h: -------------------------------------------------------------------------------- 1 | #ifndef HTTP_CONNECTION_H 2 | #define HTTP_CONNECTION_H 3 | 4 | #include "thread/thread_pool.h" 5 | #include "socketaddress.h" 6 | #include 7 | #include "userfactory.h" 8 | 9 | class HTTPConn : public RequestHandlerInterface, public Keyable { 10 | public: 11 | HTTPConn(); 12 | ~HTTPConn(); 13 | 14 | public: 15 | void Init(int sock_fd, const SocketAddress& addr); 16 | 17 | void Process() override; 18 | 19 | /*非阻塞读操作, 开发者先使用 Read 将用户请求字节读取,然后调用 process 去去处理字节*/ 20 | bool Read() override; 21 | 22 | bool Write() override; 23 | 24 | void set_key(int key) override { key_ = key; } 25 | 26 | int key() const override { return key_; } 27 | 28 | void CloseConn(bool real_close = true); 29 | public: 30 | /*文件名的最大长度*/ 31 | static const int FILENAME_LEN = 200; 32 | /*读缓冲区的大小*/ 33 | static const int READ_BUFFER_SIZE = 2048; 34 | /*写缓冲区的大小*/ 35 | static const size_t WRITE_BUFFER_SIZE = 1024; 36 | 37 | /*HTTP请求方法,但我们仅支持Get*/ 38 | enum METHOD{GET = 0, POST, HEAD, PUT, DELETE, OPTIONS, CONNECT, PATCH}; 39 | /*解析客户请求时,主机状态所处的状态*/ 40 | enum CHECK_STATE{REQUESTING = 0, HEADER, CONNENT}; 41 | /*服务器处理HTTP请求可能的结果*/ 42 | enum HTTP_CODE{NO_REQUEST, GET_REQUEST, BAD_REQUEST, 43 | NO_RESOURCE, FORBIDDEN_REQUEST, FILE_REQUEST, INTERNAL_ERROR, CLOSE_CONNECTION}; 44 | /*行的读取状态*/ 45 | enum LINE_STATUS {LINE_OK = 0, LINE_BAD, LINE_OPEN}; 46 | 47 | public: 48 | 49 | static int epoll_fd_; 50 | static int user_count_; 51 | 52 | private: 53 | void Init(); 54 | 55 | HTTP_CODE ProcessRead(); 56 | 57 | bool ProcessWrite(HTTP_CODE code); 58 | 59 | LINE_STATUS ParseLine(); 60 | 61 | HTTP_CODE ParseRequestLine(char* text); 62 | 63 | HTTP_CODE ParseHeaders(char* text); 64 | 65 | HTTP_CODE ParseContent(char* text); 66 | 67 | HTTP_CODE DoRequest(); 68 | 69 | bool AddStatusLine(int status, const char* title); 70 | 71 | bool AddHeaders(int content_length); 72 | 73 | bool AddContent(const char* content); 74 | 75 | bool AddContentLength(int content_length); 76 | 77 | bool AddKeepLive(); 78 | 79 | bool AddBlankLine(); 80 | 81 | bool AddResponse(const char* format, ...); 82 | 83 | char* GetLine() { return read_buf_ + start_line_; } 84 | 85 | void Unmap(); 86 | private: 87 | int sock_fd_; 88 | SocketAddress addr_; 89 | /*读缓冲区*/ 90 | char read_buf_[READ_BUFFER_SIZE]; 91 | /*标识读缓冲区已经读入的客户数据最后一个字节的下一个位置*/ 92 | int read_idx_; 93 | /*当前正在分析的字符在读缓冲区中的位置*/ 94 | int checked_idx_; 95 | /*当前正在解析行的起始位置*/ 96 | int start_line_; 97 | /*写缓冲区*/ 98 | char write_buf_[WRITE_BUFFER_SIZE]; 99 | /*写缓冲区中待发送的字节数*/ 100 | size_t write_idx_; 101 | /*主状态机当前所处状态*/ 102 | int check_state_; 103 | /*请求方式*/ 104 | METHOD method_; 105 | /*客户请求目标文件的完整路径*/ 106 | char real_file_[FILENAME_LEN]; 107 | /*客户请求的目标文件的文件名*/ 108 | char* url_; 109 | /*HTTP 协议版本号,目标仅支持 HTTP/1.1*/ 110 | char* version_; 111 | /*主机名*/ 112 | std::string host_; 113 | /*HTTP请求的消息体长度*/ 114 | int content_length_; 115 | /*HTTP请求是否要求保持连接*/ 116 | bool keeplive_; 117 | /*客户请求的文件被mmap到内存中的起始位置*/ 118 | char* file_address_; 119 | /*目标文件状态。通过它们我们可以判断文件是否存在,是否为目录,是否可读,并获取 120 | *文件大小等信息*/ 121 | struct stat file_stat_; 122 | /*我们将采用 writev 来执行写操作,所以定义下面两个成员,其中 iv_count_ 表示被 123 | * 写入内存块的数量*/ 124 | struct iovec iv_[2]; 125 | int iv_count_; 126 | }; 127 | 128 | #endif 129 | -------------------------------------------------------------------------------- /half_sync_half_reactor/logging/logging.h: -------------------------------------------------------------------------------- 1 | #ifndef BASE_LOGGGING_H 2 | #define BASE_LOGGGING_H 3 | 4 | #include 5 | #include 6 | #include "timestamp.h" 7 | #include "logstream.h" 8 | 9 | namespace base 10 | { 11 | 12 | class TimeZone; 13 | 14 | class Logger 15 | { 16 | public: 17 | enum LogLevel 18 | { 19 | TRACE, 20 | DEBUG, 21 | INFO, 22 | WARN, 23 | ERROR, 24 | FATAL, 25 | NUM_LOG_LEVELS, 26 | }; 27 | 28 | class SourceFile 29 | { 30 | public: 31 | template 32 | inline SourceFile(const char(&arr)[N]) /*const char (&arr)[N] C 字符串的引用*/ 33 | : data_(arr), 34 | size_(N-1) 35 | { 36 | /*查找到字符 '/' 后面的字符串才是真正的文件*/ 37 | const char* slash = strrchr(data_, '/'); 38 | if (slash) 39 | { 40 | data_ = slash + 1; 41 | size_ -= static_cast(data_ - arr); 42 | } 43 | } 44 | 45 | explicit SourceFile(const char* filename) 46 | : data_(filename) 47 | { 48 | /*查找到字符 '/' 后面的字符串才是真正的文件*/ 49 | const char* slash = strrchr(data_, '/'); 50 | if (slash) 51 | { 52 | data_ = slash + 1; 53 | } 54 | size_ = static_cast(strlen(data_)); 55 | } 56 | 57 | const char* data_; 58 | int size_; 59 | }; 60 | 61 | Logger(SourceFile file, int line); 62 | Logger(SourceFile file, int line, LogLevel level); 63 | Logger(SourceFile file, int line, LogLevel level, const char* func); 64 | Logger(SourceFile file, int line, bool toAbort); 65 | ~Logger(); 66 | 67 | LogStream& stream() { return impl_.stream_; } 68 | 69 | static LogLevel loglevel(); 70 | static void setLogLevel(LogLevel level); 71 | 72 | typedef std::function OutputFunc; 73 | typedef std::function FlushFunc; 74 | static void setOutput(OutputFunc); 75 | static void setFlush(FlushFunc); 76 | static void setTimezone(const TimeZone& tz); 77 | 78 | private: 79 | 80 | class Impl 81 | { 82 | public: 83 | typedef Logger::LogLevel LogLevel; 84 | Impl(LogLevel level, int old_errno, const SourceFile& file, int line); 85 | void formatTime(); 86 | void finish(); 87 | 88 | Timestamp time_; 89 | LogStream stream_; 90 | LogLevel level_; 91 | int line_; 92 | SourceFile basename_; 93 | }; 94 | 95 | Impl impl_; 96 | }; 97 | 98 | extern Logger::LogLevel g_logLevel; 99 | 100 | inline Logger::LogLevel Logger::loglevel() 101 | { 102 | return g_logLevel; 103 | } 104 | 105 | #define LOG_TRACE if (base::Logger::loglevel() <= base::Logger::LogLevel::TRACE) \ 106 | base::Logger(__FILE__, __LINE__, base::Logger::LogLevel::TRACE, __func__).stream() 107 | 108 | #define LOG_INFO if (base::Logger::loglevel() <= base::Logger::LogLevel::INFO) \ 109 | base::Logger(__FILE__, __LINE__).stream() 110 | 111 | #define LOG_DEBUG if (base::Logger::loglevel() <= base::Logger::LogLevel::DEBUG) \ 112 | base::Logger(__FILE__, __LINE__, base::Logger::LogLevel::DEBUG, __func__).stream() 113 | 114 | #define LOG_WARN base::Logger(__FILE__, __LINE__, base::Logger::LogLevel::WARN).stream() 115 | 116 | #define LOG_ERROR base::Logger(__FILE__, __LINE__, base::Logger::LogLevel::ERROR).stream() 117 | 118 | #define LOG_FATAL base::Logger(__FILE__, __LINE__, base::Logger::LogLevel::FATAL).stream() 119 | 120 | #define LOG_SYSERR base::Logger(__FILE__, __LINE__, false).stream() 121 | #define LOG_SYSFATAL base::Logger(__FILE__, __LINE__, true).stream() 122 | 123 | template 124 | T* CheckNotNull(Logger::SourceFile file, int line, const char* names, T* ptr) 125 | { 126 | if (ptr == nullptr) 127 | { 128 | Logger(file, line, Logger::FATAL).stream() << names; 129 | } 130 | } 131 | 132 | } 133 | 134 | #endif 135 | -------------------------------------------------------------------------------- /half_sync_half_reactor/logging/logstream.cpp: -------------------------------------------------------------------------------- 1 | #include "logstream.h" 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace base 8 | { 9 | namespace detail 10 | { 11 | 12 | const char digits[] = "9876543210123456789"; 13 | const char* zero = digits + 9; 14 | 15 | const char digitsHex[] = "0123456789ABCDEF"; 16 | 17 | template 18 | size_t covert(char buf[], T value) 19 | { 20 | T i = value; 21 | char* p = buf; 22 | /*从 value 中每个位转为 0-9 的字符串*/ 23 | do 24 | { 25 | int lsd = static_cast( i % 10 ); 26 | i /= 10; 27 | *p++ = zero[lsd]; 28 | } while(i != 0); 29 | 30 | /*添加正负号*/ 31 | if (value < 0) 32 | { 33 | *p++ = '-'; 34 | } 35 | *p = '\0'; 36 | /* 由于是从个位开始添加字符串的,需要反转容器元素顺序 */ 37 | std::reverse(buf, p); 38 | 39 | return p - buf; 40 | } 41 | 42 | size_t convertHex(char buf[], uintptr_t value) 43 | { 44 | uintptr_t i = value; 45 | char* p = buf; 46 | 47 | do 48 | { 49 | int lsd = static_cast(i % 16); 50 | i /= 16; 51 | *p++ = digitsHex[lsd]; 52 | } while(i != 0); 53 | *p++ = '\0'; 54 | std::reverse(buf, p); 55 | 56 | return p - buf; 57 | } 58 | 59 | template class FixedBuffer; 60 | template class FixedBuffer; 61 | 62 | } 63 | } 64 | 65 | using namespace base; 66 | using namespace base::detail; 67 | 68 | template 69 | const char* FixedBuffer::debugString() 70 | { 71 | *cur_ = '\0'; 72 | return data_; 73 | } 74 | 75 | template 76 | void FixedBuffer::cookieStart() 77 | { 78 | } 79 | 80 | template 81 | void FixedBuffer::cookieEnd() 82 | { 83 | } 84 | 85 | /* LogStream */ 86 | void LogStream::staticCheck() 87 | { 88 | } 89 | 90 | template 91 | void LogStream::formatInteger(T v) 92 | { 93 | if (buffer_.avail() >= kMaxNumericSize) 94 | { 95 | size_t len = covert(buffer_.current(), v); 96 | buffer_.add(len); 97 | } 98 | } 99 | 100 | LogStream& LogStream::operator<<(int v) 101 | { 102 | formatInteger(v); 103 | return *this; 104 | } 105 | 106 | LogStream& LogStream::operator<<(unsigned int v) 107 | { 108 | formatInteger(v); 109 | return *this; 110 | } 111 | 112 | LogStream& LogStream::operator<<(short v) 113 | { 114 | *this << static_cast(v); 115 | return *this; 116 | } 117 | 118 | LogStream& LogStream::operator<<(unsigned short v) 119 | { 120 | *this << static_cast(v); 121 | return *this; 122 | } 123 | 124 | LogStream& LogStream::operator<<(long v) 125 | { 126 | formatInteger(v); 127 | return *this; 128 | } 129 | 130 | LogStream& LogStream::operator<<(unsigned long v) 131 | { 132 | formatInteger(v); 133 | return *this; 134 | } 135 | 136 | LogStream& LogStream::operator<<(long long v) 137 | { 138 | formatInteger(v); 139 | return *this; 140 | } 141 | 142 | LogStream& LogStream::operator<<(unsigned long long v) 143 | { 144 | formatInteger(v); 145 | return *this; 146 | } 147 | 148 | LogStream& LogStream::operator<<(const void* v) 149 | { 150 | uintptr_t p = reinterpret_cast(v); 151 | if (buffer_.avail() >= kMaxNumericSize) 152 | { 153 | char* buf = buffer_.current(); 154 | buf[0] = '0'; 155 | buf[1] = 'x'; 156 | size_t len = convertHex(buf+2, p); 157 | buffer_.add(len); 158 | } 159 | return *this; 160 | } 161 | 162 | template 163 | Fmt::Fmt(const char* fmt, T val) 164 | { 165 | length_ = snprintf(buf_, sizeof(buf_), fmt, val); 166 | assert(static_cast(length_) < sizeof(buf_)); 167 | } 168 | 169 | /* 显式实例化 */ 170 | template Fmt::Fmt(const char* fmt, char); 171 | template Fmt::Fmt(const char* fmt, short); 172 | template Fmt::Fmt(const char* fmt, unsigned short); 173 | template Fmt::Fmt(const char* fmt, int); 174 | template Fmt::Fmt(const char* fmt, unsigned int); 175 | template Fmt::Fmt(const char* fmt, long); 176 | template Fmt::Fmt(const char* fmt, unsigned long); 177 | template Fmt::Fmt(const char* fmt, long long); 178 | template Fmt::Fmt(const char* fmt, unsigned long long); 179 | 180 | template Fmt::Fmt(const char* fmt, float); 181 | template Fmt::Fmt(const char* fmt, double); 182 | 183 | 184 | -------------------------------------------------------------------------------- /half_sync_half_reactor/logging/logstream.h: -------------------------------------------------------------------------------- 1 | #ifndef BASE_LOGSTREAM_H 2 | #define BASE_LOGSTREAM_H 3 | 4 | #include "../commont/constructormagic.h" 5 | #include 6 | #include 7 | 8 | namespace base 9 | { 10 | namespace detail 11 | { 12 | 13 | const int kSmallBuffer = 4 * 1024; 14 | const int kLargeBuffer = 4 * 1024 * 1024; 15 | 16 | template 17 | class FixedBuffer 18 | { 19 | public: 20 | FixedBuffer() 21 | : cur_(data_) 22 | { 23 | setCookie(cookieEnd); 24 | } 25 | 26 | ~FixedBuffer() 27 | { 28 | setCookie(cookieEnd); 29 | } 30 | 31 | void setCookie(std::function func) 32 | { 33 | cookie_ = func; 34 | } 35 | 36 | void append(const char* buf, size_t len) 37 | { 38 | if (static_cast(avail() > len)) 39 | { 40 | memcpy(cur_, buf, len); 41 | cur_ += len; 42 | } 43 | } 44 | 45 | void append(const std::string& buf) 46 | { 47 | append(buf.c_str(), buf.size()); 48 | } 49 | 50 | const char* data() const { return data_; } 51 | int length() const { return static_cast(cur_ - data_); } 52 | 53 | char* current() { return cur_; } 54 | int avail() const { return static_cast(end() - cur_); } 55 | void add(size_t len) { cur_ += len; } 56 | 57 | void reset() { cur_ = data_; } 58 | void bzero() { ::bzero(data_, sizeof(data_)); } 59 | 60 | const char* debugString(); 61 | 62 | std::string toString() const { return std::string(data_, length()); } 63 | 64 | private: 65 | const char* end() const { return data_ + sizeof(data_); } 66 | static void cookieStart(); 67 | static void cookieEnd(); 68 | 69 | std::function cookie_; 70 | char data_[SIZE]; 71 | char* cur_; 72 | 73 | private: 74 | BASE_DISALLOW_ASSIGN(FixedBuffer); 75 | }; 76 | 77 | } 78 | 79 | class LogStream 80 | { 81 | typedef LogStream self; 82 | public: 83 | typedef detail::FixedBuffer Buffer; 84 | 85 | self& operator<<(bool v) 86 | { 87 | buffer_.append(v ? "1" : "0"); 88 | return *this; 89 | } 90 | 91 | self& operator<<(short); 92 | self& operator<<(unsigned short); 93 | self& operator<<(int); 94 | self& operator<<(unsigned int); 95 | self& operator<<(long); 96 | self& operator<<(unsigned long); 97 | self& operator<<(long long); 98 | self& operator<<(unsigned long long); 99 | 100 | self& operator<<(const void*); 101 | 102 | self& operator<<(float v) 103 | { 104 | *this << static_cast(v); 105 | return *this; 106 | } 107 | 108 | self& operator<<(double v); 109 | 110 | self& operator<<(char v) 111 | { 112 | buffer_.append(&v, 1); 113 | return *this; 114 | } 115 | 116 | self& operator<<(const char* str) 117 | { 118 | if (str) 119 | { 120 | buffer_.append(str, strlen(str)); 121 | return *this; 122 | } 123 | else 124 | { 125 | buffer_.append("(null)"); 126 | } 127 | return *this; 128 | } 129 | 130 | self& operator<<(const unsigned char* str) 131 | { 132 | return operator<<(reinterpret_cast(str)); 133 | } 134 | 135 | self& operator<<(const std::string& v) 136 | { 137 | buffer_.append(v); 138 | return *this; 139 | } 140 | 141 | void append(const char* data, int len) { buffer_.append(data, len); } 142 | const Buffer& buffer() const { return buffer_; } 143 | void resetBuffer() { buffer_.reset(); } 144 | 145 | private: 146 | void staticCheck(); 147 | 148 | template 149 | void formatInteger(T); 150 | 151 | Buffer buffer_; 152 | 153 | static const int kMaxNumericSize = 32; 154 | private: 155 | BASE_DISALLOW_ASSIGN(LogStream); 156 | }; 157 | 158 | class Fmt 159 | { 160 | public: 161 | template 162 | Fmt(const char* fmt, T val); 163 | 164 | const char* data() const { return buf_; } 165 | int length() const { return length_; } 166 | 167 | private: 168 | char buf_[32]; 169 | int length_; 170 | }; 171 | 172 | inline LogStream& operator<<(LogStream& s, const Fmt& fmt) 173 | { 174 | s.append(fmt.data(), fmt.length()); 175 | return s; 176 | } 177 | 178 | } 179 | 180 | #endif 181 | -------------------------------------------------------------------------------- /half_sync_half_reactor/database/database_service.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | bool TestQueryDatabase(MYSQL& sql, const std::string& user, const std::string& password, 5 | const std::string& database); 6 | 7 | bool TestInsertDatabase(MYSQL& mysql, const std::string& user, const std::string& password, 8 | const std::string& database); 9 | 10 | bool TestDeleteDatabase(MYSQL& mysql, const std::string& user, const std::string& password, 11 | const std::string& database); 12 | 13 | int main(int argc, const char* argv[]) { 14 | 15 | std::string user = "root"; 16 | std::string password = "5201314Cong"; 17 | std::string host = "localhost"; 18 | std::string database = "custom_test_database"; 19 | 20 | MYSQL mysql; 21 | 22 | if (!(mysql_init(&mysql))) 23 | { 24 | printf("mysql_init():%s\n", mysql_error(&mysql)); 25 | return -1; 26 | } 27 | 28 | if (!(mysql_real_connect(&mysql, host.c_str(), user.c_str(), password.c_str(), 29 | database.c_str(), 0, nullptr, 0))) 30 | { 31 | printf("mysql_real_connect(): %s\n", mysql_error(&mysql)); 32 | return -1; 33 | } 34 | 35 | printf("Connected MySQL successful! \n"); 36 | 37 | // Do something 38 | 39 | /*Insert*/ 40 | TestInsertDatabase(mysql, user, password, database); 41 | 42 | /*Query*/ 43 | TestQueryDatabase(mysql, user, password, database); 44 | 45 | /*Delete*/ 46 | TestDeleteDatabase(mysql, user, password, database); 47 | 48 | printf("after delete \n\n\n"); 49 | 50 | /*Query*/ 51 | TestQueryDatabase(mysql, user, password, database); 52 | 53 | mysql_close(&mysql); 54 | 55 | return 0; 56 | } 57 | 58 | bool TestInsertDatabase(MYSQL& mysql, const std::string& user, const std::string& password, 59 | const std::string& database) 60 | { 61 | std::string option = "set names utf8"; 62 | mysql_real_query(&mysql, option.c_str(), option.size()); 63 | 64 | std::string query_str = "insert into msg (title, name, content) values(\"mysql有没有好用的库 \", \"petter\", \"找一个github上好用的库\")"; 65 | int ret = mysql_real_query(&mysql, query_str.c_str(), query_str.size()); 66 | if (0 != ret) 67 | { 68 | printf("mysql_real_query(): %s\n", mysql_error(&mysql)); 69 | return false; 70 | } 71 | return true; 72 | } 73 | 74 | bool TestDeleteDatabase(MYSQL& mysql, const std::string& user, const std::string& password, 75 | const std::string& database) 76 | { 77 | 78 | std::string option = "set names utf8"; 79 | mysql_real_query(&mysql, option.c_str(), option.size()); 80 | 81 | std::string query_str = "delete from msg where id = 3"; 82 | int ret = mysql_real_query(&mysql, query_str.c_str(), query_str.size()); 83 | if (0 != ret) 84 | { 85 | printf("mysql_real_query(): %s\n", mysql_error(&mysql)); 86 | return false; 87 | } 88 | 89 | return true; 90 | } 91 | 92 | bool TestQueryDatabase(MYSQL& sql, const std::string& user, const std::string& password, 93 | const std::string& database) 94 | { 95 | MYSQL_RES* result; 96 | MYSQL_ROW sql_row; 97 | 98 | int ret = 0; 99 | 100 | std::string option = "set names utf8"; 101 | mysql_real_query(&sql, option.c_str(), option.size()); 102 | 103 | std::string sql_str = "select * from msg"; 104 | ret = mysql_real_query(&sql, sql_str.c_str(), sql_str.size()); 105 | 106 | if (ret == 0) 107 | { 108 | result = mysql_store_result(&sql); 109 | if (result) 110 | { 111 | int fields = mysql_num_fields(result); 112 | int rows = mysql_num_rows(result); 113 | printf("有多少行数据: %d\n", rows); 114 | printf("每行数据有多少列: %d\n", fields); 115 | printf("desc table msg\n"); 116 | while ((sql_row = mysql_fetch_row(result))) 117 | { 118 | printf("get message:\n"); 119 | for (int i = 0; i < fields; ++i) 120 | { 121 | printf("%s ", sql_row[i]); 122 | } 123 | printf("\n"); 124 | } 125 | } 126 | else 127 | { 128 | std::cout << "mysql_store_result is failured" << std::endl; 129 | } 130 | } 131 | else 132 | { 133 | std::cout << "mysql_query is failured" << std::endl; 134 | } 135 | 136 | if (ret) 137 | { 138 | mysql_free_result(result); 139 | } 140 | 141 | return 0; 142 | } 143 | -------------------------------------------------------------------------------- /half_sync_half_reactor/web_server.cpp: -------------------------------------------------------------------------------- 1 | #include "http_conn.h" 2 | #include "commont/commont.h" 3 | #include "userfactory.h" 4 | 5 | #define MAX_FD 0x10000 6 | #define MAX_EVENT_NUMBER 10000 7 | 8 | extern bool HandleListen(int listen_fd); 9 | 10 | extern bool HandleReadConnfd(int connfd); 11 | 12 | extern bool HandleWriteConnfd(int connfd); 13 | 14 | /*预先未每个可能的客户连接分配一个 HTTPConn 对象*/ 15 | //std::vector> users(MAX_FD, std::make_shared()); 16 | 17 | std::shared_ptr> users(UserFactory::Create()); 18 | 19 | std::unique_ptr> pool = nullptr; 20 | 21 | int main(int argc, const char* argv[]) 22 | { 23 | if (argc <= 2) { 24 | printf("usage:%s ipaddress port_number\n", argv[0]); 25 | return 1; 26 | } 27 | const char* ip = argv[1]; 28 | int port = atoi(argv[2]); 29 | 30 | /*忽略SIGPIPE信号*/ 31 | base::AddSig(SIGPIPE, SIG_IGN); 32 | 33 | try 34 | { 35 | pool.reset(new ThreadPool()); 36 | } 37 | catch (...) 38 | { 39 | return 1; 40 | } 41 | 42 | int listen_fd = socket(PF_INET, SOCK_STREAM, 0); 43 | assert(listen_fd); 44 | 45 | /* close() 后立刻返回,但不会发送未发送完成的数据,而是通过一个REST包强制的关闭socket描述符,即强制退出。 46 | * */ 47 | struct linger temp = {1, 0}; 48 | setsockopt(listen_fd, SOL_SOCKET, SO_LINGER, &temp, sizeof(temp)); 49 | 50 | sockaddr_in sock_addr; 51 | SocketAddress addr = SocketAddress(std::string(ip), port); 52 | addr.ToSockAddr(&sock_addr); 53 | int ret = bind(listen_fd, (struct sockaddr*)&sock_addr, sizeof(sock_addr)); 54 | assert(ret >= 0); 55 | 56 | ret = listen(listen_fd, 5); 57 | assert(ret >= 0); 58 | 59 | epoll_event events[MAX_EVENT_NUMBER]; 60 | int epoll_fd = epoll_create(5); 61 | assert(epoll_fd != -1); 62 | 63 | base::AddFd(epoll_fd, listen_fd); 64 | HTTPConn::epoll_fd_ = epoll_fd; 65 | 66 | // event loop 67 | while(1) 68 | { 69 | int number = epoll_wait(epoll_fd, events, MAX_EVENT_NUMBER, -1); 70 | if (number < 0 && errno != EINTR) 71 | { 72 | printf("epoll failure\n"); 73 | break; 74 | } 75 | for (int i = 0; i < number; i++) 76 | { 77 | int sock_fd = events[i].data.fd; 78 | 79 | if (sock_fd == listen_fd && events[i].events & EPOLLIN) 80 | { 81 | bool ret = HandleListen(listen_fd); 82 | if (!ret) { continue; } 83 | } 84 | else if (events[i].events & (EPOLLRDHUP | EPOLLHUP | EPOLLERR)) 85 | { 86 | /*发生异常,直接关闭客户连接*/ 87 | users->Get(sock_fd)->CloseConn(true); 88 | } 89 | else if (events[i].events & EPOLLIN) 90 | { 91 | HandleReadConnfd(sock_fd); 92 | } 93 | else if (events[i].events & EPOLLOUT) 94 | { 95 | HandleWriteConnfd(sock_fd); 96 | } 97 | else{ 98 | std::cout << "get some havent hanndle epoll event" << std::endl; 99 | } 100 | } 101 | } 102 | 103 | base::RemoveFd(epoll_fd, listen_fd); 104 | close(epoll_fd); 105 | return 0; 106 | } 107 | 108 | bool HandleListen(int listen_fd) 109 | { 110 | sockaddr_in client_addr; 111 | socklen_t len = sizeof(client_addr); 112 | int connfd = accept(listen_fd, (struct sockaddr*)&client_addr, &len); 113 | if (connfd < 0) 114 | { 115 | printf("errno is: %d\n", errno); 116 | return false; 117 | } 118 | if (HTTPConn::user_count_ >= MAX_FD) 119 | { 120 | base::ShowError(connfd, "Internal server busy"); 121 | return false; 122 | } 123 | SocketAddress addr; 124 | addr.FromSockAddr(client_addr); 125 | /*初始化客户连接*/ 126 | users->Get(connfd)->Init(connfd, addr); 127 | return true; 128 | } 129 | 130 | bool HandleReadConnfd(int connfd) 131 | { 132 | /*根据读的结果, 决定是将任务添加到线程池, 还是关闭连接*/ 133 | bool ret = users->Get(connfd)->Read(); // 获取客户端发送的字节流 134 | printf("%s return %d \n", __func__, ret); 135 | if (ret) 136 | { 137 | pool->append(users->Get(connfd)); // 通过线程池,派发到子线程当中去处理读操作 138 | return true; 139 | } 140 | else 141 | { 142 | users->Get(connfd)->CloseConn(true); 143 | return false; 144 | } 145 | } 146 | 147 | bool HandleWriteConnfd(int connfd) 148 | { 149 | bool ret = users->Get(connfd)->Write(); 150 | printf("%s return %d \n", __func__, ret); 151 | if (!ret) 152 | { 153 | users->Get(connfd)->CloseConn(true); 154 | return true; 155 | } 156 | return false; 157 | } 158 | -------------------------------------------------------------------------------- /half_sync_half_reactor/socketaddress.cpp: -------------------------------------------------------------------------------- 1 | #include "socketaddress.h" 2 | #include 3 | #include 4 | 5 | void SocketAddress::Clear() { 6 | hostname_.clear(); 7 | literal_ = false; 8 | ip_ = IPAddress(); 9 | port_ = 0; 10 | scope_id_ = 0; 11 | } 12 | 13 | SocketAddress::SocketAddress() { 14 | Clear(); 15 | } 16 | 17 | SocketAddress::SocketAddress(const std::string& hostname, int port) { 18 | SetIP(hostname); 19 | SetPort(port); 20 | } 21 | 22 | SocketAddress::SocketAddress(uint32_t ip_as_host_order_interger, int port) { 23 | SetIP(IPAddress(ip_as_host_order_interger)); 24 | SetPort(port); 25 | } 26 | 27 | SocketAddress::SocketAddress(const IPAddress& ip, int port) { 28 | SetIP(ip); 29 | SetPort(port); 30 | } 31 | 32 | SocketAddress::SocketAddress(const SocketAddress& addr) { 33 | this->operator=(addr); 34 | } 35 | 36 | const SocketAddress & SocketAddress::operator=(const SocketAddress& addr) { 37 | hostname_ = addr.hostname_; 38 | ip_ = addr.ip_; 39 | port_ = addr.port_; 40 | scope_id_ = addr.scope_id_; 41 | literal_ = addr.literal_; 42 | return *this; 43 | } 44 | 45 | void SocketAddress::SetIP(const std::string& hostname) { 46 | hostname_ = hostname; 47 | literal_ = IPFromString(hostname, &ip_); 48 | if (!literal_) { 49 | ip_ = IPAddress(); 50 | } 51 | scope_id_ = 0; 52 | } 53 | 54 | void SocketAddress::SetIP(const IPAddress& ip) { 55 | hostname_.clear(); 56 | literal_ = false; 57 | ip_ = ip; 58 | scope_id_ = 0; 59 | } 60 | 61 | void SocketAddress::SetIP(uint32_t ip_as_host_order_interger) { 62 | hostname_.clear(); 63 | literal_ = false; 64 | ip_ = IPAddress(ip_as_host_order_interger); 65 | scope_id_ = 0; 66 | } 67 | 68 | void SocketAddress::SetPort(int port) { 69 | port_ = static_cast(port); 70 | } 71 | 72 | bool SocketAddress::IPIsLoopbackIP() const { 73 | return IPIsLoopback(ip_) || (IPIsAny(ip_) && 74 | 0 == strcmp(hostname_.c_str(), "localhost")); 75 | } 76 | 77 | bool SocketAddress::IsPrivateIP() const { 78 | return IPIsPrivateNetWork(ip_); 79 | } 80 | 81 | void SocketAddress::ToSockAddr(sockaddr_in* saddr) const { 82 | 83 | memset(saddr, 0, sizeof(*saddr)); 84 | 85 | if (ip_.family() != AF_INET) { 86 | saddr->sin_family = AF_UNSPEC; 87 | return; 88 | } 89 | 90 | saddr->sin_family = AF_INET; 91 | saddr->sin_port = htons(port_); 92 | if (IPIsAny(ip_)) { 93 | saddr->sin_addr.s_addr = INADDR_ANY; 94 | } 95 | else { 96 | saddr->sin_addr = ip_.ip4_address(); 97 | } 98 | } 99 | 100 | bool SocketAddress::FromSockAddr(const sockaddr_in& saddr) { 101 | if (saddr.sin_family != AF_INET) 102 | return false; 103 | 104 | SetIP(ntohl(saddr.sin_addr.s_addr)); 105 | SetPort(ntohs(saddr.sin_port)); 106 | literal_ = false; 107 | return true; 108 | } 109 | 110 | std::string SocketAddress::HostAsURIString() const { 111 | // If the hostname was a literal IP string, it may need to have square 112 | // brackets added (for SocketAddress::ToString()). 113 | if (!literal_ && !hostname_.empty()) { 114 | return hostname_; 115 | } 116 | if (ip_.family() == AF_INET6) { 117 | return "[" + ip_.ToString() + "]"; 118 | } 119 | return ip_.ToString(); 120 | } 121 | 122 | std::string SocketAddress::PortAsString() const { 123 | std::ostringstream ost; 124 | ost << port_; 125 | return ost.str(); 126 | } 127 | 128 | uint32_t SocketAddress::ip() const { 129 | return ip_.v4AddressAsHostOrderInteger(); 130 | } 131 | 132 | const IPAddress& SocketAddress::ipaddr() const { 133 | return ip_; 134 | } 135 | 136 | std::string SocketAddress::ToString() const { 137 | std::ostringstream ost; 138 | ost << *this; 139 | return ost.str(); 140 | } 141 | 142 | std::ostream& operator<<(std::ostream& os, const SocketAddress& addr) { 143 | os << addr.HostAsURIString() << ":" << addr.port(); 144 | return os; 145 | } 146 | 147 | bool SocketAddress::EqualIPs(const SocketAddress& addr) const { 148 | return (ip_ == addr.ip_ && ((!IPIsAny(ip_) && !IPIsUnspec(ip_)) || 149 | hostname_ == addr.hostname_)); 150 | } 151 | 152 | bool SocketAddress::EqualPorts(const SocketAddress& addr) const { 153 | return port_ == addr.port_; 154 | } 155 | 156 | bool SocketAddress::operator==(const SocketAddress& addr) const { 157 | return EqualIPs(addr) && EqualPorts(addr); 158 | } 159 | 160 | SocketAddress EmptySocketAddressWithFamily(int family) { 161 | if (family == AF_INET) { 162 | return SocketAddress(IPAddress(INADDR_ANY), 0); 163 | } 164 | else if (family == AF_INET6) { 165 | return SocketAddress(IPAddress(in6addr_any), 0); 166 | } 167 | return SocketAddress(); 168 | } 169 | -------------------------------------------------------------------------------- /half_sync_half_reactor/logging/logging.cpp: -------------------------------------------------------------------------------- 1 | #include "logging.h" 2 | 3 | #include "logstream.h" 4 | #include "timezone.h" 5 | #include "current_thread.h" 6 | 7 | #include 8 | #include 9 | 10 | namespace base 11 | { 12 | 13 | __thread char t_errnobuf[512]; 14 | __thread char t_time[64]; 15 | __thread time_t t_lastSecond; 16 | 17 | const char* strerror_tl(int savedErrno) 18 | { 19 | return strerror_r(savedErrno, t_errnobuf, sizeof(t_errnobuf)); 20 | } 21 | 22 | Logger::LogLevel initLogLevel() 23 | { 24 | if (::getenv("BASE_LOG_TRACE")) 25 | return Logger::TRACE; 26 | else if (::getenv("BASE_LOG_DEBUG")) 27 | return Logger::DEBUG; 28 | else 29 | return Logger::INFO; 30 | } 31 | 32 | Logger::LogLevel g_logLevel = initLogLevel(); 33 | 34 | const char* LogLevelName[Logger::NUM_LOG_LEVELS] = 35 | { 36 | "TRACE ", 37 | "DEBUG ", 38 | "INFO ", 39 | "WARN ", 40 | "ERROR ", 41 | "FATAL ", 42 | }; 43 | 44 | class T 45 | { 46 | public: 47 | T(const char* str, unsigned len) 48 | : str_(str), 49 | len_(len) 50 | { 51 | assert(strlen(str) == len_); 52 | } 53 | 54 | const char* str_; 55 | const unsigned len_; 56 | }; 57 | 58 | inline LogStream& operator<<(LogStream& s, T v) 59 | { 60 | s.append(v.str_, v.len_); 61 | return s; 62 | } 63 | 64 | inline LogStream& operator<<(LogStream& s, const Logger::SourceFile& v) 65 | { 66 | s.append(v.data_, v.size_); 67 | return s; 68 | } 69 | 70 | void defaultOutput(const char* msg, int len) 71 | { 72 | size_t n = fwrite(msg, 1, len, stdout); 73 | static_cast(n); 74 | } 75 | 76 | void defaultFlush() 77 | { 78 | fflush(stdout); 79 | } 80 | 81 | Logger::OutputFunc g_output = defaultOutput; 82 | Logger::FlushFunc g_flush = defaultFlush; 83 | TimeZone g_logTimeZone; 84 | 85 | } 86 | 87 | using namespace base; 88 | 89 | Logger::Impl::Impl(Logger::LogLevel level, int savedErrno, const Logger::SourceFile& file, int line) 90 | : time_(Timestamp::now()), 91 | stream_(), 92 | level_(level), 93 | line_(line), 94 | basename_(file) 95 | { 96 | formatTime(); 97 | CurrentThread::tid(); 98 | stream_ << T(CurrentThread::tidString(), CurrentThread::tidStringLength()); 99 | stream_ << T(LogLevelName[level], 6); 100 | if (savedErrno != 0) 101 | { 102 | stream_ << strerror_tl(savedErrno) << " (errno=" << savedErrno << ") "; 103 | } 104 | } 105 | 106 | void Logger::Impl::formatTime() 107 | { 108 | int64_t microSecondsSinceEpoch = time_.microSecondsSinceEpoch(); 109 | /* 秒 */ 110 | time_t seconds = static_cast(microSecondsSinceEpoch / Timestamp::kMicroSecondsPerSecond); 111 | /* 毫秒 */ 112 | int microseconds = static_cast(microSecondsSinceEpoch % Timestamp::kMicroSecondsPerSecond); 113 | if (seconds != t_lastSecond) 114 | { 115 | t_lastSecond = seconds; 116 | 117 | struct tm tm_time; 118 | if (g_logTimeZone.valid()) 119 | { 120 | tm_time = g_logTimeZone.toLocalTime(microSecondsSinceEpoch); 121 | } 122 | else 123 | { 124 | ::gmtime_r(&seconds, &tm_time); 125 | } 126 | 127 | std::cout << tm_time.tm_year + 1900 << " " << tm_time.tm_mon + 1 << " "<< tm_time.tm_mday << " "<< 128 | tm_time.tm_hour << " " << tm_time.tm_min << " " << tm_time.tm_sec << std::endl; 129 | 130 | int len = snprintf(t_time, sizeof(t_time), "%4d%02d%02d %02d:%02d:%02d", 131 | tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday, 132 | tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec); 133 | std::cout << "t_time: " << t_time << " len: " << len << std::endl; 134 | assert(len == 17); (void)len; 135 | static_cast(len); 136 | } 137 | 138 | /* if (g_logTimeZone.valid()) */ 139 | /* { */ 140 | Fmt us(".%06dZ ", microseconds); 141 | assert(us.length() == 9); 142 | stream_ << T(t_time, 17) << T(us.data(), 9); 143 | /* } */ 144 | } 145 | 146 | void Logger::Impl::finish() 147 | { 148 | stream_ << " - " << basename_ << ':' << line_ << '\n'; 149 | } 150 | 151 | Logger::Logger(Logger::SourceFile file, int line) 152 | : impl_(INFO, 0, file, line) 153 | {} 154 | 155 | Logger::Logger(Logger::SourceFile file, int line, Logger::LogLevel level, const char* func) 156 | : impl_(level, 0, file, line) 157 | { 158 | impl_.stream_ << func << ' '; 159 | } 160 | 161 | Logger::Logger(Logger::SourceFile file, int line, Logger::LogLevel level) 162 | : impl_(level, 0, file, line) 163 | {} 164 | 165 | Logger::Logger(Logger::SourceFile file, int line, bool toAbort) 166 | : impl_(toAbort ? FATAL : ERROR, errno, file, line) 167 | {} 168 | 169 | Logger::~Logger() 170 | { 171 | impl_.finish(); 172 | const LogStream::Buffer& buf(stream().buffer()); 173 | g_output(buf.data(), buf.length()); 174 | } 175 | 176 | void Logger::setLogLevel(Logger::LogLevel level) 177 | { 178 | g_logLevel = level; 179 | } 180 | 181 | void Logger::setOutput(OutputFunc out) 182 | { 183 | g_output = out; 184 | } 185 | 186 | void Logger::setFlush(FlushFunc flush) 187 | { 188 | g_flush = flush; 189 | } 190 | 191 | void Logger::setTimezone(const TimeZone& tz) 192 | { 193 | g_logTimeZone = tz; 194 | } 195 | -------------------------------------------------------------------------------- /half_sync_half_reactor/ipaddress.cpp: -------------------------------------------------------------------------------- 1 | #include "ipaddress.h" 2 | #include "commont/stringutils.h" 3 | 4 | #define NDEBUG 1 5 | 6 | static const in6_addr kV4MappedPrefix = {{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7 | 0xFF, 0xFF, 0}}}; 8 | 9 | static const in6_addr kPrivateNetworkPrefix = {{{0xFD}}}; 10 | 11 | static bool IPIsHelper(const IPAddress& ip, const in6_addr& tomatch, int length); 12 | 13 | uint32_t IPAddress::v4AddressAsHostOrderInteger() const { 14 | if (family_ == AF_INET) { 15 | return ntohl(u_.ip4.s_addr); 16 | } 17 | return 0; 18 | } 19 | 20 | bool IPAddress::IsNil() const { 21 | return family_ == AF_UNSPEC; 22 | } 23 | 24 | size_t IPAddress::Size() const { 25 | switch (family_) { 26 | case AF_INET: 27 | return sizeof(in_addr); 28 | case AF_INET6: 29 | return sizeof(in6_addr); 30 | } 31 | return 0; 32 | } 33 | 34 | std::string IPAddress::ToString() const { 35 | if (family_ != AF_INET && family_ != AF_INET6) { 36 | return std::string(); 37 | } 38 | char buf[INET6_ADDRSTRLEN] = {0}; 39 | const void* src = &u_.ip4; 40 | if (family_ == AF_INET6) { 41 | src = &u_.ip6; 42 | } 43 | if (inet_ntop(family_, src, buf, sizeof(buf))) { 44 | return std::string(); 45 | } 46 | return std::string(buf); 47 | } 48 | 49 | std::string IPAddress::ToSensitiveString() const { 50 | #if !defined (NDEBUG) 51 | return ToString(); 52 | #else 53 | switch (family_) { 54 | case AF_INET: 55 | { 56 | std::string address = ToString(); 57 | size_t find_pos = address.rfind('.'); 58 | if (find_pos == std::string::npos) { 59 | return std::string(); 60 | } 61 | address.resize(find_pos); 62 | address += ".x"; 63 | return address; 64 | } 65 | case AF_INET6: 66 | { 67 | std::string result; 68 | result.resize(INET6_ADDRSTRLEN); 69 | in6_addr addr = ip6_address(); 70 | size_t len = sprintfn(&result[0], result.size(), "%x:%x:%x:x:x:x:x:x", 71 | (addr.s6_addr[0] >> 8) + addr.s6_addr[1], 72 | (addr.s6_addr[2] << 8) + addr.s6_addr[3], 73 | (addr.s6_addr[4] << 8) + addr.s6_addr[5]); 74 | result.resize(len); 75 | return result; 76 | } 77 | } 78 | return std::string(); 79 | #endif 80 | } 81 | 82 | bool IPAddress::operator==(const IPAddress& other) const { 83 | if (family_ != other.family_) { 84 | return false; 85 | } 86 | if (family_ == AF_INET) { 87 | return memcmp(&u_.ip4, &other.u_.ip4, sizeof(u_.ip4)) == 0; 88 | } 89 | if (family_ == AF_INET6) { 90 | return memcmp(&u_.ip6, &other.u_.ip6, sizeof(u_.ip6)) == 0; 91 | } 92 | return family_ == AF_UNSPEC; 93 | } 94 | 95 | bool IPFromString(const std::string& str, IPAddress* out) { 96 | if (!out) { 97 | return false; 98 | } 99 | in_addr addr; 100 | if (inet_pton(AF_INET, str.c_str(), &addr) == 0) { 101 | in6_addr addr6; 102 | if (inet_pton(AF_INET6, str.c_str(), &addr6) == 0) { 103 | *out = IPAddress(); 104 | return false; 105 | } 106 | *out = IPAddress(addr6); 107 | return true; 108 | } 109 | *out = IPAddress(addr); 110 | return true; 111 | } 112 | 113 | IPAddress IPAddress::AsIPV6Address() const { 114 | /*如果已经是ipv6的话,就没必要转了*/ 115 | if (AF_INET != family_) { 116 | return *this; 117 | } 118 | in6_addr addr6 = kV4MappedPrefix; 119 | ::memcpy(&addr6.s6_addr[12], &u_.ip4.s_addr, sizeof(u_.ip4.s_addr)); 120 | return IPAddress(addr6); 121 | } 122 | 123 | bool IPIsAny(const IPAddress& ip) { 124 | switch (ip.family()) { 125 | case AF_INET: 126 | { 127 | return ip == IPAddress(INADDR_ANY); 128 | } 129 | case AF_INET6: 130 | { 131 | return ip == IPAddress(in6addr_any) || ip == IPAddress(kV4MappedPrefix); 132 | } 133 | case AF_UNSPEC: 134 | { 135 | return false; 136 | } 137 | } 138 | return false; 139 | } 140 | 141 | static bool IPIsLoopbackV4(const IPAddress& ip) { 142 | uint32_t ip_in_host_order = ip.v4AddressAsHostOrderInteger(); 143 | return ((ip_in_host_order >> 24) == 127); 144 | } 145 | 146 | static bool IPIsLoopbackV6(const IPAddress& ip) { 147 | return ip == IPAddress(in6addr_loopback); 148 | } 149 | 150 | bool IPIsLoopback(const IPAddress& ip) { 151 | switch (ip.family()) { 152 | case AF_INET: 153 | { 154 | return IPIsLoopbackV4(ip); 155 | } 156 | case AF_INET6: 157 | { 158 | return IPIsLoopbackV6(ip); 159 | } 160 | } 161 | return false; 162 | } 163 | 164 | bool IPIsHelper(const IPAddress& ip, const in6_addr& tomatch, int length) { 165 | // Helper method for checking IP prefix matches (but only on whole byte 166 | // lengths). Length is in bits. 167 | in6_addr addr = ip.ip6_address(); 168 | /*memcmp 的length用的是字节,但是外部传进来是bits,所以要左移动三位*/ 169 | return ::memcmp(&addr, &tomatch, (length >> 3)) == 0; 170 | } 171 | 172 | /*局域网ip地址为 10.x.x.x 或 172.1.x.x 或 192.168.x.x*/ 173 | static bool IPIsPrivateNetWorkV4(const IPAddress& ip) { 174 | uint32_t ip_in_host_order = ip.v4AddressAsHostOrderInteger(); 175 | return ((ip_in_host_order >> 24 == 10) || 176 | (ip_in_host_order >> 20) == ((172 << 4) | 1 ) || 177 | (ip_in_host_order >> 16) == ((192 << 8) | 168)); 178 | } 179 | 180 | static bool IPIsPrivateNetWorkV6(const IPAddress& ip) { 181 | return IPIsHelper(ip, kPrivateNetworkPrefix, 8); 182 | } 183 | 184 | bool IPIsPrivateNetWork(const IPAddress& ip) { 185 | switch (ip.family()) { 186 | case AF_INET: 187 | { 188 | return IPIsPrivateNetWorkV4(ip); 189 | } 190 | case AF_INET6: 191 | { 192 | return IPIsPrivateNetWorkV6(ip); 193 | } 194 | } 195 | return false; 196 | } 197 | 198 | bool IPIsUnspec(const IPAddress& ip) { 199 | return ip.family() == AF_UNSPEC; 200 | } 201 | -------------------------------------------------------------------------------- /half_sync_half_reactor/logging/timezone.cpp: -------------------------------------------------------------------------------- 1 | #include "timezone.h" 2 | #include "../commont/constructormagic.h" 3 | #include "date.h" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace base 13 | { 14 | namespace detail 15 | { 16 | 17 | struct Transition 18 | { 19 | time_t gmttime; 20 | time_t localtime; 21 | int localtime_idx; 22 | 23 | Transition(time_t t, time_t l, int local_idx) 24 | : gmttime(t), localtime(l), localtime_idx(local_idx) 25 | {} 26 | }; 27 | 28 | struct Comp 29 | { 30 | bool compare_gmt; 31 | 32 | explicit Comp(bool gmt) 33 | : compare_gmt(gmt) 34 | {} 35 | 36 | bool operator()(const Transition& lhs, const Transition& rhs) const 37 | { 38 | if (compare_gmt) 39 | return lhs.gmttime < rhs.gmttime; 40 | else 41 | return lhs.localtime < rhs.localtime; 42 | } 43 | 44 | bool equal(const Transition& lhs, const Transition& rhs) const 45 | { 46 | if (compare_gmt) 47 | return lhs.gmttime == rhs.gmttime; 48 | else 49 | return lhs.localtime == rhs.localtime; 50 | } 51 | }; 52 | 53 | struct Localtime 54 | { 55 | time_t gmt_offset; 56 | bool is_dst; 57 | int arrb_idx; 58 | 59 | Localtime(time_t offset, bool dst, int arrb) 60 | : gmt_offset(offset), is_dst(dst), arrb_idx(arrb) 61 | {} 62 | }; 63 | 64 | inline void FillHMS(unsigned seconds, struct tm* utc) 65 | { 66 | utc->tm_sec = seconds % 60; 67 | unsigned minutes = seconds / 60; 68 | utc->tm_min = minutes % 60; 69 | utc->tm_hour = minutes / 60; 70 | } 71 | 72 | const int kSecondsPerDay = 24 * 60 * 60; 73 | 74 | } 75 | } 76 | 77 | 78 | using namespace base; 79 | struct TimeZone::Data 80 | { 81 | std::vector transitions; 82 | std::vector localtimes; 83 | std::vector names; 84 | std::string abbreviation; 85 | }; 86 | 87 | 88 | namespace base 89 | { 90 | namespace detail 91 | { 92 | 93 | class File 94 | { 95 | public: 96 | explicit File(const char* file) 97 | : fp_(::fopen(file, "rb")) 98 | {} 99 | 100 | ~File() 101 | { 102 | if (fp_) 103 | { 104 | ::fclose(fp_); 105 | } 106 | } 107 | 108 | bool valid() const { return fp_; } 109 | 110 | std::string readBytes(int n) 111 | { 112 | char buf[n]; 113 | ssize_t nr = ::fread(buf, 1, n, fp_); 114 | if (nr != n) 115 | throw std::logic_error("no enough data"); 116 | return std::string(buf, n); 117 | } 118 | 119 | int32_t readInt32() 120 | { 121 | int32_t x = 0; 122 | ssize_t nr = ::fread(&x, 1, sizeof(int32_t), fp_); 123 | if (nr != sizeof(int32_t)) 124 | throw std::logic_error("bad int32_t data"); 125 | return be32toh(x); 126 | } 127 | 128 | uint8_t readUInt8() 129 | { 130 | uint8_t x = 0; 131 | ssize_t nr = ::fread(&x, 1, sizeof(uint8_t), fp_); 132 | if (nr != sizeof(uint8_t)) 133 | throw std::logic_error("bad uint8_t data"); 134 | return x; 135 | } 136 | 137 | private: 138 | FILE* fp_; 139 | 140 | BASE_DISALLOW_IMPLICIT_CONSTRUCTORS(File); 141 | }; 142 | 143 | using namespace base; 144 | 145 | bool readTimeZoneFile(const char* zonefile, struct TimeZone::Data* data) 146 | { 147 | std::cout << __func__ << std::endl; 148 | 149 | File f(zonefile); 150 | if (f.valid()) 151 | { 152 | try 153 | { 154 | std::string head = f.readBytes(4); 155 | if (head != "TZif") 156 | throw std::logic_error("bad head"); 157 | std::string version = f.readBytes(1); 158 | f.readBytes(15); 159 | 160 | int32_t isgmtcnt = f.readInt32(); 161 | int32_t isstdcnt = f.readInt32(); 162 | int32_t leapcnt = f.readInt32(); 163 | int32_t timecnt = f.readInt32(); 164 | int32_t typecnt = f.readInt32(); 165 | int32_t charcnt = f.readInt32(); 166 | 167 | std::vector trans; 168 | std::vector localtimes; 169 | trans.reserve(timecnt); 170 | for (int i = 0; i < timecnt; ++i) 171 | { 172 | trans.push_back(f.readInt32()); 173 | } 174 | 175 | for (int i = 0; i < timecnt; ++i) 176 | { 177 | uint8_t local = f.readUInt8(); 178 | localtimes.push_back(local); 179 | } 180 | 181 | for (int i = 0; i < typecnt; ++i) 182 | { 183 | int32_t gmtoff = f.readInt32(); 184 | uint8_t isdst = f.readUInt8(); 185 | uint8_t abbrind = f.readUInt8(); 186 | 187 | data->localtimes.push_back(detail::Localtime(gmtoff, isdst, abbrind)); 188 | } 189 | 190 | for (int i = 0; i < timecnt; ++i) 191 | { 192 | int local_idx = localtimes[i]; 193 | time_t localtime = trans[i] + data->localtimes[local_idx].gmt_offset; 194 | data->transitions.push_back(Transition(trans[i], localtime, local_idx)); 195 | } 196 | 197 | data->abbreviation = f.readBytes(charcnt); 198 | 199 | // leapcnt 200 | for (int i = 0; i < leapcnt; ++i) 201 | { 202 | } 203 | 204 | static_cast(isstdcnt); 205 | static_cast(isgmtcnt); 206 | static_cast(version); 207 | } 208 | catch (std::logic_error& e) 209 | { 210 | fprintf(stderr, "%s\n", e.what()); 211 | } 212 | } 213 | return true; 214 | } 215 | 216 | const Localtime* findLocalTime(const TimeZone::Data& data, Transition sentry, Comp comp) 217 | { 218 | const Localtime* local = nullptr; 219 | 220 | if (data.transitions.empty() || comp(sentry, data.transitions.front())) 221 | { 222 | local = &data.localtimes.front(); 223 | } 224 | else 225 | { 226 | auto trans_i = std::lower_bound(data.transitions.begin(), 227 | data.transitions.end(), sentry, comp); 228 | 229 | if (trans_i != data.transitions.end()) 230 | { 231 | if (!comp.equal(sentry, *trans_i)) 232 | { 233 | assert(trans_i != data.transitions.begin()); 234 | --trans_i; 235 | } 236 | local = &data.localtimes[trans_i->localtime_idx]; 237 | } 238 | else 239 | { 240 | local = &data.localtimes[data.transitions.back().localtime_idx]; 241 | } 242 | } 243 | return local; 244 | } 245 | 246 | } 247 | } 248 | 249 | TimeZone::TimeZone(const char* zonefile) 250 | : data_(new TimeZone::Data) 251 | { 252 | if (!detail::readTimeZoneFile(zonefile, data_.get())) 253 | { 254 | data_.reset(); 255 | } 256 | } 257 | 258 | TimeZone::TimeZone(int eastOfUtc, const char* name) 259 | : data_(new TimeZone::Data) 260 | { 261 | data_->localtimes.push_back(detail::Localtime(eastOfUtc, false, 0)); 262 | data_->abbreviation = name; 263 | } 264 | 265 | struct tm TimeZone::toLocalTime(time_t seconds) const 266 | { 267 | std::cout << __func__ << std::endl; 268 | 269 | struct tm local_time; 270 | bzero(&local_time, sizeof(local_time)); 271 | assert(data_ != nullptr); 272 | const Data& data(*data_); 273 | 274 | detail::Transition sentry(seconds, 0, 0); 275 | const detail::Localtime* local = detail::findLocalTime(data, sentry, detail::Comp(true)); 276 | 277 | if (local) 278 | { 279 | time_t local_seconds = seconds + local->gmt_offset; 280 | ::gmtime_r(&local_seconds, &local_time); 281 | local_time.tm_isdst = local->is_dst; 282 | local_time.tm_gmtoff = local->gmt_offset; 283 | local_time.tm_zone = &data.abbreviation[local->arrb_idx]; 284 | } 285 | 286 | local_time = *(::localtime(nullptr)); 287 | return local_time; 288 | } 289 | 290 | time_t TimeZone::fromLocalTime(const struct tm& local_tm) const 291 | { 292 | assert(data_ != nullptr); 293 | const Data& data(*data_); 294 | 295 | struct tm tmp = local_tm; 296 | time_t seconds = ::timegm(&tmp); 297 | detail::Transition sentry(0, seconds, 0); 298 | const detail::Localtime* local = detail::findLocalTime(data, sentry, detail::Comp(false)); 299 | 300 | if (local_tm.tm_isdst) 301 | { 302 | struct tm try_tm = toLocalTime(seconds - local->gmt_offset); 303 | if (!try_tm.tm_isdst 304 | && try_tm.tm_hour == local_tm.tm_hour 305 | && try_tm.tm_min == local_tm.tm_min) 306 | { 307 | seconds -= 3600; 308 | } 309 | } 310 | return seconds - local->gmt_offset; 311 | } 312 | 313 | struct tm TimeZone::toUtcTime(time_t secondsSinceEpoch, bool yday) 314 | { 315 | struct tm utc; 316 | bzero(&utc, sizeof(utc)); 317 | utc.tm_zone = "GMT"; 318 | 319 | int seconds = static_cast(secondsSinceEpoch % detail::kSecondsPerDay); 320 | int days = static_cast(secondsSinceEpoch / detail::kSecondsPerDay); 321 | if (seconds < 0) 322 | { 323 | seconds += detail::kSecondsPerDay; 324 | --days; 325 | } 326 | detail::FillHMS(seconds, &utc); 327 | 328 | /* Date */ 329 | Date date(days + Date::kJulianDayOf1970_01_01); 330 | Date::YearMonthDay ymd = date.yearMonthDay(); 331 | utc.tm_year = ymd.year - 1900; 332 | utc.tm_mon = ymd.month - 1; 333 | utc.tm_mday = ymd.day; 334 | utc.tm_wday = date.weekDay(); 335 | 336 | if (yday) 337 | { 338 | Date start_of_year(ymd.year, 1, 1); 339 | utc.tm_yday = date.julianDayNumber() - start_of_year.julianDayNumber(); 340 | } 341 | 342 | return utc; 343 | } 344 | 345 | time_t TimeZone::fromUtcTime(const struct tm& utc) 346 | { 347 | return fromUtcTime(utc.tm_year + 1970, utc.tm_mon + 1, utc.tm_mday, 348 | utc.tm_hour, utc.tm_min, utc.tm_sec); 349 | } 350 | 351 | time_t TimeZone::fromUtcTime(int year, int month, int day, 352 | int hour, int minute, int seconds) 353 | { 354 | Date date(year, month, day); 355 | int seconds_in_day = hour * 3600 + minute * 60 + seconds; 356 | time_t days = date.julianDayNumber() - Date::kJulianDayOf1970_01_01; 357 | return days * detail::kSecondsPerDay + seconds_in_day; 358 | } 359 | 360 | -------------------------------------------------------------------------------- /half_sync_half_reactor/http_conn.cpp: -------------------------------------------------------------------------------- 1 | #include "http_conn.h" 2 | #include "commont/commont.h" 3 | #include 4 | #include "commont/stringutils.h" 5 | 6 | const char* doc_root = "/home/parallels/Desktop"; 7 | 8 | const char* error_400_title = "Bad Request"; 9 | const char* error_400_form = "Your request has bad syntax or is inherently impossible to satisfy.\n"; 10 | 11 | const char* error_500_title = "Internal Error"; 12 | const char* error_500_form = "There was an unusual problem serving the requested file.\n"; 13 | 14 | const char* error_404_title = "Not Found"; 15 | const char* error_404_form = "The requested file was not found on this server.\n"; 16 | 17 | const char* error_403_title = "Forbidden"; 18 | const char* error_403_form = "You do not have permission to get file from this server.\n"; 19 | 20 | const char* ok_200_title = "OK"; 21 | 22 | int HTTPConn::epoll_fd_ = -1; 23 | int HTTPConn::user_count_ = 0; 24 | 25 | HTTPConn::HTTPConn() {} 26 | HTTPConn::~HTTPConn() {} 27 | 28 | void HTTPConn::Init(int sock_fd, const SocketAddress& addr) 29 | { 30 | sock_fd_ = sock_fd; 31 | addr_ = addr; 32 | /*如下两行是为了避免 TIME_WAIT 状态,仅用于调试,实际使用时应该去掉*/ 33 | int reuse = 1; 34 | setsockopt(sock_fd_, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); 35 | 36 | base::AddFd(epoll_fd_, sock_fd_, true); 37 | user_count_++; 38 | Init(); 39 | } 40 | 41 | void HTTPConn::Init() { 42 | read_idx_ = 0; 43 | checked_idx_ = 0; 44 | start_line_ = 0; 45 | write_idx_ = 0; 46 | check_state_ = CHECK_STATE::REQUESTING; 47 | method_ = GET; 48 | url_ = 0; 49 | version_ = 0; 50 | host_ = ""; 51 | content_length_ = 0; 52 | keeplive_ = false; 53 | file_address_ = nullptr; 54 | 55 | memset(read_buf_, '\0', READ_BUFFER_SIZE); 56 | memset(write_buf_, '\0', WRITE_BUFFER_SIZE); 57 | memset(real_file_, '\0', FILENAME_LEN); 58 | } 59 | 60 | /*循环读取客户数据,直到无数据可读或者对方关闭连接*/ 61 | bool HTTPConn::Read() { 62 | if (read_idx_ >= READ_BUFFER_SIZE) { 63 | return false; 64 | } 65 | 66 | while (true) { 67 | int bytes_read = recv(sock_fd_, read_buf_ + read_idx_, 68 | READ_BUFFER_SIZE - read_idx_, 0); 69 | if (bytes_read == 0) // 没有可读数据了 70 | { 71 | return false; 72 | } 73 | else if (bytes_read == -1) 74 | { 75 | if (errno == EAGAIN || errno == EWOULDBLOCK) /*数据读完了或操作将阻塞(可能跟没有数据可读一样)*/ 76 | { 77 | break; 78 | } 79 | return false; 80 | } 81 | 82 | read_idx_ += bytes_read; 83 | } 84 | return true; 85 | } 86 | 87 | HTTPConn::LINE_STATUS HTTPConn::ParseLine() { 88 | for (; checked_idx_ < read_idx_; ++checked_idx_) { 89 | 90 | char temp = read_buf_[checked_idx_]; 91 | 92 | if (temp == '\r') { 93 | if ((checked_idx_ + 1) == read_idx_) { 94 | return LINE_OPEN; 95 | } 96 | else if (read_buf_[checked_idx_ + 1] == '\n') { 97 | read_buf_[checked_idx_++] = '\0'; 98 | read_buf_[checked_idx_++] = '\0'; 99 | return LINE_OK; 100 | } 101 | return LINE_BAD; 102 | } 103 | else if (temp == '\n') { 104 | if (checked_idx_ > 1 && read_buf_[checked_idx_ - 1] == '\r') { 105 | read_buf_[checked_idx_-1] = '\0';/*替换\r*/ 106 | read_buf_[checked_idx_++] = '\0'; 107 | return LINE_OK; 108 | } 109 | return LINE_BAD; 110 | } 111 | } 112 | return LINE_OPEN; 113 | } 114 | 115 | /*eg: "GET http://www.baidu.com/index.html HTTP/1.1"*/ 116 | HTTPConn::HTTP_CODE HTTPConn::ParseRequestLine(char* text) { 117 | std::cout << __func__ << std::endl; 118 | /*获取请求行*/ 119 | url_ = strpbrk(text, " "); 120 | if (!url_) { 121 | return BAD_REQUEST; 122 | } 123 | *url_++ = '\0'; // 替换 "\t" 字符 124 | char* method = text; 125 | /*目前仅支持GET*/ 126 | if (strcasecmp(method, "GET") == 0) { 127 | method_ = METHOD::GET; 128 | } 129 | else { 130 | return BAD_REQUEST; 131 | } 132 | 133 | url_ += strspn(url_, " "); // 跳过url_前多少个字符为空格"\t" 134 | version_ = strpbrk(url_, " ");// 查找url_ 中 "\t" 位置开始的字符串,得到HTTP/1.0 135 | if (!version_) { 136 | return BAD_REQUEST; 137 | } 138 | *version_++ = '\0'; 139 | if (strcasecmp(version_, "HTTP/1.1") != 0) { 140 | return BAD_REQUEST; 141 | } 142 | // strncasecmp 函数比较前 url_ 前7个字符,是否与 http:// 相同 143 | if (strncasecmp(url_, "http://", 7) == 0) { 144 | url_ += 7; 145 | // strchr 返回第一个指向字符 / 的位置字符串, 就是文件名, index.html 146 | url_ = strchr(url_, '/'); 147 | } 148 | if (!url_ || url_[0] != '/') { 149 | return BAD_REQUEST; 150 | } 151 | /*更改 check_state_,去解析请求头*/ 152 | check_state_ = CHECK_STATE::HEADER; 153 | return NO_REQUEST; 154 | } 155 | 156 | /*eg: 157 | "User-Agent:Wget/1.12(linux-gnu) 158 | Host:www.baidu.com 159 | Connection:close" 160 | */ 161 | HTTPConn::HTTP_CODE HTTPConn::ParseHeaders(char* text) { 162 | std::cout << __func__ << std::endl; 163 | /*遇到空行,表示头部字段解析完毕*/ 164 | if (text[0] == '\0') { 165 | if (content_length_ != 0) { 166 | /*如果HTTP请求有消息体, 则还需要读取 content_length 字节的消息体, 状态机转移到CHECK_STATE_CONTENT状态*/ 167 | check_state_ = CHECK_STATE::CONNENT; 168 | return NO_REQUEST; 169 | } 170 | return GET_REQUEST; 171 | } 172 | else if ( strncasecmp(text, "Connection:", 11) == 0) { 173 | text += 11; 174 | text += strspn(text, " "); 175 | if (strcasecmp(text, "keep-alive") == 0) { 176 | keeplive_ = true; 177 | } 178 | } 179 | else if (strncasecmp(text, "Content-Length:", 15) == 0) { 180 | text += 15; 181 | text += strspn(text, " "); 182 | content_length_ = atoi(text); 183 | } 184 | else if (strncasecmp(text, "Host:", 5) == 0) { 185 | text += 5; 186 | text += strspn(text, " "); 187 | host_ = text; 188 | } 189 | else { 190 | std::cout << "oop! unknow headers" << text << std::endl; 191 | } 192 | return NO_REQUEST; 193 | } 194 | 195 | /*我们没有真正解析HTTP请求的消息体, 只是判断它是否被完整地读入了*/ 196 | HTTPConn::HTTP_CODE HTTPConn::ParseContent(char* text) { 197 | /*recv 方法接受到的字符串是否大于 内容长度 + 前面已解析的字节长度*/ 198 | if (read_idx_ >= (content_length_ + checked_idx_)) { 199 | text[content_length_] = '\0'; 200 | return GET_REQUEST; 201 | } 202 | return NO_REQUEST; 203 | } 204 | 205 | /*当得到一个完整的,正确的HTTP请求时,我们就分析目标文件的属性。如果目标文件存在、对所有用户可读, 206 | *且不是目录,则使用 mmap 将其映射到内存地址 file_address_ 处,并告诉调用者获取文件成功*/ 207 | HTTPConn::HTTP_CODE HTTPConn::DoRequest() 208 | { 209 | std::cout << __func__ << std::endl; 210 | strcpy(real_file_, doc_root); 211 | int len = strlen(real_file_); 212 | strncpy(real_file_ + len, url_, FILENAME_LEN-len-1); 213 | /*获取不到文件信息*/ 214 | if (stat(real_file_, &file_stat_) < 0) 215 | { 216 | return NO_REQUEST; 217 | } 218 | if (!(file_stat_.st_mode & S_IROTH)) 219 | { // 是否有读取权限 220 | return FORBIDDEN_REQUEST; 221 | } 222 | if (S_ISDIR(file_stat_.st_mode)) 223 | { 224 | return BAD_REQUEST; 225 | } 226 | int fd = open(real_file_, O_RDONLY); // 只读 227 | file_address_ = (char*)mmap(0, file_stat_.st_size, PROT_READ, MAP_PRIVATE, fd, 0); 228 | close(fd); 229 | return FILE_REQUEST; 230 | } 231 | 232 | HTTPConn::HTTP_CODE HTTPConn::ProcessRead() { 233 | LINE_STATUS line_status = LINE_OK; 234 | HTTP_CODE ret = HTTP_CODE::NO_REQUEST; 235 | 236 | while ( (check_state_ == CHECK_STATE::CONNENT && line_status == LINE_OK) 237 | || (line_status = ParseLine()) == LINE_OK ) { 238 | 239 | /*一行一行的解析 HTTP 协议*/ 240 | char* text = GetLine(); 241 | start_line_ = checked_idx_; 242 | 243 | std::cout << "got 1 http line " << text << std::endl; 244 | std::cout << "current check_state:" << check_state_ << std::endl; 245 | switch (check_state_) { 246 | case CHECK_STATE::REQUESTING: 247 | { 248 | ret = ParseRequestLine(text); 249 | if (ret == HTTP_CODE::BAD_REQUEST) { 250 | return HTTP_CODE::BAD_REQUEST; 251 | } 252 | break; /*解析了请求行,继续获取下一行内容进行解析*/ 253 | } 254 | case CHECK_STATE::HEADER: 255 | { 256 | ret = ParseHeaders(text); 257 | if (ret == HTTPConn::BAD_REQUEST) { 258 | return HTTP_CODE::BAD_REQUEST; 259 | } 260 | else if (ret == GET_REQUEST) { 261 | return DoRequest(); /*解析最后一步了,直接返回*/ 262 | } 263 | /*ret 状态没有改变,不断解析头部信息*/ 264 | break; 265 | } 266 | case CHECK_STATE::CONNENT: 267 | { 268 | ret = ParseContent(text); 269 | if (ret == GET_REQUEST) { 270 | return DoRequest(); 271 | } 272 | line_status = LINE_OPEN; 273 | break; 274 | } 275 | default: 276 | return INTERNAL_ERROR; 277 | } 278 | } 279 | 280 | return NO_REQUEST; 281 | } 282 | 283 | void HTTPConn::Unmap() 284 | { 285 | if (file_address_) { 286 | munmap(file_address_, file_stat_.st_size); 287 | file_address_ = nullptr; 288 | } 289 | } 290 | 291 | bool HTTPConn::AddStatusLine(int status, const char* title) 292 | { 293 | return AddResponse("%s %d %s\r\n", "HTTP/1.1", status, title); 294 | } 295 | 296 | bool HTTPConn::AddHeaders(int content_length) 297 | { 298 | bool ret = AddContentLength(content_length); 299 | if (!ret) { return false; } 300 | 301 | ret = AddKeepLive(); 302 | if (!ret) { return false; } 303 | 304 | ret = AddBlankLine(); 305 | return ret; 306 | } 307 | 308 | bool HTTPConn::AddContent(const char* content) 309 | { 310 | return AddResponse("%s", content); 311 | } 312 | 313 | bool HTTPConn::AddContentLength(int content_length) 314 | { 315 | return AddResponse("Content-Length:%d\r\n", content_length); 316 | } 317 | 318 | bool HTTPConn::AddKeepLive() 319 | { 320 | return AddResponse("Connection:%s\r\n", (keeplive_ == true) ? "keep-alive":"close"); 321 | } 322 | 323 | bool HTTPConn::AddBlankLine() 324 | { 325 | return AddResponse("%s", "\r\n"); 326 | } 327 | 328 | bool HTTPConn::AddResponse(const char* format, ...) 329 | { 330 | if (write_idx_ >= WRITE_BUFFER_SIZE) { 331 | return false; 332 | } 333 | 334 | // int len = sprintfn(write_buf_ + write_idx_, WRITE_BUFFER_SIZE - 1 - write_idx_, format); 335 | va_list args; 336 | va_start(args, format); 337 | size_t len = vsprintfn(write_buf_ + write_idx_, WRITE_BUFFER_SIZE - 1 - write_idx_, format, args); 338 | va_end(args); 339 | 340 | if (len >= WRITE_BUFFER_SIZE - 1 - write_idx_) { 341 | return false; 342 | } 343 | write_idx_ += len; 344 | return true; 345 | } 346 | 347 | bool HTTPConn::Write() 348 | { 349 | int byte_have_send = 0; /*已经发送的字节数*/ 350 | int byte_to_send = write_idx_; /*需要发送的字节数*/ 351 | 352 | /*没有内容发送,返回*/ 353 | if (byte_to_send == 0) { 354 | base::ModifyFd(epoll_fd_, sock_fd_, EPOLLIN); 355 | Init(); 356 | return true; 357 | } 358 | 359 | while(1) { 360 | // 将 iv_ 中两个流合成一个流,写到 sock_fd_ 中 361 | int temp = writev(sock_fd_, iv_, iv_count_); 362 | if (temp <= -1) { 363 | /*如果TCP写缓冲没有空间, 则等待下一轮 EPOLLOUT 事件。虽然在此期间, 服务器无法立即接收到同一客户的下一个请求, 但这可以保证连接的完整性*/ 364 | if (errno == EAGAIN) { 365 | base::ModifyFd(epoll_fd_, sock_fd_, EPOLLOUT); 366 | return true; 367 | } 368 | 369 | Unmap(); 370 | return false; 371 | } 372 | 373 | printf("%s server write bytes to sock_fd:%d\n %s\n", __func__, sock_fd_, write_buf_); 374 | 375 | // byte_to_send -= temp; 376 | byte_have_send += temp; 377 | 378 | if (byte_to_send <= byte_have_send) { 379 | /*发送HTTP响应成功, 根据HTTP请求中的 Connection 字段决定是否立即关闭连接*/ 380 | Unmap(); // 关闭内存映射 381 | if (keeplive_) 382 | { 383 | Init(); 384 | base::ModifyFd(epoll_fd_, sock_fd_, EPOLLIN); 385 | return true; 386 | } 387 | else 388 | { 389 | base::ModifyFd(epoll_fd_, sock_fd_, EPOLLIN); 390 | return false; 391 | } 392 | } 393 | } 394 | } 395 | 396 | /*根据服务器处理HTTP请求的结果,决定返回给客户端的内容*/ 397 | bool HTTPConn::ProcessWrite(HTTPConn::HTTP_CODE code) 398 | { 399 | switch (code) { 400 | case HTTP_CODE::BAD_REQUEST : 401 | { 402 | AddStatusLine(400, error_400_title); 403 | AddHeaders(strlen(error_400_form)); 404 | if (!AddContent(error_400_form)) { 405 | return false; 406 | } 407 | break; 408 | } 409 | case HTTP_CODE::INTERNAL_ERROR: 410 | { 411 | AddStatusLine(500, error_500_title); 412 | AddHeaders(strlen(error_500_form)); 413 | if (!AddContent(error_500_form)) { 414 | return false; 415 | } 416 | break; 417 | } 418 | case HTTP_CODE::NO_REQUEST : 419 | { 420 | AddStatusLine(404, error_404_title); 421 | AddHeaders(strlen(error_404_form)); 422 | if (!AddContent(error_404_form)) { 423 | return false; 424 | } 425 | break; 426 | } 427 | case HTTP_CODE::FORBIDDEN_REQUEST : 428 | { 429 | AddStatusLine(403, error_403_title); 430 | AddHeaders(strlen(error_403_form)); 431 | if (!AddContent(error_403_form)) { 432 | return false; 433 | } 434 | break; 435 | } 436 | case HTTP_CODE::FILE_REQUEST : 437 | { 438 | AddStatusLine(200, ok_200_title); 439 | if (file_stat_.st_size != 0) { 440 | AddHeaders(file_stat_.st_size); 441 | 442 | /*合并 write_buf_ 和 file_address 两个流*/ 443 | iv_[0].iov_base = write_buf_; 444 | iv_[0].iov_len = write_idx_; 445 | iv_[1].iov_base = file_address_; 446 | iv_[1].iov_len = file_stat_.st_size; 447 | iv_count_ = 2; 448 | return true; 449 | } 450 | else { 451 | const char* ok_string = ""; 452 | AddHeaders(strlen(ok_string)); 453 | if (!AddContent(ok_string)) { 454 | return false; 455 | } 456 | } 457 | } 458 | default: 459 | { 460 | return false; 461 | } 462 | } 463 | /*没有文件内容需要写入*/ 464 | iv_[0].iov_base = write_buf_; 465 | iv_[0].iov_len = write_idx_; 466 | iv_count_ = 1; 467 | return true; 468 | } 469 | 470 | /*当线程池收到事件启动Set的时候,调用 Process*/ 471 | void HTTPConn::Process() 472 | { 473 | HTTP_CODE read_ret = ProcessRead(); 474 | std::cout << "get read_ret: " << read_ret << std::endl; 475 | if (read_ret == NO_REQUEST) { 476 | base::ModifyFd(epoll_fd_, sock_fd_, EPOLLIN); 477 | return; 478 | } 479 | /*通过 ProcessRead 解析完HTTP协议信息后,通过 ProcessWrite 给客户 480 | * 发送返回信息*/ 481 | bool write_ret = ProcessWrite(read_ret); 482 | if (!write_ret) { 483 | CloseConn(); 484 | } 485 | base::ModifyFd(epoll_fd_, sock_fd_, EPOLLOUT); 486 | } 487 | 488 | void HTTPConn::CloseConn(bool real_close) 489 | { 490 | if (real_close && sock_fd_ != -1) 491 | { 492 | base::RemoveFd(epoll_fd_, sock_fd_); 493 | sock_fd_ = -1; 494 | user_count_ --; 495 | } 496 | } 497 | 498 | -------------------------------------------------------------------------------- /half_sync_half_reactor/commont/sigslot.h: -------------------------------------------------------------------------------- 1 | // sigslot.h: Signal/Slot classes 2 | // 3 | // Written by Sarah Thompson (sarah@telergy.com) 2002. 4 | // 5 | // License: Public domain. You are free to use this code however you like, with 6 | // the proviso that the author takes on no responsibility or liability for any 7 | // use. 8 | // 9 | // QUICK DOCUMENTATION 10 | // 11 | // (see also the full documentation at http://sigslot.sourceforge.net/) 12 | // 13 | // #define switches 14 | // SIGSLOT_PURE_ISO: 15 | // Define this to force ISO C++ compliance. This also disables all of 16 | // the thread safety support on platforms where it is available. 17 | // 18 | // SIGSLOT_USE_POSIX_THREADS: 19 | // Force use of Posix threads when using a C++ compiler other than gcc 20 | // on a platform that supports Posix threads. (When using gcc, this is 21 | // the default - use SIGSLOT_PURE_ISO to disable this if necessary) 22 | // 23 | // SIGSLOT_DEFAULT_MT_POLICY: 24 | // Where thread support is enabled, this defaults to 25 | // multi_threaded_global. Otherwise, the default is single_threaded. 26 | // #define this yourself to override the default. In pure ISO mode, 27 | // anything other than single_threaded will cause a compiler error. 28 | // 29 | // PLATFORM NOTES 30 | // 31 | // Win32: 32 | // On Win32, the WEBRTC_WIN symbol must be #defined. Most mainstream 33 | // compilers do this by default, but you may need to define it yourself 34 | // if your build environment is less standard. This causes the Win32 35 | // thread support to be compiled in and used automatically. 36 | // 37 | // Unix/Linux/BSD, etc.: 38 | // If you're using gcc, it is assumed that you have Posix threads 39 | // available, so they are used automatically. You can override this (as 40 | // under Windows) with the SIGSLOT_PURE_ISO switch. If you're using 41 | // something other than gcc but still want to use Posix threads, you 42 | // need to #define SIGSLOT_USE_POSIX_THREADS. 43 | // 44 | // ISO C++: 45 | // If none of the supported platforms are detected, or if 46 | // SIGSLOT_PURE_ISO is defined, all multithreading support is turned 47 | // off, along with any code that might cause a pure ISO C++ environment 48 | // to complain. Before you ask, gcc -ansi -pedantic won't compile this 49 | // library, but gcc -ansi is fine. Pedantic mode seems to throw a lot of 50 | // errors that aren't really there. If you feel like investigating this, 51 | // please contact the author. 52 | // 53 | // 54 | // THREADING MODES 55 | // 56 | // single_threaded: 57 | // Your program is assumed to be single threaded from the point of view 58 | // of signal/slot usage (i.e. all objects using signals and slots are 59 | // created and destroyed from a single thread). Behaviour if objects are 60 | // destroyed concurrently is undefined (i.e. you'll get the occasional 61 | // segmentation fault/memory exception). 62 | // 63 | // multi_threaded_global: 64 | // Your program is assumed to be multi threaded. Objects using signals 65 | // and slots can be safely created and destroyed from any thread, even 66 | // when connections exist. In multi_threaded_global mode, this is 67 | // achieved by a single global mutex (actually a critical section on 68 | // Windows because they are faster). This option uses less OS resources, 69 | // but results in more opportunities for contention, possibly resulting 70 | // in more context switches than are strictly necessary. 71 | // 72 | // multi_threaded_local: 73 | // Behaviour in this mode is essentially the same as 74 | // multi_threaded_global, except that each signal, and each object that 75 | // inherits has_slots, all have their own mutex/critical section. In 76 | // practice, this means that mutex collisions (and hence context 77 | // switches) only happen if they are absolutely essential. However, on 78 | // some platforms, creating a lot of mutexes can slow down the whole OS, 79 | // so use this option with care. 80 | // 81 | // USING THE LIBRARY 82 | // 83 | // See the full documentation at http://sigslot.sourceforge.net/ 84 | // 85 | // Libjingle specific: 86 | // 87 | // This file has been modified such that has_slots and signalx do not have to be 88 | // using the same threading requirements. E.g. it is possible to connect a 89 | // has_slots and signal0 or 90 | // has_slots and signal0. 91 | // If has_slots is single threaded the user must ensure that it is not trying 92 | // to connect or disconnect to signalx concurrently or data race may occur. 93 | // If signalx is single threaded the user must ensure that disconnect, connect 94 | // or signal is not happening concurrently or data race may occur. 95 | 96 | #ifndef RTC_BASE_SIGSLOT_H_ 97 | #define RTC_BASE_SIGSLOT_H_ 98 | 99 | #include 100 | #include 101 | #include 102 | #include 103 | 104 | // On our copy of sigslot.h, we set single threading as default. 105 | #define SIGSLOT_DEFAULT_MT_POLICY single_threaded 106 | 107 | #if defined(SIGSLOT_PURE_ISO) || \ 108 | (!defined(WEBRTC_WIN) && !defined(__GNUG__) && \ 109 | !defined(SIGSLOT_USE_POSIX_THREADS)) 110 | #define _SIGSLOT_SINGLE_THREADED 111 | #elif defined(WEBRTC_WIN) 112 | #define _SIGSLOT_HAS_WIN32_THREADS 113 | #if !defined(WIN32_LEAN_AND_MEAN) 114 | #define WIN32_LEAN_AND_MEAN 115 | #endif 116 | #include "rtc_base/win32.h" 117 | #elif defined(__GNUG__) || defined(SIGSLOT_USE_POSIX_THREADS) 118 | #define _SIGSLOT_HAS_POSIX_THREADS 119 | #include 120 | #else 121 | #define _SIGSLOT_SINGLE_THREADED 122 | #endif 123 | 124 | #ifndef SIGSLOT_DEFAULT_MT_POLICY 125 | #ifdef _SIGSLOT_SINGLE_THREADED 126 | #define SIGSLOT_DEFAULT_MT_POLICY single_threaded 127 | #else 128 | #define SIGSLOT_DEFAULT_MT_POLICY multi_threaded_local 129 | #endif 130 | #endif 131 | 132 | // TODO: change this namespace to rtc? 133 | namespace sigslot { 134 | 135 | class single_threaded { 136 | public: 137 | void lock() {} 138 | void unlock() {} 139 | }; 140 | 141 | #ifdef _SIGSLOT_HAS_WIN32_THREADS 142 | // The multi threading policies only get compiled in if they are enabled. 143 | class multi_threaded_global { 144 | public: 145 | multi_threaded_global() { 146 | static bool isinitialised = false; 147 | 148 | if (!isinitialised) { 149 | InitializeCriticalSection(get_critsec()); 150 | isinitialised = true; 151 | } 152 | } 153 | 154 | void lock() { EnterCriticalSection(get_critsec()); } 155 | 156 | void unlock() { LeaveCriticalSection(get_critsec()); } 157 | 158 | private: 159 | CRITICAL_SECTION* get_critsec() { 160 | static CRITICAL_SECTION g_critsec; 161 | return &g_critsec; 162 | } 163 | }; 164 | 165 | class multi_threaded_local { 166 | public: 167 | multi_threaded_local() { InitializeCriticalSection(&m_critsec); } 168 | 169 | multi_threaded_local(const multi_threaded_local&) { 170 | InitializeCriticalSection(&m_critsec); 171 | } 172 | 173 | ~multi_threaded_local() { DeleteCriticalSection(&m_critsec); } 174 | 175 | void lock() { EnterCriticalSection(&m_critsec); } 176 | 177 | void unlock() { LeaveCriticalSection(&m_critsec); } 178 | 179 | private: 180 | CRITICAL_SECTION m_critsec; 181 | }; 182 | #endif // _SIGSLOT_HAS_WIN32_THREADS 183 | 184 | #ifdef _SIGSLOT_HAS_POSIX_THREADS 185 | // The multi threading policies only get compiled in if they are enabled. 186 | class multi_threaded_global { 187 | public: 188 | void lock() { pthread_mutex_lock(get_mutex()); } 189 | void unlock() { pthread_mutex_unlock(get_mutex()); } 190 | 191 | private: 192 | static pthread_mutex_t* get_mutex(); 193 | }; 194 | 195 | class multi_threaded_local { 196 | public: 197 | multi_threaded_local() { pthread_mutex_init(&m_mutex, nullptr); } 198 | multi_threaded_local(const multi_threaded_local&) { 199 | pthread_mutex_init(&m_mutex, nullptr); 200 | } 201 | ~multi_threaded_local() { pthread_mutex_destroy(&m_mutex); } 202 | void lock() { pthread_mutex_lock(&m_mutex); } 203 | void unlock() { pthread_mutex_unlock(&m_mutex); } 204 | 205 | private: 206 | pthread_mutex_t m_mutex; 207 | }; 208 | #endif // _SIGSLOT_HAS_POSIX_THREADS 209 | 210 | template 211 | class lock_block { 212 | public: 213 | mt_policy* m_mutex; 214 | 215 | lock_block(mt_policy* mtx) : m_mutex(mtx) { m_mutex->lock(); } 216 | 217 | ~lock_block() { m_mutex->unlock(); } 218 | }; 219 | 220 | class _signal_base_interface; 221 | 222 | class has_slots_interface { 223 | private: 224 | typedef void (*signal_connect_t)(has_slots_interface* self, 225 | _signal_base_interface* sender); 226 | typedef void (*signal_disconnect_t)(has_slots_interface* self, 227 | _signal_base_interface* sender); 228 | typedef void (*disconnect_all_t)(has_slots_interface* self); 229 | 230 | const signal_connect_t m_signal_connect; 231 | const signal_disconnect_t m_signal_disconnect; 232 | const disconnect_all_t m_disconnect_all; 233 | 234 | protected: 235 | has_slots_interface(signal_connect_t conn, 236 | signal_disconnect_t disc, 237 | disconnect_all_t disc_all) 238 | : m_signal_connect(conn), 239 | m_signal_disconnect(disc), 240 | m_disconnect_all(disc_all) {} 241 | 242 | // Doesn't really need to be virtual, but is for backwards compatibility 243 | // (it was virtual in a previous version of sigslot). 244 | virtual ~has_slots_interface() {} 245 | 246 | public: 247 | void signal_connect(_signal_base_interface* sender) { 248 | m_signal_connect(this, sender); 249 | } 250 | 251 | void signal_disconnect(_signal_base_interface* sender) { 252 | m_signal_disconnect(this, sender); 253 | } 254 | 255 | void disconnect_all() { m_disconnect_all(this); } 256 | }; 257 | 258 | class _signal_base_interface { 259 | private: 260 | typedef void (*slot_disconnect_t)(_signal_base_interface* self, 261 | has_slots_interface* pslot); 262 | typedef void (*slot_duplicate_t)(_signal_base_interface* self, 263 | const has_slots_interface* poldslot, 264 | has_slots_interface* pnewslot); 265 | 266 | const slot_disconnect_t m_slot_disconnect; 267 | const slot_duplicate_t m_slot_duplicate; 268 | 269 | protected: 270 | _signal_base_interface(slot_disconnect_t disc, slot_duplicate_t dupl) 271 | : m_slot_disconnect(disc), m_slot_duplicate(dupl) {} 272 | 273 | ~_signal_base_interface() {} 274 | 275 | public: 276 | void slot_disconnect(has_slots_interface* pslot) { 277 | m_slot_disconnect(this, pslot); 278 | } 279 | 280 | void slot_duplicate(const has_slots_interface* poldslot, 281 | has_slots_interface* pnewslot) { 282 | m_slot_duplicate(this, poldslot, pnewslot); 283 | } 284 | }; 285 | 286 | class _opaque_connection { 287 | private: 288 | typedef void (*emit_t)(const _opaque_connection*); 289 | template 290 | union union_caster { 291 | FromT from; 292 | ToT to; 293 | }; 294 | 295 | emit_t pemit; 296 | has_slots_interface* pdest; 297 | // Pointers to member functions may be up to 16 bytes for virtual classes, 298 | // so make sure we have enough space to store it. 299 | unsigned char pmethod[16]; 300 | 301 | public: 302 | template 303 | _opaque_connection(DestT* pd, void (DestT::*pm)(Args...)) : pdest(pd) { 304 | typedef void (DestT::*pm_t)(Args...); 305 | static_assert(sizeof(pm_t) <= sizeof(pmethod), 306 | "Size of slot function pointer too large."); 307 | 308 | std::memcpy(pmethod, &pm, sizeof(pm_t)); 309 | 310 | typedef void (*em_t)(const _opaque_connection* self, Args...); 311 | union_caster caster2; 312 | caster2.from = &_opaque_connection::emitter; 313 | pemit = caster2.to; 314 | } 315 | 316 | has_slots_interface* getdest() const { return pdest; } 317 | 318 | _opaque_connection duplicate(has_slots_interface* newtarget) const { 319 | _opaque_connection res = *this; 320 | res.pdest = newtarget; 321 | return res; 322 | } 323 | 324 | // Just calls the stored "emitter" function pointer stored at construction 325 | // time. 326 | template 327 | void emit(Args... args) const { 328 | typedef void (*em_t)(const _opaque_connection*, Args...); 329 | union_caster caster; 330 | caster.from = pemit; 331 | (caster.to)(this, args...); 332 | } 333 | 334 | private: 335 | template 336 | static void emitter(const _opaque_connection* self, Args... args) { 337 | typedef void (DestT::*pm_t)(Args...); 338 | pm_t pm; 339 | std::memcpy(&pm, self->pmethod, sizeof(pm_t)); 340 | (static_cast(self->pdest)->*(pm))(args...); 341 | } 342 | }; 343 | 344 | template 345 | class _signal_base : public _signal_base_interface, public mt_policy { 346 | protected: 347 | typedef std::list<_opaque_connection> connections_list; 348 | 349 | _signal_base() 350 | : _signal_base_interface(&_signal_base::do_slot_disconnect, 351 | &_signal_base::do_slot_duplicate), 352 | m_current_iterator(m_connected_slots.end()) {} 353 | 354 | ~_signal_base() { disconnect_all(); } 355 | 356 | private: 357 | _signal_base& operator=(_signal_base const& that); 358 | 359 | public: 360 | _signal_base(const _signal_base& o) 361 | : _signal_base_interface(&_signal_base::do_slot_disconnect, 362 | &_signal_base::do_slot_duplicate), 363 | m_current_iterator(m_connected_slots.end()) { 364 | lock_block lock(this); 365 | for (const auto& connection : o.m_connected_slots) { 366 | connection.getdest()->signal_connect(this); 367 | m_connected_slots.push_back(connection); 368 | } 369 | } 370 | 371 | bool is_empty() { 372 | lock_block lock(this); 373 | return m_connected_slots.empty(); 374 | } 375 | 376 | void disconnect_all() { 377 | lock_block lock(this); 378 | 379 | while (!m_connected_slots.empty()) { 380 | has_slots_interface* pdest = m_connected_slots.front().getdest(); 381 | m_connected_slots.pop_front(); 382 | pdest->signal_disconnect(static_cast<_signal_base_interface*>(this)); 383 | } 384 | // If disconnect_all is called while the signal is firing, advance the 385 | // current slot iterator to the end to avoid an invalidated iterator from 386 | // being dereferenced. 387 | m_current_iterator = m_connected_slots.end(); 388 | } 389 | 390 | #if !defined(NDEBUG) 391 | bool connected(has_slots_interface* pclass) { 392 | lock_block lock(this); 393 | connections_list::const_iterator it = m_connected_slots.begin(); 394 | connections_list::const_iterator itEnd = m_connected_slots.end(); 395 | while (it != itEnd) { 396 | if (it->getdest() == pclass) 397 | return true; 398 | ++it; 399 | } 400 | return false; 401 | } 402 | #endif 403 | 404 | void disconnect(has_slots_interface* pclass) { 405 | lock_block lock(this); 406 | connections_list::iterator it = m_connected_slots.begin(); 407 | connections_list::iterator itEnd = m_connected_slots.end(); 408 | 409 | while (it != itEnd) { 410 | if (it->getdest() == pclass) { 411 | // If we're currently using this iterator because the signal is firing, 412 | // advance it to avoid it being invalidated. 413 | if (m_current_iterator == it) { 414 | m_current_iterator = m_connected_slots.erase(it); 415 | } else { 416 | m_connected_slots.erase(it); 417 | } 418 | pclass->signal_disconnect(static_cast<_signal_base_interface*>(this)); 419 | return; 420 | } 421 | ++it; 422 | } 423 | } 424 | 425 | private: 426 | static void do_slot_disconnect(_signal_base_interface* p, 427 | has_slots_interface* pslot) { 428 | _signal_base* const self = static_cast<_signal_base*>(p); 429 | lock_block lock(self); 430 | connections_list::iterator it = self->m_connected_slots.begin(); 431 | connections_list::iterator itEnd = self->m_connected_slots.end(); 432 | 433 | while (it != itEnd) { 434 | connections_list::iterator itNext = it; 435 | ++itNext; 436 | 437 | if (it->getdest() == pslot) { 438 | // If we're currently using this iterator because the signal is firing, 439 | // advance it to avoid it being invalidated. 440 | if (self->m_current_iterator == it) { 441 | self->m_current_iterator = self->m_connected_slots.erase(it); 442 | } else { 443 | self->m_connected_slots.erase(it); 444 | } 445 | } 446 | 447 | it = itNext; 448 | } 449 | } 450 | 451 | static void do_slot_duplicate(_signal_base_interface* p, 452 | const has_slots_interface* oldtarget, 453 | has_slots_interface* newtarget) { 454 | _signal_base* const self = static_cast<_signal_base*>(p); 455 | lock_block lock(self); 456 | connections_list::iterator it = self->m_connected_slots.begin(); 457 | connections_list::iterator itEnd = self->m_connected_slots.end(); 458 | 459 | while (it != itEnd) { 460 | if (it->getdest() == oldtarget) { 461 | self->m_connected_slots.push_back(it->duplicate(newtarget)); 462 | } 463 | 464 | ++it; 465 | } 466 | } 467 | 468 | protected: 469 | connections_list m_connected_slots; 470 | 471 | // Used to handle a slot being disconnected while a signal is 472 | // firing (iterating m_connected_slots). 473 | connections_list::iterator m_current_iterator; 474 | bool m_erase_current_iterator = false; 475 | }; 476 | 477 | template 478 | class has_slots : public has_slots_interface, public mt_policy { 479 | private: 480 | typedef std::set<_signal_base_interface*> sender_set; 481 | typedef sender_set::const_iterator const_iterator; 482 | 483 | public: 484 | has_slots() 485 | : has_slots_interface(&has_slots::do_signal_connect, 486 | &has_slots::do_signal_disconnect, 487 | &has_slots::do_disconnect_all) {} 488 | 489 | has_slots(has_slots const& o) 490 | : has_slots_interface(&has_slots::do_signal_connect, 491 | &has_slots::do_signal_disconnect, 492 | &has_slots::do_disconnect_all) { 493 | lock_block lock(this); 494 | for (auto* sender : o.m_senders) { 495 | sender->slot_duplicate(&o, this); 496 | m_senders.insert(sender); 497 | } 498 | } 499 | 500 | ~has_slots() { this->disconnect_all(); } 501 | 502 | private: 503 | has_slots& operator=(has_slots const&); 504 | 505 | static void do_signal_connect(has_slots_interface* p, 506 | _signal_base_interface* sender) { 507 | has_slots* const self = static_cast(p); 508 | lock_block lock(self); 509 | self->m_senders.insert(sender); 510 | } 511 | 512 | static void do_signal_disconnect(has_slots_interface* p, 513 | _signal_base_interface* sender) { 514 | has_slots* const self = static_cast(p); 515 | lock_block lock(self); 516 | self->m_senders.erase(sender); 517 | } 518 | 519 | static void do_disconnect_all(has_slots_interface* p) { 520 | has_slots* const self = static_cast(p); 521 | lock_block lock(self); 522 | while (!self->m_senders.empty()) { 523 | std::set<_signal_base_interface*> senders; 524 | senders.swap(self->m_senders); 525 | const_iterator it = senders.begin(); 526 | const_iterator itEnd = senders.end(); 527 | 528 | while (it != itEnd) { 529 | _signal_base_interface* s = *it; 530 | ++it; 531 | s->slot_disconnect(p); 532 | } 533 | } 534 | } 535 | 536 | private: 537 | sender_set m_senders; 538 | }; 539 | 540 | template 541 | class signal_with_thread_policy : public _signal_base { 542 | private: 543 | typedef _signal_base base; 544 | 545 | protected: 546 | typedef typename base::connections_list connections_list; 547 | 548 | public: 549 | signal_with_thread_policy() {} 550 | 551 | template 552 | void connect(desttype* pclass, void (desttype::*pmemfun)(Args...)) { 553 | lock_block lock(this); 554 | this->m_connected_slots.push_back(_opaque_connection(pclass, pmemfun)); 555 | pclass->signal_connect(static_cast<_signal_base_interface*>(this)); 556 | } 557 | 558 | void emit(Args... args) { 559 | lock_block lock(this); 560 | this->m_current_iterator = this->m_connected_slots.begin(); 561 | while (this->m_current_iterator != this->m_connected_slots.end()) { 562 | _opaque_connection const& conn = *this->m_current_iterator; 563 | ++(this->m_current_iterator); 564 | conn.emit(args...); 565 | } 566 | } 567 | 568 | void operator()(Args... args) { emit(args...); } 569 | }; 570 | 571 | // Alias with default thread policy. Needed because both default arguments 572 | // and variadic template arguments must go at the end of the list, so we 573 | // can't have both at once. 574 | template 575 | using signal = signal_with_thread_policy; 576 | 577 | // The previous verion of sigslot didn't use variadic templates, so you would 578 | // need to write "sigslot::signal2", for example. 579 | // Now you can just write "sigslot::signal", but these aliases 580 | // exist for backwards compatibility. 581 | template 582 | using signal0 = signal_with_thread_policy; 583 | 584 | template 585 | using signal1 = signal_with_thread_policy; 586 | 587 | template 590 | using signal2 = signal_with_thread_policy; 591 | 592 | template 596 | using signal3 = signal_with_thread_policy; 597 | 598 | template 603 | using signal4 = signal_with_thread_policy; 604 | 605 | template 611 | using signal5 = signal_with_thread_policy; 612 | 613 | template 620 | using signal6 = signal_with_thread_policy; 621 | 622 | template 630 | using signal7 = 631 | signal_with_thread_policy; 632 | 633 | template 642 | using signal8 = 643 | signal_with_thread_policy; 644 | 645 | } // namespace sigslot 646 | 647 | #endif // RTC_BASE_SIGSLOT_H_ 648 | -------------------------------------------------------------------------------- /half_sync_half_reactor/json/json.h: -------------------------------------------------------------------------------- 1 | #ifndef JSON_H 2 | #define JSON_H 3 | 4 | //#define CROW_JSON_NO_ERROR_CHECK 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "settings.h" 17 | 18 | #if defined(__GNUG__) || defined(__clang__) 19 | #define crow_json_likely(x) __builtin_expect(x, 1) 20 | #define crow_json_unlikely(x) __builtin_expect(x, 0) 21 | #else 22 | #define crow_json_likely(x) x 23 | #define crow_json_unlikely(x) x 24 | #endif 25 | 26 | 27 | namespace mustache 28 | { 29 | class template_t; 30 | } 31 | 32 | namespace json 33 | { 34 | inline void escape(const std::string& str, std::string& ret) 35 | { 36 | ret.reserve(ret.size() + str.size()+str.size()/4); 37 | for(char c:str) 38 | { 39 | switch(c) 40 | { 41 | case '"': ret += "\\\""; break; 42 | case '\\': ret += "\\\\"; break; 43 | case '\n': ret += "\\n"; break; 44 | case '\b': ret += "\\b"; break; 45 | case '\f': ret += "\\f"; break; 46 | case '\r': ret += "\\r"; break; 47 | case '\t': ret += "\\t"; break; 48 | default: 49 | if (0 <= c && c < 0x20) 50 | { 51 | ret += "\\u00"; 52 | auto to_hex = [](char c) 53 | { 54 | c = c&0xf; 55 | if (c < 10) 56 | return '0' + c; 57 | return 'a'+c-10; 58 | }; 59 | ret += to_hex(c/16); 60 | ret += to_hex(c%16); 61 | } 62 | else 63 | ret += c; 64 | break; 65 | } 66 | } 67 | } 68 | inline std::string escape(const std::string& str) 69 | { 70 | std::string ret; 71 | escape(str, ret); 72 | return ret; 73 | } 74 | 75 | enum class type : char 76 | { 77 | Null, 78 | False, 79 | True, 80 | Number, 81 | String, 82 | List, 83 | Object, 84 | }; 85 | 86 | inline const char* get_type_str(type t) { 87 | switch(t){ 88 | case type::Number: return "Number"; 89 | case type::False: return "False"; 90 | case type::True: return "True"; 91 | case type::List: return "List"; 92 | case type::String: return "String"; 93 | case type::Object: return "Object"; 94 | default: return "Unknown"; 95 | } 96 | } 97 | 98 | enum class num_type : char { 99 | Signed_integer, 100 | Unsigned_integer, 101 | Floating_point, 102 | Null 103 | }; 104 | 105 | class rvalue; 106 | rvalue load(const char* data, size_t size); 107 | 108 | namespace detail 109 | { 110 | 111 | struct r_string 112 | : boost::less_than_comparable, 113 | boost::less_than_comparable, 114 | boost::equality_comparable, 115 | boost::equality_comparable 116 | { 117 | r_string() {}; 118 | r_string(char* s, char* e) 119 | : s_(s), e_(e) 120 | {}; 121 | ~r_string() 122 | { 123 | if (owned_) 124 | delete[] s_; 125 | } 126 | 127 | r_string(const r_string& r) 128 | { 129 | *this = r; 130 | } 131 | 132 | r_string(r_string&& r) 133 | { 134 | *this = r; 135 | } 136 | 137 | r_string& operator = (r_string&& r) 138 | { 139 | s_ = r.s_; 140 | e_ = r.e_; 141 | owned_ = r.owned_; 142 | if (r.owned_) 143 | r.owned_ = 0; 144 | return *this; 145 | } 146 | 147 | r_string& operator = (const r_string& r) 148 | { 149 | s_ = r.s_; 150 | e_ = r.e_; 151 | owned_ = 0; 152 | return *this; 153 | } 154 | 155 | operator std::string () const 156 | { 157 | return std::string(s_, e_); 158 | } 159 | 160 | 161 | const char* begin() const { return s_; } 162 | const char* end() const { return e_; } 163 | size_t size() const { return end() - begin(); } 164 | 165 | using iterator = const char*; 166 | using const_iterator = const char*; 167 | 168 | char* s_; 169 | mutable char* e_; 170 | uint8_t owned_{0}; 171 | friend std::ostream& operator << (std::ostream& os, const r_string& s) 172 | { 173 | os << (std::string)s; 174 | return os; 175 | } 176 | private: 177 | void force(char* s, uint32_t length) 178 | { 179 | s_ = s; 180 | e_ = s_ + length; 181 | owned_ = 1; 182 | } 183 | friend rvalue json::load(const char* data, size_t size); 184 | }; 185 | 186 | inline bool operator < (const r_string& l, const r_string& r) 187 | { 188 | return boost::lexicographical_compare(l,r); 189 | } 190 | 191 | inline bool operator < (const r_string& l, const std::string& r) 192 | { 193 | return boost::lexicographical_compare(l,r); 194 | } 195 | 196 | inline bool operator > (const r_string& l, const std::string& r) 197 | { 198 | return boost::lexicographical_compare(r,l); 199 | } 200 | 201 | inline bool operator == (const r_string& l, const r_string& r) 202 | { 203 | return boost::equals(l,r); 204 | } 205 | 206 | inline bool operator == (const r_string& l, const std::string& r) 207 | { 208 | return boost::equals(l,r); 209 | } 210 | } 211 | 212 | class rvalue 213 | { 214 | static const int cached_bit = 2; 215 | static const int error_bit = 4; 216 | public: 217 | rvalue() noexcept : option_{error_bit} 218 | {} 219 | rvalue(type t) noexcept 220 | : lsize_{}, lremain_{}, t_{t} 221 | {} 222 | rvalue(type t, char* s, char* e) noexcept 223 | : start_{s}, 224 | end_{e}, 225 | t_{t} 226 | { 227 | determine_num_type(); 228 | } 229 | 230 | rvalue(const rvalue& r) 231 | : start_(r.start_), 232 | end_(r.end_), 233 | key_(r.key_), 234 | t_(r.t_), 235 | nt_(r.nt_), 236 | option_(r.option_) 237 | { 238 | copy_l(r); 239 | } 240 | 241 | rvalue(rvalue&& r) noexcept 242 | { 243 | *this = std::move(r); 244 | } 245 | 246 | rvalue& operator = (const rvalue& r) 247 | { 248 | start_ = r.start_; 249 | end_ = r.end_; 250 | key_ = r.key_; 251 | t_ = r.t_; 252 | nt_ = r.nt_; 253 | option_ = r.option_; 254 | copy_l(r); 255 | return *this; 256 | } 257 | rvalue& operator = (rvalue&& r) noexcept 258 | { 259 | start_ = r.start_; 260 | end_ = r.end_; 261 | key_ = std::move(r.key_); 262 | l_ = std::move(r.l_); 263 | lsize_ = r.lsize_; 264 | lremain_ = r.lremain_; 265 | t_ = r.t_; 266 | nt_ = r.nt_; 267 | option_ = r.option_; 268 | return *this; 269 | } 270 | 271 | explicit operator bool() const noexcept 272 | { 273 | return (option_ & error_bit) == 0; 274 | } 275 | 276 | explicit operator int64_t() const 277 | { 278 | return i(); 279 | } 280 | 281 | explicit operator uint64_t() const 282 | { 283 | return u(); 284 | } 285 | 286 | explicit operator int() const 287 | { 288 | return (int)i(); 289 | } 290 | 291 | type t() const 292 | { 293 | #ifndef CROW_JSON_NO_ERROR_CHECK 294 | if (option_ & error_bit) 295 | { 296 | throw std::runtime_error("invalid json object"); 297 | } 298 | #endif 299 | return t_; 300 | } 301 | 302 | num_type nt() const 303 | { 304 | #ifndef CROW_JSON_NO_ERROR_CHECK 305 | if (option_ & error_bit) 306 | { 307 | throw std::runtime_error("invalid json object"); 308 | } 309 | #endif 310 | return nt_; 311 | } 312 | 313 | int64_t i() const 314 | { 315 | #ifndef CROW_JSON_NO_ERROR_CHECK 316 | switch (t()) { 317 | case type::Number: 318 | case type::String: 319 | return boost::lexical_cast(start_, end_-start_); 320 | default: 321 | const std::string msg = "expected number, got: " 322 | + std::string(get_type_str(t())); 323 | throw std::runtime_error(msg); 324 | } 325 | #endif 326 | return boost::lexical_cast(start_, end_-start_); 327 | } 328 | 329 | uint64_t u() const 330 | { 331 | #ifndef CROW_JSON_NO_ERROR_CHECK 332 | switch (t()) { 333 | case type::Number: 334 | case type::String: 335 | return boost::lexical_cast(start_, end_-start_); 336 | default: 337 | throw std::runtime_error(std::string("expected number, got: ") + get_type_str(t())); 338 | } 339 | #endif 340 | return boost::lexical_cast(start_, end_-start_); 341 | } 342 | 343 | double d() const 344 | { 345 | #ifndef CROW_JSON_NO_ERROR_CHECK 346 | if (t() != type::Number) 347 | throw std::runtime_error("value is not number"); 348 | #endif 349 | return boost::lexical_cast(start_, end_-start_); 350 | } 351 | 352 | bool b() const 353 | { 354 | #ifndef CROW_JSON_NO_ERROR_CHECK 355 | if (t() != type::True && t() != type::False) 356 | throw std::runtime_error("value is not boolean"); 357 | #endif 358 | return t() == type::True; 359 | } 360 | 361 | void unescape() const 362 | { 363 | if (*(start_-1)) 364 | { 365 | char* head = start_; 366 | char* tail = start_; 367 | while(head != end_) 368 | { 369 | if (*head == '\\') 370 | { 371 | switch(*++head) 372 | { 373 | case '"': *tail++ = '"'; break; 374 | case '\\': *tail++ = '\\'; break; 375 | case '/': *tail++ = '/'; break; 376 | case 'b': *tail++ = '\b'; break; 377 | case 'f': *tail++ = '\f'; break; 378 | case 'n': *tail++ = '\n'; break; 379 | case 'r': *tail++ = '\r'; break; 380 | case 't': *tail++ = '\t'; break; 381 | case 'u': 382 | { 383 | auto from_hex = [](char c) 384 | { 385 | if (c >= 'a') 386 | return c - 'a' + 10; 387 | if (c >= 'A') 388 | return c - 'A' + 10; 389 | return c - '0'; 390 | }; 391 | unsigned int code = 392 | (from_hex(head[1])<<12) + 393 | (from_hex(head[2])<< 8) + 394 | (from_hex(head[3])<< 4) + 395 | from_hex(head[4]); 396 | if (code >= 0x800) 397 | { 398 | *tail++ = 0xE0 | (code >> 12); 399 | *tail++ = 0x80 | ((code >> 6) & 0x3F); 400 | *tail++ = 0x80 | (code & 0x3F); 401 | } 402 | else if (code >= 0x80) 403 | { 404 | *tail++ = 0xC0 | (code >> 6); 405 | *tail++ = 0x80 | (code & 0x3F); 406 | } 407 | else 408 | { 409 | *tail++ = code; 410 | } 411 | head += 4; 412 | } 413 | break; 414 | } 415 | } 416 | else 417 | *tail++ = *head; 418 | head++; 419 | } 420 | end_ = tail; 421 | *end_ = 0; 422 | *(start_-1) = 0; 423 | } 424 | } 425 | 426 | detail::r_string s() const 427 | { 428 | #ifndef CROW_JSON_NO_ERROR_CHECK 429 | if (t() != type::String) 430 | throw std::runtime_error("value is not string"); 431 | #endif 432 | unescape(); 433 | return detail::r_string{start_, end_}; 434 | } 435 | 436 | bool has(const char* str) const 437 | { 438 | return has(std::string(str)); 439 | } 440 | 441 | bool has(const std::string& str) const 442 | { 443 | struct Pred 444 | { 445 | bool operator()(const rvalue& l, const rvalue& r) const 446 | { 447 | return l.key_ < r.key_; 448 | }; 449 | bool operator()(const rvalue& l, const std::string& r) const 450 | { 451 | return l.key_ < r; 452 | }; 453 | bool operator()(const std::string& l, const rvalue& r) const 454 | { 455 | return l < r.key_; 456 | }; 457 | }; 458 | if (!is_cached()) 459 | { 460 | std::sort(begin(), end(), Pred()); 461 | set_cached(); 462 | } 463 | auto it = lower_bound(begin(), end(), str, Pred()); 464 | return it != end() && it->key_ == str; 465 | } 466 | 467 | int count(const std::string& str) 468 | { 469 | return has(str) ? 1 : 0; 470 | } 471 | 472 | rvalue* begin() const 473 | { 474 | #ifndef CROW_JSON_NO_ERROR_CHECK 475 | if (t() != type::Object && t() != type::List) 476 | throw std::runtime_error("value is not a container"); 477 | #endif 478 | return l_.get(); 479 | } 480 | rvalue* end() const 481 | { 482 | #ifndef CROW_JSON_NO_ERROR_CHECK 483 | if (t() != type::Object && t() != type::List) 484 | throw std::runtime_error("value is not a container"); 485 | #endif 486 | return l_.get()+lsize_; 487 | } 488 | 489 | const detail::r_string& key() const 490 | { 491 | return key_; 492 | } 493 | 494 | size_t size() const 495 | { 496 | if (t() == type::String) 497 | return s().size(); 498 | #ifndef CROW_JSON_NO_ERROR_CHECK 499 | if (t() != type::Object && t() != type::List) 500 | throw std::runtime_error("value is not a container"); 501 | #endif 502 | return lsize_; 503 | } 504 | 505 | const rvalue& operator[](int index) const 506 | { 507 | #ifndef CROW_JSON_NO_ERROR_CHECK 508 | if (t() != type::List) 509 | throw std::runtime_error("value is not a list"); 510 | if (index >= (int)lsize_ || index < 0) 511 | throw std::runtime_error("list out of bound"); 512 | #endif 513 | return l_[index]; 514 | } 515 | 516 | const rvalue& operator[](size_t index) const 517 | { 518 | #ifndef CROW_JSON_NO_ERROR_CHECK 519 | if (t() != type::List) 520 | throw std::runtime_error("value is not a list"); 521 | if (index >= lsize_) 522 | throw std::runtime_error("list out of bound"); 523 | #endif 524 | return l_[index]; 525 | } 526 | 527 | const rvalue& operator[](const char* str) const 528 | { 529 | return this->operator[](std::string(str)); 530 | } 531 | 532 | const rvalue& operator[](const std::string& str) const 533 | { 534 | #ifndef CROW_JSON_NO_ERROR_CHECK 535 | if (t() != type::Object) 536 | throw std::runtime_error("value is not an object"); 537 | #endif 538 | struct Pred 539 | { 540 | bool operator()(const rvalue& l, const rvalue& r) const 541 | { 542 | return l.key_ < r.key_; 543 | }; 544 | bool operator()(const rvalue& l, const std::string& r) const 545 | { 546 | return l.key_ < r; 547 | }; 548 | bool operator()(const std::string& l, const rvalue& r) const 549 | { 550 | return l < r.key_; 551 | }; 552 | }; 553 | if (!is_cached()) 554 | { 555 | std::sort(begin(), end(), Pred()); 556 | set_cached(); 557 | } 558 | auto it = lower_bound(begin(), end(), str, Pred()); 559 | if (it != end() && it->key_ == str) 560 | return *it; 561 | #ifndef CROW_JSON_NO_ERROR_CHECK 562 | throw std::runtime_error("cannot find key"); 563 | #else 564 | static rvalue nullValue; 565 | return nullValue; 566 | #endif 567 | } 568 | 569 | void set_error() 570 | { 571 | option_|=error_bit; 572 | } 573 | 574 | bool error() const 575 | { 576 | return (option_&error_bit)!=0; 577 | } 578 | private: 579 | bool is_cached() const 580 | { 581 | return (option_&cached_bit)!=0; 582 | } 583 | void set_cached() const 584 | { 585 | option_ |= cached_bit; 586 | } 587 | void copy_l(const rvalue& r) 588 | { 589 | if (r.t() != type::Object && r.t() != type::List) 590 | return; 591 | lsize_ = r.lsize_; 592 | lremain_ = 0; 593 | l_.reset(new rvalue[lsize_]); 594 | std::copy(r.begin(), r.end(), begin()); 595 | } 596 | 597 | void emplace_back(rvalue&& v) 598 | { 599 | if (!lremain_) 600 | { 601 | int new_size = lsize_ + lsize_; 602 | if (new_size - lsize_ > 60000) 603 | new_size = lsize_ + 60000; 604 | if (new_size < 4) 605 | new_size = 4; 606 | rvalue* p = new rvalue[new_size]; 607 | rvalue* p2 = p; 608 | for(auto& x : *this) 609 | *p2++ = std::move(x); 610 | l_.reset(p); 611 | lremain_ = new_size - lsize_; 612 | } 613 | l_[lsize_++] = std::move(v); 614 | lremain_ --; 615 | } 616 | 617 | // determines num_type from the string 618 | void determine_num_type() 619 | { 620 | if (t_ != type::Number) 621 | { 622 | nt_ = num_type::Null; 623 | return; 624 | } 625 | 626 | const std::size_t len = end_ - start_; 627 | const bool has_minus = std::memchr(start_, '-', len) != nullptr; 628 | const bool has_e = std::memchr(start_, 'e', len) != nullptr 629 | || std::memchr(start_, 'E', len) != nullptr; 630 | const bool has_dec_sep = std::memchr(start_, '.', len) != nullptr; 631 | if (has_dec_sep || has_e) 632 | nt_ = num_type::Floating_point; 633 | else if (has_minus) 634 | nt_ = num_type::Signed_integer; 635 | else 636 | nt_ = num_type::Unsigned_integer; 637 | } 638 | 639 | mutable char* start_; 640 | mutable char* end_; 641 | detail::r_string key_; 642 | std::unique_ptr l_; 643 | uint32_t lsize_; 644 | uint16_t lremain_; 645 | type t_; 646 | num_type nt_{num_type::Null}; 647 | mutable uint8_t option_{0}; 648 | 649 | friend rvalue load_nocopy_internal(char* data, size_t size); 650 | friend rvalue load(const char* data, size_t size); 651 | friend std::ostream& operator <<(std::ostream& os, const rvalue& r) 652 | { 653 | switch(r.t_) 654 | { 655 | 656 | case type::Null: os << "null"; break; 657 | case type::False: os << "false"; break; 658 | case type::True: os << "true"; break; 659 | case type::Number: 660 | { 661 | switch (r.nt()) 662 | { 663 | case num_type::Floating_point: os << r.d(); break; 664 | case num_type::Signed_integer: os << r.i(); break; 665 | case num_type::Unsigned_integer: os << r.u(); break; 666 | case num_type::Null: throw std::runtime_error("Number with num_type Null"); 667 | } 668 | } 669 | break; 670 | case type::String: os << '"' << r.s() << '"'; break; 671 | case type::List: 672 | { 673 | os << '['; 674 | bool first = true; 675 | for(auto& x : r) 676 | { 677 | if (!first) 678 | os << ','; 679 | first = false; 680 | os << x; 681 | } 682 | os << ']'; 683 | } 684 | break; 685 | case type::Object: 686 | { 687 | os << '{'; 688 | bool first = true; 689 | for(auto& x : r) 690 | { 691 | if (!first) 692 | os << ','; 693 | os << '"' << escape(x.key_) << "\":"; 694 | first = false; 695 | os << x; 696 | } 697 | os << '}'; 698 | } 699 | break; 700 | } 701 | return os; 702 | } 703 | }; 704 | namespace detail { 705 | } 706 | 707 | inline bool operator == (const rvalue& l, const std::string& r) 708 | { 709 | return l.s() == r; 710 | } 711 | 712 | inline bool operator == (const std::string& l, const rvalue& r) 713 | { 714 | return l == r.s(); 715 | } 716 | 717 | inline bool operator != (const rvalue& l, const std::string& r) 718 | { 719 | return l.s() != r; 720 | } 721 | 722 | inline bool operator != (const std::string& l, const rvalue& r) 723 | { 724 | return l != r.s(); 725 | } 726 | 727 | inline bool operator == (const rvalue& l, double r) 728 | { 729 | return l.d() == r; 730 | } 731 | 732 | inline bool operator == (double l, const rvalue& r) 733 | { 734 | return l == r.d(); 735 | } 736 | 737 | inline bool operator != (const rvalue& l, double r) 738 | { 739 | return l.d() != r; 740 | } 741 | 742 | inline bool operator != (double l, const rvalue& r) 743 | { 744 | return l != r.d(); 745 | } 746 | 747 | 748 | inline rvalue load_nocopy_internal(char* data, size_t size) 749 | { 750 | //static const char* escaped = "\"\\/\b\f\n\r\t"; 751 | struct Parser 752 | { 753 | Parser(char* data, size_t /*size*/) 754 | : data(data) 755 | { 756 | } 757 | 758 | bool consume(char c) 759 | { 760 | if (crow_json_unlikely(*data != c)) 761 | return false; 762 | data++; 763 | return true; 764 | } 765 | 766 | void ws_skip() 767 | { 768 | while(*data == ' ' || *data == '\t' || *data == '\r' || *data == '\n') ++data; 769 | }; 770 | 771 | rvalue decode_string() 772 | { 773 | if (crow_json_unlikely(!consume('"'))) 774 | return {}; 775 | char* start = data; 776 | uint8_t has_escaping = 0; 777 | while(1) 778 | { 779 | if (crow_json_likely(*data != '"' && *data != '\\' && *data != '\0')) 780 | { 781 | data ++; 782 | } 783 | else if (*data == '"') 784 | { 785 | *data = 0; 786 | *(start-1) = has_escaping; 787 | data++; 788 | return {type::String, start, data-1}; 789 | } 790 | else if (*data == '\\') 791 | { 792 | has_escaping = 1; 793 | data++; 794 | switch(*data) 795 | { 796 | case 'u': 797 | { 798 | auto check = [](char c) 799 | { 800 | return 801 | ('0' <= c && c <= '9') || 802 | ('a' <= c && c <= 'f') || 803 | ('A' <= c && c <= 'F'); 804 | }; 805 | if (!(check(*(data+1)) && 806 | check(*(data+2)) && 807 | check(*(data+3)) && 808 | check(*(data+4)))) 809 | return {}; 810 | } 811 | data += 5; 812 | break; 813 | case '"': 814 | case '\\': 815 | case '/': 816 | case 'b': 817 | case 'f': 818 | case 'n': 819 | case 'r': 820 | case 't': 821 | data ++; 822 | break; 823 | default: 824 | return {}; 825 | } 826 | } 827 | else 828 | return {}; 829 | } 830 | return {}; 831 | } 832 | 833 | rvalue decode_list() 834 | { 835 | rvalue ret(type::List); 836 | if (crow_json_unlikely(!consume('['))) 837 | { 838 | ret.set_error(); 839 | return ret; 840 | } 841 | ws_skip(); 842 | if (crow_json_unlikely(*data == ']')) 843 | { 844 | data++; 845 | return ret; 846 | } 847 | 848 | while(1) 849 | { 850 | auto v = decode_value(); 851 | if (crow_json_unlikely(!v)) 852 | { 853 | ret.set_error(); 854 | break; 855 | } 856 | ws_skip(); 857 | ret.emplace_back(std::move(v)); 858 | if (*data == ']') 859 | { 860 | data++; 861 | break; 862 | } 863 | if (crow_json_unlikely(!consume(','))) 864 | { 865 | ret.set_error(); 866 | break; 867 | } 868 | ws_skip(); 869 | } 870 | return ret; 871 | } 872 | 873 | rvalue decode_number() 874 | { 875 | char* start = data; 876 | 877 | enum NumberParsingState 878 | { 879 | Minus, 880 | AfterMinus, 881 | ZeroFirst, 882 | Digits, 883 | DigitsAfterPoints, 884 | E, 885 | DigitsAfterE, 886 | Invalid, 887 | } state{Minus}; 888 | while(crow_json_likely(state != Invalid)) 889 | { 890 | switch(*data) 891 | { 892 | case '0': 893 | state = (NumberParsingState)"\2\2\7\3\4\6\6"[state]; 894 | /*if (state == NumberParsingState::Minus || state == NumberParsingState::AfterMinus) 895 | { 896 | state = NumberParsingState::ZeroFirst; 897 | } 898 | else if (state == NumberParsingState::Digits || 899 | state == NumberParsingState::DigitsAfterE || 900 | state == NumberParsingState::DigitsAfterPoints) 901 | { 902 | // ok; pass 903 | } 904 | else if (state == NumberParsingState::E) 905 | { 906 | state = NumberParsingState::DigitsAfterE; 907 | } 908 | else 909 | return {};*/ 910 | break; 911 | case '1': case '2': case '3': 912 | case '4': case '5': case '6': 913 | case '7': case '8': case '9': 914 | state = (NumberParsingState)"\3\3\7\3\4\6\6"[state]; 915 | while(*(data+1) >= '0' && *(data+1) <= '9') data++; 916 | /*if (state == NumberParsingState::Minus || state == NumberParsingState::AfterMinus) 917 | { 918 | state = NumberParsingState::Digits; 919 | } 920 | else if (state == NumberParsingState::Digits || 921 | state == NumberParsingState::DigitsAfterE || 922 | state == NumberParsingState::DigitsAfterPoints) 923 | { 924 | // ok; pass 925 | } 926 | else if (state == NumberParsingState::E) 927 | { 928 | state = NumberParsingState::DigitsAfterE; 929 | } 930 | else 931 | return {};*/ 932 | break; 933 | case '.': 934 | state = (NumberParsingState)"\7\7\4\4\7\7\7"[state]; 935 | /* 936 | if (state == NumberParsingState::Digits || state == NumberParsingState::ZeroFirst) 937 | { 938 | state = NumberParsingState::DigitsAfterPoints; 939 | } 940 | else 941 | return {}; 942 | */ 943 | break; 944 | case '-': 945 | state = (NumberParsingState)"\1\7\7\7\7\6\7"[state]; 946 | /*if (state == NumberParsingState::Minus) 947 | { 948 | state = NumberParsingState::AfterMinus; 949 | } 950 | else if (state == NumberParsingState::E) 951 | { 952 | state = NumberParsingState::DigitsAfterE; 953 | } 954 | else 955 | return {};*/ 956 | break; 957 | case '+': 958 | state = (NumberParsingState)"\7\7\7\7\7\6\7"[state]; 959 | /*if (state == NumberParsingState::E) 960 | { 961 | state = NumberParsingState::DigitsAfterE; 962 | } 963 | else 964 | return {};*/ 965 | break; 966 | case 'e': case 'E': 967 | state = (NumberParsingState)"\7\7\7\5\5\7\7"[state]; 968 | /*if (state == NumberParsingState::Digits || 969 | state == NumberParsingState::DigitsAfterPoints) 970 | { 971 | state = NumberParsingState::E; 972 | } 973 | else 974 | return {};*/ 975 | break; 976 | default: 977 | if (crow_json_likely(state == NumberParsingState::ZeroFirst || 978 | state == NumberParsingState::Digits || 979 | state == NumberParsingState::DigitsAfterPoints || 980 | state == NumberParsingState::DigitsAfterE)) 981 | return {type::Number, start, data}; 982 | else 983 | return {}; 984 | } 985 | data++; 986 | } 987 | 988 | return {}; 989 | } 990 | 991 | rvalue decode_value() 992 | { 993 | switch(*data) 994 | { 995 | case '[': 996 | return decode_list(); 997 | case '{': 998 | return decode_object(); 999 | case '"': 1000 | return decode_string(); 1001 | case 't': 1002 | if (//e-data >= 4 && 1003 | data[1] == 'r' && 1004 | data[2] == 'u' && 1005 | data[3] == 'e') 1006 | { 1007 | data += 4; 1008 | return {type::True}; 1009 | } 1010 | else 1011 | return {}; 1012 | case 'f': 1013 | if (//e-data >= 5 && 1014 | data[1] == 'a' && 1015 | data[2] == 'l' && 1016 | data[3] == 's' && 1017 | data[4] == 'e') 1018 | { 1019 | data += 5; 1020 | return {type::False}; 1021 | } 1022 | else 1023 | return {}; 1024 | case 'n': 1025 | if (//e-data >= 4 && 1026 | data[1] == 'u' && 1027 | data[2] == 'l' && 1028 | data[3] == 'l') 1029 | { 1030 | data += 4; 1031 | return {type::Null}; 1032 | } 1033 | else 1034 | return {}; 1035 | //case '1': case '2': case '3': 1036 | //case '4': case '5': case '6': 1037 | //case '7': case '8': case '9': 1038 | //case '0': case '-': 1039 | default: 1040 | return decode_number(); 1041 | } 1042 | return {}; 1043 | } 1044 | 1045 | rvalue decode_object() 1046 | { 1047 | rvalue ret(type::Object); 1048 | if (crow_json_unlikely(!consume('{'))) 1049 | { 1050 | ret.set_error(); 1051 | return ret; 1052 | } 1053 | 1054 | ws_skip(); 1055 | 1056 | if (crow_json_unlikely(*data == '}')) 1057 | { 1058 | data++; 1059 | return ret; 1060 | } 1061 | 1062 | while(1) 1063 | { 1064 | auto t = decode_string(); 1065 | if (crow_json_unlikely(!t)) 1066 | { 1067 | ret.set_error(); 1068 | break; 1069 | } 1070 | 1071 | ws_skip(); 1072 | if (crow_json_unlikely(!consume(':'))) 1073 | { 1074 | ret.set_error(); 1075 | break; 1076 | } 1077 | 1078 | // TODO caching key to speed up (flyweight?) 1079 | auto key = t.s(); 1080 | 1081 | ws_skip(); 1082 | auto v = decode_value(); 1083 | if (crow_json_unlikely(!v)) 1084 | { 1085 | ret.set_error(); 1086 | break; 1087 | } 1088 | ws_skip(); 1089 | 1090 | v.key_ = std::move(key); 1091 | ret.emplace_back(std::move(v)); 1092 | if (crow_json_unlikely(*data == '}')) 1093 | { 1094 | data++; 1095 | break; 1096 | } 1097 | if (crow_json_unlikely(!consume(','))) 1098 | { 1099 | ret.set_error(); 1100 | break; 1101 | } 1102 | ws_skip(); 1103 | } 1104 | return ret; 1105 | } 1106 | 1107 | rvalue parse() 1108 | { 1109 | ws_skip(); 1110 | auto ret = decode_value(); // or decode object? 1111 | ws_skip(); 1112 | if (ret && *data != '\0') 1113 | ret.set_error(); 1114 | return ret; 1115 | } 1116 | 1117 | char* data; 1118 | }; 1119 | return Parser(data, size).parse(); 1120 | } 1121 | inline rvalue load(const char* data, size_t size) 1122 | { 1123 | char* s = new char[size+1]; 1124 | memcpy(s, data, size); 1125 | s[size] = 0; 1126 | auto ret = load_nocopy_internal(s, size); 1127 | if (ret) 1128 | ret.key_.force(s, size); 1129 | else 1130 | delete[] s; 1131 | return ret; 1132 | } 1133 | 1134 | inline rvalue load(const char* data) 1135 | { 1136 | return load(data, strlen(data)); 1137 | } 1138 | 1139 | inline rvalue load(const std::string& str) 1140 | { 1141 | return load(str.data(), str.size()); 1142 | } 1143 | 1144 | class wvalue 1145 | { 1146 | friend class crow::mustache::template_t; 1147 | public: 1148 | type t() const { return t_; } 1149 | private: 1150 | type t_{type::Null}; 1151 | num_type nt{num_type::Null}; 1152 | union { 1153 | double d; 1154 | int64_t si; 1155 | uint64_t ui {}; 1156 | } num; 1157 | std::string s; 1158 | std::unique_ptr> l; 1159 | std::unique_ptr> o; 1160 | public: 1161 | 1162 | wvalue() {} 1163 | 1164 | wvalue(const rvalue& r) 1165 | { 1166 | t_ = r.t(); 1167 | switch(r.t()) 1168 | { 1169 | case type::Null: 1170 | case type::False: 1171 | case type::True: 1172 | return; 1173 | case type::Number: 1174 | nt = r.nt(); 1175 | if (nt == num_type::Floating_point) 1176 | num.d = r.d(); 1177 | else if (nt == num_type::Signed_integer) 1178 | num.si = r.i(); 1179 | else 1180 | num.ui = r.u(); 1181 | return; 1182 | case type::String: 1183 | s = r.s(); 1184 | return; 1185 | case type::List: 1186 | l = std::unique_ptr>(new std::vector{}); 1187 | l->reserve(r.size()); 1188 | for(auto it = r.begin(); it != r.end(); ++it) 1189 | l->emplace_back(*it); 1190 | return; 1191 | case type::Object: 1192 | o = std::unique_ptr< 1193 | std::unordered_map 1194 | >( 1195 | new std::unordered_map{}); 1196 | for(auto it = r.begin(); it != r.end(); ++it) 1197 | o->emplace(it->key(), *it); 1198 | return; 1199 | } 1200 | } 1201 | 1202 | wvalue(wvalue&& r) 1203 | { 1204 | *this = std::move(r); 1205 | } 1206 | 1207 | wvalue& operator = (wvalue&& r) 1208 | { 1209 | t_ = r.t_; 1210 | num = r.num; 1211 | s = std::move(r.s); 1212 | l = std::move(r.l); 1213 | o = std::move(r.o); 1214 | return *this; 1215 | } 1216 | 1217 | void clear() 1218 | { 1219 | reset(); 1220 | } 1221 | 1222 | void reset() 1223 | { 1224 | t_ = type::Null; 1225 | l.reset(); 1226 | o.reset(); 1227 | } 1228 | 1229 | wvalue& operator = (std::nullptr_t) 1230 | { 1231 | reset(); 1232 | return *this; 1233 | } 1234 | wvalue& operator = (bool value) 1235 | { 1236 | reset(); 1237 | if (value) 1238 | t_ = type::True; 1239 | else 1240 | t_ = type::False; 1241 | return *this; 1242 | } 1243 | 1244 | wvalue& operator = (double value) 1245 | { 1246 | reset(); 1247 | t_ = type::Number; 1248 | num.d = value; 1249 | nt = num_type::Floating_point; 1250 | return *this; 1251 | } 1252 | 1253 | wvalue& operator = (unsigned short value) 1254 | { 1255 | reset(); 1256 | t_ = type::Number; 1257 | num.ui = value; 1258 | nt = num_type::Unsigned_integer; 1259 | return *this; 1260 | } 1261 | 1262 | wvalue& operator = (short value) 1263 | { 1264 | reset(); 1265 | t_ = type::Number; 1266 | num.si = value; 1267 | nt = num_type::Signed_integer; 1268 | return *this; 1269 | } 1270 | 1271 | wvalue& operator = (long long value) 1272 | { 1273 | reset(); 1274 | t_ = type::Number; 1275 | num.si = value; 1276 | nt = num_type::Signed_integer; 1277 | return *this; 1278 | } 1279 | 1280 | wvalue& operator = (long value) 1281 | { 1282 | reset(); 1283 | t_ = type::Number; 1284 | num.si = value; 1285 | nt = num_type::Signed_integer; 1286 | return *this; 1287 | } 1288 | 1289 | wvalue& operator = (int value) 1290 | { 1291 | reset(); 1292 | t_ = type::Number; 1293 | num.si = value; 1294 | nt = num_type::Signed_integer; 1295 | return *this; 1296 | } 1297 | 1298 | wvalue& operator = (unsigned long long value) 1299 | { 1300 | reset(); 1301 | t_ = type::Number; 1302 | num.ui = value; 1303 | nt = num_type::Unsigned_integer; 1304 | return *this; 1305 | } 1306 | 1307 | wvalue& operator = (unsigned long value) 1308 | { 1309 | reset(); 1310 | t_ = type::Number; 1311 | num.ui = value; 1312 | nt = num_type::Unsigned_integer; 1313 | return *this; 1314 | } 1315 | 1316 | wvalue& operator = (unsigned int value) 1317 | { 1318 | reset(); 1319 | t_ = type::Number; 1320 | num.ui = value; 1321 | nt = num_type::Unsigned_integer; 1322 | return *this; 1323 | } 1324 | 1325 | wvalue& operator=(const char* str) 1326 | { 1327 | reset(); 1328 | t_ = type::String; 1329 | s = str; 1330 | return *this; 1331 | } 1332 | 1333 | wvalue& operator=(const std::string& str) 1334 | { 1335 | reset(); 1336 | t_ = type::String; 1337 | s = str; 1338 | return *this; 1339 | } 1340 | 1341 | wvalue& operator=(std::vector&& v) 1342 | { 1343 | if (t_ != type::List) 1344 | reset(); 1345 | t_ = type::List; 1346 | if (!l) 1347 | l = std::unique_ptr>(new std::vector{}); 1348 | l->clear(); 1349 | l->resize(v.size()); 1350 | size_t idx = 0; 1351 | for(auto& x:v) 1352 | { 1353 | (*l)[idx++] = std::move(x); 1354 | } 1355 | return *this; 1356 | } 1357 | 1358 | template 1359 | wvalue& operator=(const std::vector& v) 1360 | { 1361 | if (t_ != type::List) 1362 | reset(); 1363 | t_ = type::List; 1364 | if (!l) 1365 | l = std::unique_ptr>(new std::vector{}); 1366 | l->clear(); 1367 | l->resize(v.size()); 1368 | size_t idx = 0; 1369 | for(auto& x:v) 1370 | { 1371 | (*l)[idx++] = x; 1372 | } 1373 | return *this; 1374 | } 1375 | 1376 | wvalue& operator[](unsigned index) 1377 | { 1378 | if (t_ != type::List) 1379 | reset(); 1380 | t_ = type::List; 1381 | if (!l) 1382 | l = std::unique_ptr>(new std::vector{}); 1383 | if (l->size() < index+1) 1384 | l->resize(index+1); 1385 | return (*l)[index]; 1386 | } 1387 | 1388 | int count(const std::string& str) 1389 | { 1390 | if (t_ != type::Object) 1391 | return 0; 1392 | if (!o) 1393 | return 0; 1394 | return o->count(str); 1395 | } 1396 | 1397 | wvalue& operator[](const std::string& str) 1398 | { 1399 | if (t_ != type::Object) 1400 | reset(); 1401 | t_ = type::Object; 1402 | if (!o) 1403 | o = std::unique_ptr< 1404 | std::unordered_map 1405 | >( 1406 | new std::unordered_map{}); 1407 | return (*o)[str]; 1408 | } 1409 | 1410 | std::vector keys() const 1411 | { 1412 | if (t_ != type::Object) 1413 | return {}; 1414 | std::vector result; 1415 | for (auto& kv:*o) 1416 | { 1417 | result.push_back(kv.first); 1418 | } 1419 | return result; 1420 | } 1421 | 1422 | size_t estimate_length() const 1423 | { 1424 | switch(t_) 1425 | { 1426 | case type::Null: return 4; 1427 | case type::False: return 5; 1428 | case type::True: return 4; 1429 | case type::Number: return 30; 1430 | case type::String: return 2+s.size()+s.size()/2; 1431 | case type::List: 1432 | { 1433 | size_t sum{}; 1434 | if (l) 1435 | { 1436 | for(auto& x:*l) 1437 | { 1438 | sum += 1; 1439 | sum += x.estimate_length(); 1440 | } 1441 | } 1442 | return sum+2; 1443 | } 1444 | case type::Object: 1445 | { 1446 | size_t sum{}; 1447 | if (o) 1448 | { 1449 | for(auto& kv:*o) 1450 | { 1451 | sum += 2; 1452 | sum += 2+kv.first.size()+kv.first.size()/2; 1453 | sum += kv.second.estimate_length(); 1454 | } 1455 | } 1456 | return sum+2; 1457 | } 1458 | } 1459 | return 1; 1460 | } 1461 | 1462 | friend void dump_internal(const wvalue& v, std::string& out); 1463 | friend std::string dump(const wvalue& v); 1464 | }; 1465 | 1466 | inline void dump_string(const std::string& str, std::string& out) 1467 | { 1468 | out.push_back('"'); 1469 | escape(str, out); 1470 | out.push_back('"'); 1471 | } 1472 | inline void dump_internal(const wvalue& v, std::string& out) 1473 | { 1474 | switch(v.t_) 1475 | { 1476 | case type::Null: out += "null"; break; 1477 | case type::False: out += "false"; break; 1478 | case type::True: out += "true"; break; 1479 | case type::Number: 1480 | { 1481 | if (v.nt == num_type::Floating_point) 1482 | { 1483 | #ifdef _MSC_VER 1484 | #define MSC_COMPATIBLE_SPRINTF(BUFFER_PTR, FORMAT_PTR, VALUE) sprintf_s((BUFFER_PTR), 128, (FORMAT_PTR), (VALUE)) 1485 | #else 1486 | #define MSC_COMPATIBLE_SPRINTF(BUFFER_PTR, FORMAT_PTR, VALUE) sprintf((BUFFER_PTR), (FORMAT_PTR), (VALUE)) 1487 | #endif 1488 | char outbuf[128]; 1489 | MSC_COMPATIBLE_SPRINTF(outbuf, "%g", v.num.d); 1490 | out += outbuf; 1491 | #undef MSC_COMPATIBLE_SPRINTF 1492 | } 1493 | else if (v.nt == num_type::Signed_integer) 1494 | { 1495 | out += std::to_string(v.num.si); 1496 | } 1497 | else 1498 | { 1499 | out += std::to_string(v.num.ui); 1500 | } 1501 | } 1502 | break; 1503 | case type::String: dump_string(v.s, out); break; 1504 | case type::List: 1505 | { 1506 | out.push_back('['); 1507 | if (v.l) 1508 | { 1509 | bool first = true; 1510 | for(auto& x:*v.l) 1511 | { 1512 | if (!first) 1513 | { 1514 | out.push_back(','); 1515 | } 1516 | first = false; 1517 | dump_internal(x, out); 1518 | } 1519 | } 1520 | out.push_back(']'); 1521 | } 1522 | break; 1523 | case type::Object: 1524 | { 1525 | out.push_back('{'); 1526 | if (v.o) 1527 | { 1528 | bool first = true; 1529 | for(auto& kv:*v.o) 1530 | { 1531 | if (!first) 1532 | { 1533 | out.push_back(','); 1534 | } 1535 | first = false; 1536 | dump_string(kv.first, out); 1537 | out.push_back(':'); 1538 | dump_internal(kv.second, out); 1539 | } 1540 | } 1541 | out.push_back('}'); 1542 | } 1543 | break; 1544 | } 1545 | } 1546 | 1547 | inline std::string dump(const wvalue& v) 1548 | { 1549 | std::string ret; 1550 | ret.reserve(v.estimate_length()); 1551 | dump_internal(v, ret); 1552 | return ret; 1553 | } 1554 | 1555 | //std::vector dump_ref(wvalue& v) 1556 | //{ 1557 | //} 1558 | } 1559 | 1560 | #undef crow_json_likely 1561 | #undef crow_json_unlikely 1562 | 1563 | #endif 1564 | --------------------------------------------------------------------------------