├── .travis.yml ├── LICENSE ├── README.md ├── SConstruct ├── cocgi ├── README.md ├── SConstruct ├── backend.cpp ├── backend.h ├── cgicc_lib │ ├── CgiUtils.cpp │ ├── CgiUtils.h │ ├── Cgicc.cpp │ ├── Cgicc.h │ ├── FormEntry.cpp │ ├── FormEntry.h │ ├── FormFile.cpp │ ├── FormFile.h │ ├── HTTPCookie.cpp │ ├── HTTPCookie.h │ ├── MStreamable.cpp │ └── MStreamable.h ├── fastcgi.cpp ├── fastcgi.h ├── libco │ ├── co_closure.h │ ├── co_epoll.cpp │ ├── co_epoll.h │ ├── co_hook_sys_call.cpp │ ├── co_routine.cpp │ ├── co_routine.h │ ├── co_routine_inner.h │ ├── co_routine_specific.h │ ├── coctx.cpp │ ├── coctx.h │ └── coctx_swap.S ├── main.cpp ├── make.sh ├── muduo_lib │ ├── Buffer.cpp │ ├── Buffer.h │ └── StringPiece.h └── type.h ├── doc ├── image │ ├── code.png │ ├── fireframe1.png │ ├── fireframe2.png │ ├── image001.png │ ├── image002.png │ ├── image003.png │ ├── image004.png │ ├── image005.png │ ├── image006.png │ ├── image007.png │ ├── image008.png │ ├── image009.png │ ├── image010.png │ ├── image011.png │ ├── image012.png │ ├── image013.png │ ├── image014.png │ ├── image015.png │ ├── image016.png │ ├── image017.png │ ├── image018.png │ ├── image019.png │ ├── last01.jpg │ ├── last02.png │ └── last03.png ├── libfcgi_vs_mucgi_performance.md ├── nginx_configure.conf └── nginx_shortlink_performance.md └── mucgi ├── README.md ├── SConstruct ├── backend.cpp ├── backend.h ├── cgicc_lib ├── CgiUtils.cpp ├── CgiUtils.h ├── Cgicc.cpp ├── Cgicc.h ├── FormEntry.cpp ├── FormEntry.h ├── FormFile.cpp ├── FormFile.h ├── HTTPCookie.cpp ├── HTTPCookie.h ├── MStreamable.cpp └── MStreamable.h ├── fastcgi.cpp ├── fastcgi.h ├── main.cpp ├── make.sh ├── muduo_base ├── Atomic.h ├── Condition.h ├── CurrentThread.h ├── Date.cc ├── Date.h ├── Exception.cc ├── Exception.h ├── FileUtil.cc ├── FileUtil.h ├── LogFile.cc ├── LogFile.h ├── LogStream.cc ├── LogStream.h ├── Logging.cc ├── Logging.h ├── Mutex.h ├── ProcessInfo.cc ├── ProcessInfo.h ├── StringPiece.h ├── Thread.cc ├── Thread.h ├── TimeZone.cc ├── TimeZone.h ├── Timestamp.cc ├── Timestamp.h ├── Types.h ├── WeakCallback.h └── copyable.h ├── muduo_net ├── Acceptor.cc ├── Acceptor.h ├── Buffer.cc ├── Buffer.h ├── Callbacks.h ├── Channel.cc ├── Channel.h ├── DefaultPoller.cc ├── EPollPoller.cc ├── EPollPoller.h ├── Endian.h ├── EventLoop.cc ├── EventLoop.h ├── EventLoopThread.cc ├── EventLoopThread.h ├── EventLoopThreadPool.cc ├── EventLoopThreadPool.h ├── InetAddress.cc ├── InetAddress.h ├── PollPoller.cc ├── PollPoller.h ├── Poller.cc ├── Poller.h ├── Socket.cc ├── Socket.h ├── SocketsOps.cc ├── SocketsOps.h ├── TcpConnection.cc ├── TcpConnection.h ├── TcpServer.cc ├── TcpServer.h ├── Timer.cc ├── Timer.h ├── TimerId.h ├── TimerQueue.cc └── TimerQueue.h └── type.h /.travis.yml: -------------------------------------------------------------------------------- 1 | # 开启Travis CI任务, 提交后自动生成测试报告。 2 | language: cpp 3 | os: 4 | - linux 5 | 6 | compiler: 7 | - gcc 8 | 9 | branches: 10 | only: 11 | - master 12 | 13 | env: 14 | global: 15 | # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created 16 | # via the "travis encrypt" command using the project repo's public key 17 | - secure: "C7smbw+mWbRYws6rKUoeGZRbK4feg+Xnfp0Owk8tLepMIGCUw/SLxPhe0rXNl1c09ABQaX9pCtXxFtz/nnfCuO55Eqdi71Il/+X6PYwMgaBOnMVWdywRgThUp7Hu2i/rK0b4ZYEQURj0HdOfIOjWY4L7v/CrnOPprwLjvrmg8CZOku2ytVmxULIrWYumbfV2KgJZs/hQaPlhcUR/eSYNVl0tz/aPEXGfUfFekuxmLWDP/z3vrIDW/hPmmWEelJVx3RTKDB+BXuNfaVfgzvoU4IV/mIG9l3FGybnQVviGZv03rJJUpaWTIsf+/CqUd6qDaesnCoiRcbkO8PwOT30GzMiPu7usu1veWhhVp9yb32nzfqITeQvzPqla74Hzjuzmyhqbi+Y1kD9rJkfS/300Z1qgb5BFjU0eblW6REuWNw4AvqgcbbqWAS5IBLVLTw+lBZNjWMl5pPlRBh3cNWKi7y1Ak2PeLgqTy03v9nlieo18PCbBFFRk2qpEiJ2bud7ptl2L/gBURvTRA6jNq5wAkCdr8xNnmeaKtbJyGuB5F9cRaz7LBRbZ36pgdO1it1Rq4kg57ooJB9cNn/ODKzZ51KPIPxkU4ODI8bvhGGZwmMKzv1kFHiAAelKaNb5TqoD4fmLp/4ukRAJo3m9QTKsWyw4NYPuGgFkT5tRucNhBSAs=" 18 | 19 | before_install: 20 | - echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca- 21 | - sudo apt-get update -y 22 | - sudo apt-get install libboost-all-dev -y 23 | - sudo apt-get install aptitude -y 24 | - aptitude search boost -y 25 | - sudo apt-get install scons -y 26 | 27 | script: if [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then make ; fi 28 | 29 | addons: 30 | coverity_scan: 31 | project: 32 | name: "toniz/async-or-coroutine-fastcgi" 33 | description: "Build submitted via Travis CI" 34 | notification_email: toniz7960@gmail.com 35 | build_command_prepend: "scons -c" 36 | build_command: "scons" 37 | branch_pattern: master 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 toniz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /SConstruct: -------------------------------------------------------------------------------- 1 | SConscript(['mucgi/SConstruct']) 2 | SConscript(['cocgi/SConstruct']) 3 | 4 | -------------------------------------------------------------------------------- /cocgi/README.md: -------------------------------------------------------------------------------- 1 | # Coroutine Fastcgi 2 | 3 | `cocgi` is a coroutine fastcgi using Tencent Libco Library. 4 | Use Muduo Buffer.cpp for tcp receive buffer. 5 | Use Some Cgicc Files to parse http request. 6 | Modify the [BackendProc Class](backend.cpp) then You can pass the http request to back-end service. 7 | 8 | --- 9 | 10 | ## INSTALL 11 | ```sh 12 | yum install scons -y 13 | scons 14 | ``` 15 | 16 | __Or run:__ 17 | ```sh 18 | sh make.sh 19 | ``` 20 | 21 | ## Usage 22 | ```sh 23 | ./cocgi [IP] [PORT] [TASK_COUNT] [PROCESS_COUNT] 24 | ./cocgi [IP] [PORT] [TASK_COUNT] [PROCESS_COUNT] -d # daemonize mode 25 | ``` 26 | 27 | __Linux Version > 3.9, support for the SO_REUSEPORT socket option. We can add process on runtime.__ 28 | ```sh 29 | ./cocgi 127.0.0.1 6888 30 1 -d 30 | ./cocgi 127.0.0.1 6888 30 1 -d 31 | ./cocgi 127.0.0.1 6888 30 1 -d 32 | ./cocgi 127.0.0.1 6888 30 1 -d 33 | ... 34 | ``` 35 | 36 | * [nginx configure](/doc/nginx_configure.conf) 37 | > cocgi is a synchronize model, must use short-link. 38 | 39 | * Test 40 | ![测试](/doc/image/last02.png) 41 | 42 | 43 | > Test on Centos 6/7 44 | 45 | -------------------------------------------------------------------------------- /cocgi/SConstruct: -------------------------------------------------------------------------------- 1 | env = Environment() 2 | 3 | env.Append(CPPDEFINES = ['_LINUX_OS_']) 4 | 5 | env.Append(CPPFLAGS=[ '-fPIC', 6 | '-DLINUX', 7 | '-pipe', 8 | '-c', 9 | '-fno-inline', 10 | '-g', 11 | '-fno-strict-aliasing', 12 | '-O2', 13 | '-export-dynamic', 14 | '-Wall', 15 | '-D_GNU_SOURCE', 16 | '-D_REENTRANT', 17 | '-m64', 18 | '-Wno-deprecated' 19 | ]) 20 | 21 | 22 | env.Append(CPPPATH = ['.']) 23 | 24 | env.Append(LIBPATH = ['./', 25 | '/usr/lib', 26 | '/usr/lib64/', 27 | '/usr/local/lib', 28 | ]) 29 | 30 | env.Append(RPATH = ['/usr/lib64/', '/usr/lib', '/usr/local/lib']) 31 | 32 | SharedObject(target = 'libco/coctx_swap.o', source = 'libco/coctx_swap.S') 33 | 34 | env.Append(LIBS = ['pthread', 'dl']) 35 | 36 | coCgi = env.Program('cocgi', [ 37 | 'libco/co_epoll.cpp', 38 | 'libco/co_routine.cpp', 39 | 'libco/co_hook_sys_call.cpp', 40 | 'libco/coctx.cpp', 41 | 'libco/coctx_swap.o', 42 | 'cgicc_lib/CgiUtils.cpp', 43 | 'cgicc_lib/FormEntry.cpp', 44 | 'cgicc_lib/FormFile.cpp', 45 | 'cgicc_lib/HTTPCookie.cpp', 46 | 'cgicc_lib/MStreamable.cpp', 47 | 'cgicc_lib/Cgicc.cpp', 48 | 'muduo_lib/Buffer.cpp', 49 | 'backend.cpp', 50 | 'fastcgi.cpp', 51 | 'main.cpp', 52 | ]) 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /cocgi/backend.cpp: -------------------------------------------------------------------------------- 1 | #include "backend.h" 2 | #include 3 | 4 | std::string BackendProc::printRequest(ParamMap &qmap, ParamMap &header) 5 | { 6 | for (ParamMap::iterator it = qmap.begin(); it != qmap.end(); it++) 7 | { 8 | printf("Param: [%s] ==> [%s] \n", it->first.c_str(), it->second.c_str()); 9 | } 10 | 11 | for (ParamMap::iterator it = header.begin(); it != header.end(); it++) 12 | { 13 | printf("Header:[%s] ==> [%s] \n", it->first.c_str(), it->second.c_str()); 14 | } 15 | 16 | std::string content = "OK!!"; 17 | std::string resp = "Content-Type: text/html; charset=UTF-8\r\n"; 18 | resp += "Content-Length: "; 19 | resp += content.length(); 20 | resp += "\r\n\r\n"; 21 | resp += content; 22 | 23 | return resp; 24 | } 25 | 26 | -------------------------------------------------------------------------------- /cocgi/backend.h: -------------------------------------------------------------------------------- 1 | #ifndef _BACKEND_PROC_H__ 2 | #define _BACKEND_PROC_H__ 3 | #include "type.h" 4 | 5 | class BackendProc 6 | { 7 | public: 8 | std::string printRequest(ParamMap &qmap, ParamMap &header); 9 | 10 | 11 | }; 12 | 13 | 14 | 15 | 16 | #endif /*_BACKEND_PROC_H__*/ 17 | 18 | -------------------------------------------------------------------------------- /cocgi/cgicc_lib/FormEntry.cpp: -------------------------------------------------------------------------------- 1 | /* -*-mode:c++; c-file-style: "gnu";-*- */ 2 | /* 3 | * $Id: FormEntry.cpp,v 1.13 2007/07/02 18:48:18 sebdiaz Exp $ 4 | * 5 | * Copyright (C) 1996 - 2004 Stephen F. Booth 6 | * 2007 Sebastien DIAZ 7 | * Part of the GNU cgicc library, http://www.gnu.org/software/cgicc 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 3 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA 22 | */ 23 | 24 | #ifdef __GNUG__ 25 | # pragma implementation 26 | #endif 27 | 28 | #include 29 | #include 30 | 31 | #include "cgicc_lib/FormEntry.h" 32 | 33 | // local macro for integer maximum 34 | #define MAX(a, b) ((a) > (b) ? (a) : (b)) 35 | 36 | cgicc::FormEntry& 37 | cgicc::FormEntry::operator= (const FormEntry& entry) 38 | { 39 | fName = entry.fName; 40 | fValue = entry.fValue; 41 | 42 | return *this; 43 | } 44 | 45 | long 46 | cgicc::FormEntry::getIntegerValue(long min, 47 | long max) const 48 | { 49 | long value = std::atol(fValue.c_str()); 50 | 51 | if(value > max) 52 | value = max; 53 | else if(value < min) 54 | value = min; 55 | 56 | return value; 57 | } 58 | 59 | long 60 | cgicc::FormEntry::getIntegerValue(long min, 61 | long max, 62 | bool& bounded) const 63 | { 64 | long value = std::atol(fValue.c_str()); 65 | 66 | bounded = false; 67 | 68 | if(value > max) { 69 | value = max; 70 | bounded = true; 71 | } 72 | else if(value < min) { 73 | value = min; 74 | bounded = true; 75 | } 76 | 77 | return value; 78 | } 79 | 80 | double 81 | cgicc::FormEntry::getDoubleValue(double min, 82 | double max) const 83 | { 84 | double value = std::atof(fValue.c_str()); 85 | if(value > max) 86 | value = max; 87 | else if(value < min) 88 | value = min; 89 | 90 | return value; 91 | } 92 | 93 | double 94 | cgicc::FormEntry::getDoubleValue(double min, 95 | double max, 96 | bool& bounded) const 97 | { 98 | double value = std::atof(fValue.c_str()); 99 | 100 | bounded = false; 101 | 102 | if(value > max) { 103 | value = max; 104 | bounded = true; 105 | } 106 | else if(value < min) { 107 | value = min; 108 | bounded = true; 109 | } 110 | 111 | return value; 112 | } 113 | 114 | std::string 115 | cgicc::FormEntry::makeString(std::string::size_type maxLen, 116 | bool allowNewlines) const 117 | { 118 | std::string::size_type len = 0; 119 | std::string::size_type avail = maxLen; 120 | std::string::size_type crCount = 0; 121 | std::string::size_type lfCount = 0; 122 | std::string::const_iterator src = fValue.begin(); 123 | std::string::const_iterator lim = fValue.end(); 124 | std::string dst; 125 | 126 | 127 | while(src != lim && len < avail) { 128 | 129 | // handle newlines 130 | if('\r' == *src || '\n' == *src) { 131 | crCount = 0; 132 | lfCount = 0; 133 | 134 | // Count the number of each kind of line break ('\r' and '\n') 135 | while( ('\r' == *src || '\n' == *src) && (src != lim)) { 136 | if('\r' == *src) 137 | crCount++; 138 | else 139 | lfCount++; 140 | ++src; 141 | } 142 | 143 | // if newlines are allowed, add them 144 | if(allowNewlines) { 145 | // output the larger value 146 | int lfsAdd = MAX(crCount, lfCount); 147 | dst.append(lfsAdd, '\n'); 148 | len += lfsAdd; 149 | } 150 | } 151 | // just append all other characters 152 | else { 153 | dst.append(1, *src); 154 | ++len; 155 | ++src; 156 | } 157 | } 158 | 159 | return dst; 160 | } 161 | -------------------------------------------------------------------------------- /cocgi/cgicc_lib/FormFile.cpp: -------------------------------------------------------------------------------- 1 | /* -*-mode:c++; c-file-style: "gnu";-*- */ 2 | /* 3 | * $Id: FormFile.cpp,v 1.10 2007/07/02 18:48:18 sebdiaz Exp $ 4 | * 5 | * Copyright (C) 1996 - 2004 Stephen F. Booth 6 | * 2007 Sebastien DIAZ 7 | * Part of the GNU cgicc library, http://www.gnu.org/software/cgicc 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 3 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA 22 | */ 23 | 24 | #ifdef __GNUG__ 25 | # pragma implementation 26 | #endif 27 | 28 | #include "cgicc_lib/FormFile.h" 29 | #include "cgicc_lib/CgiUtils.h" 30 | 31 | cgicc::FormFile::FormFile(const std::string& name, 32 | const std::string& filename, 33 | const std::string& dataType, 34 | const std::string& data) 35 | : fName(name), 36 | fFilename(filename), 37 | fData(data) 38 | { 39 | fDataType = dataType.empty() ? std::string("text/plain") : dataType; 40 | } 41 | 42 | bool 43 | cgicc::FormFile::operator== (const FormFile& file) const 44 | { 45 | return (stringsAreEqual(fName, file.fName) && 46 | stringsAreEqual(fFilename, file.fFilename) && 47 | stringsAreEqual(fDataType, file.fDataType)); 48 | } 49 | 50 | cgicc::FormFile& 51 | cgicc::FormFile::operator= (const FormFile& file) 52 | { 53 | fName = file.fName; 54 | fFilename = file.fFilename; 55 | fDataType = file.fDataType; 56 | fData = file.fData; 57 | 58 | return *this; 59 | } 60 | 61 | void 62 | cgicc::FormFile::writeToStream(std::ostream& out) const 63 | { 64 | out.write(getData().data(), getDataLength()); 65 | } 66 | -------------------------------------------------------------------------------- /cocgi/cgicc_lib/HTTPCookie.cpp: -------------------------------------------------------------------------------- 1 | /* -*-mode:c++; c-file-style: "gnu";-*- */ 2 | /* 3 | * $Id: HTTPCookie.cpp,v 1.11 2009/01/18 13:58:25 sebdiaz Exp $ 4 | * 5 | * Copyright (C) 1996 - 2004 Stephen F. Booth 6 | * 2007 Sebastien DIAZ 7 | * Part of the GNU cgicc library, http://www.gnu.org/software/cgicc 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 3 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA 22 | */ 23 | 24 | #ifdef __GNUG__ 25 | # pragma implementation 26 | #endif 27 | 28 | #include "cgicc_lib/HTTPCookie.h" 29 | #include "cgicc_lib/CgiUtils.h" 30 | 31 | // ============================================================ 32 | // Class HTTPCookie 33 | // ============================================================ 34 | cgicc::HTTPCookie::HTTPCookie() 35 | : fMaxAge(0), 36 | fSecure(false), 37 | fRemoved(false) 38 | {} 39 | 40 | cgicc::HTTPCookie::HTTPCookie(const std::string& name, 41 | const std::string& value) 42 | : fName(name), 43 | fValue(value), 44 | fMaxAge(0), 45 | fSecure(false), 46 | fRemoved(false) 47 | {} 48 | 49 | cgicc::HTTPCookie::HTTPCookie(const std::string& name, 50 | const std::string& value, 51 | const std::string& comment, 52 | const std::string& domain, 53 | unsigned long maxAge, 54 | const std::string& path, 55 | bool secure) 56 | : fName(name), 57 | fValue(value), 58 | fComment(comment), 59 | fDomain(domain), 60 | fMaxAge(maxAge), 61 | fPath(path), 62 | fSecure(secure), 63 | fRemoved(false) 64 | {} 65 | 66 | cgicc::HTTPCookie::HTTPCookie(const HTTPCookie& cookie) 67 | : MStreamable(), 68 | fName(cookie.fName), 69 | fValue(cookie.fValue), 70 | fComment(cookie.fComment), 71 | fDomain(cookie.fDomain), 72 | fMaxAge(cookie.fMaxAge), 73 | fPath(cookie.fPath), 74 | fSecure(cookie.fSecure), 75 | fRemoved(cookie.fRemoved) 76 | {} 77 | 78 | cgicc::HTTPCookie::~HTTPCookie() 79 | {} 80 | 81 | bool 82 | cgicc::HTTPCookie::operator== (const HTTPCookie& cookie) const 83 | { 84 | return (stringsAreEqual(fName, cookie.fName) 85 | && stringsAreEqual(fValue, cookie.fValue) 86 | && stringsAreEqual(fComment, cookie.fComment) 87 | && stringsAreEqual(fDomain, cookie.fDomain) 88 | && fMaxAge == cookie.fMaxAge 89 | && stringsAreEqual(fPath, cookie.fPath) 90 | && fSecure == cookie.fSecure 91 | && fRemoved == cookie.fRemoved); 92 | } 93 | 94 | void 95 | cgicc::HTTPCookie::render(std::ostream& out) const 96 | { 97 | out << "Set-Cookie:" << fName << '=' << fValue; 98 | if(false == fComment.empty()) 99 | out << "; Comment=" << fComment; 100 | if(false == fDomain.empty()) 101 | out << "; Domain=" << fDomain; 102 | if(fRemoved) 103 | out << "; Expires=Fri, 01-Jan-1971 01:00:00 GMT;"; 104 | else if(0 != fMaxAge) 105 | out << "; Max-Age=" << fMaxAge; 106 | if(false == fPath.empty()) 107 | out << "; Path=" << fPath; 108 | if(true == fSecure) 109 | out << "; Secure"; 110 | 111 | out << "; Version=1"; 112 | } 113 | -------------------------------------------------------------------------------- /cocgi/cgicc_lib/MStreamable.cpp: -------------------------------------------------------------------------------- 1 | /* -*-mode:c++; c-file-style: "gnu";-*- */ 2 | /* 3 | * $Id: MStreamable.cpp,v 1.9 2007/07/02 18:48:19 sebdiaz Exp $ 4 | * 5 | * Copyright (C) 1996 - 2004 Stephen F. Booth 6 | * 2007 Sebastien DIAZ 7 | * Part of the GNU cgicc library, http://www.gnu.org/software/cgicc 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 3 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA 22 | */ 23 | 24 | #ifdef __GNUG__ 25 | # pragma implementation 26 | #endif 27 | 28 | #include "cgicc_lib/MStreamable.h" 29 | 30 | // ============================================================ 31 | // Class MStreamable 32 | // ============================================================ 33 | std::ostream& 34 | cgicc::operator<<(std::ostream& out, 35 | const MStreamable& obj) 36 | { 37 | obj.render(out); 38 | return out; 39 | } 40 | -------------------------------------------------------------------------------- /cocgi/cgicc_lib/MStreamable.h: -------------------------------------------------------------------------------- 1 | /* -*-mode:c++; c-file-style: "gnu";-*- */ 2 | /* 3 | * $Id: MStreamable.h,v 1.12 2007/07/02 18:48:19 sebdiaz Exp $ 4 | * 5 | * Copyright (C) 1996 - 2004 Stephen F. Booth 6 | * 2007 Sebastien DIAZ 7 | * Part of the GNU cgicc library, http://www.gnu.org/software/cgicc 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 3 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA 22 | */ 23 | 24 | #ifndef _MSTREAMABLE_H_ 25 | #define _MSTREAMABLE_H_ 1 26 | 27 | #ifdef __GNUG__ 28 | # pragma interface 29 | #endif 30 | 31 | /*! \file MStreamable.h 32 | * \brief Abstract base class for all streamable objects. 33 | * 34 | * A streamable object is an object that can be written to an \c 35 | * ostream using the \c << operator. 36 | */ 37 | 38 | #include 39 | 40 | namespace cgicc { 41 | 42 | class MStreamable; 43 | 44 | /*! 45 | * Prototype for overloading streaming operator 46 | * \param out The ostream to which to write 47 | * \param obj The MStreamable object to write 48 | * \return A reference to \c out 49 | */ 50 | std::ostream& 51 | operator<<(std::ostream& out, const MStreamable& obj); 52 | 53 | // ============================================================ 54 | // Class MStreamable 55 | // ============================================================ 56 | 57 | /*! \class MStreamable MStreamable.h cgicc/MStreamable.h 58 | * \brief Mix-in streamable interface. 59 | * 60 | * Abstract mix-in class which makes classes streamable via 61 | * the \c << operator. 62 | * Written in the spirit of a Java interface. 63 | */ 64 | class MStreamable 65 | { 66 | 67 | friend std::ostream& 68 | operator<<(std::ostream& out, const MStreamable& obj); 69 | 70 | public: 71 | /*! 72 | * \brief Empty constructor 73 | * 74 | */ 75 | inline MStreamable() 76 | {} 77 | 78 | /*! 79 | * \brief Empty destructor 80 | * 81 | */ 82 | inline virtual ~MStreamable() 83 | {} 84 | 85 | /*! 86 | * \brief Write this object to a stream. 87 | * 88 | * Subclasses must implement this function. 89 | * \param out The ostream to which to write. 90 | */ 91 | virtual void 92 | render(std::ostream& out) const = 0; 93 | }; 94 | 95 | } // namespace cgicc 96 | 97 | #endif /* ! _MSTREAMABLE_H_ */ 98 | -------------------------------------------------------------------------------- /cocgi/fastcgi.h: -------------------------------------------------------------------------------- 1 | // Taken from muduo fastcgi exmaple 2 | // https://github.com/chenshuo/muduo 3 | #ifndef FASTCGI_FASTCGI_H 4 | #define FASTCGI_FASTCGI_H 5 | 6 | #include "type.h" 7 | #include "muduo_lib/Buffer.h" 8 | 9 | // one FastCgiCodec per TcpConnection 10 | // one Tcp Connection per Coroutine 11 | // there is no concurrent requests of one connection. 12 | class FastCgiCodec 13 | { 14 | public: 15 | FastCgiCodec() 16 | { 17 | m_gotRequest = false; 18 | m_keepConn = false; 19 | }; 20 | 21 | int readData(int &fd); 22 | int doRequest(int &fd); 23 | void respond(std::string &out, muduo::net::Buffer* response); 24 | 25 | private: 26 | struct FcgiRecordHeader; 27 | bool parseFcgiPackage(); 28 | bool onBeginRequest(const FcgiRecordHeader& header, const muduo::net::Buffer* buf); 29 | void onStdin(const char* content, uint16_t length); 30 | bool onParams(const char* content, uint16_t length); 31 | bool parseAllParams(); 32 | uint32_t readLen(); 33 | 34 | static void endStdout(muduo::net::Buffer* buf); 35 | static void endRequest(muduo::net::Buffer* buf); 36 | 37 | bool m_gotRequest; 38 | bool m_keepConn; 39 | muduo::net::Buffer m_buf; 40 | muduo::net::Buffer m_stdin; 41 | muduo::net::Buffer m_paramsStream; 42 | ParamMap m_params; 43 | 44 | const static unsigned kRecordHeader; 45 | }; 46 | 47 | #endif // FASTCGI_FASTCGI_H 48 | -------------------------------------------------------------------------------- /cocgi/libco/co_closure.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Libco available. 3 | 4 | * Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef __CO_CLOSURE_H__ 20 | #define __CO_CLOSURE_H__ 21 | struct stCoClosure_t 22 | { 23 | public: 24 | virtual void exec() = 0; 25 | }; 26 | 27 | //1.base 28 | //-- 1.1 comac_argc 29 | 30 | #define comac_get_args_cnt( ... ) comac_arg_n( __VA_ARGS__ ) 31 | #define comac_arg_n( _0,_1,_2,_3,_4,_5,_6,_7,N,...) N 32 | #define comac_args_seqs() 7,6,5,4,3,2,1,0 33 | #define comac_join_1( x,y ) x##y 34 | 35 | #define comac_argc( ... ) comac_get_args_cnt( 0,##__VA_ARGS__,comac_args_seqs() ) 36 | #define comac_join( x,y) comac_join_1( x,y ) 37 | 38 | //-- 1.2 repeat 39 | #define repeat_0( fun,a,... ) 40 | #define repeat_1( fun,a,... ) fun( 1,a,__VA_ARGS__ ) repeat_0( fun,__VA_ARGS__ ) 41 | #define repeat_2( fun,a,... ) fun( 2,a,__VA_ARGS__ ) repeat_1( fun,__VA_ARGS__ ) 42 | #define repeat_3( fun,a,... ) fun( 3,a,__VA_ARGS__ ) repeat_2( fun,__VA_ARGS__ ) 43 | #define repeat_4( fun,a,... ) fun( 4,a,__VA_ARGS__ ) repeat_3( fun,__VA_ARGS__ ) 44 | #define repeat_5( fun,a,... ) fun( 5,a,__VA_ARGS__ ) repeat_4( fun,__VA_ARGS__ ) 45 | #define repeat_6( fun,a,... ) fun( 6,a,__VA_ARGS__ ) repeat_5( fun,__VA_ARGS__ ) 46 | 47 | #define repeat( n,fun,... ) comac_join( repeat_,n )( fun,__VA_ARGS__) 48 | 49 | //2.implement 50 | #if __cplusplus <= 199711L 51 | #define decl_typeof( i,a,... ) typedef typeof( a ) typeof_##a; 52 | #else 53 | #define decl_typeof( i,a,... ) typedef decltype( a ) typeof_##a; 54 | #endif 55 | #define impl_typeof( i,a,... ) typeof_##a & a; 56 | #define impl_typeof_cpy( i,a,... ) typeof_##a a; 57 | #define con_param_typeof( i,a,... ) typeof_##a & a##r, 58 | #define param_init_typeof( i,a,... ) a(a##r), 59 | 60 | 61 | //2.1 reference 62 | 63 | #define co_ref( name,... )\ 64 | repeat( comac_argc(__VA_ARGS__) ,decl_typeof,__VA_ARGS__ )\ 65 | class type_##name\ 66 | {\ 67 | public:\ 68 | repeat( comac_argc(__VA_ARGS__) ,impl_typeof,__VA_ARGS__ )\ 69 | int _member_cnt;\ 70 | type_##name( \ 71 | repeat( comac_argc(__VA_ARGS__),con_param_typeof,__VA_ARGS__ ) ... ): \ 72 | repeat( comac_argc(__VA_ARGS__),param_init_typeof,__VA_ARGS__ ) _member_cnt(comac_argc(__VA_ARGS__)) \ 73 | {}\ 74 | } name( __VA_ARGS__ ) ; 75 | 76 | 77 | //2.2 function 78 | 79 | #define co_func(name,...)\ 80 | repeat( comac_argc(__VA_ARGS__) ,decl_typeof,__VA_ARGS__ )\ 81 | class name:public stCoClosure_t\ 82 | {\ 83 | public:\ 84 | repeat( comac_argc(__VA_ARGS__) ,impl_typeof_cpy,__VA_ARGS__ )\ 85 | int _member_cnt;\ 86 | public:\ 87 | name( repeat( comac_argc(__VA_ARGS__),con_param_typeof,__VA_ARGS__ ) ... ): \ 88 | repeat( comac_argc(__VA_ARGS__),param_init_typeof,__VA_ARGS__ ) _member_cnt(comac_argc(__VA_ARGS__))\ 89 | {}\ 90 | void exec() 91 | 92 | #define co_func_end } 93 | 94 | 95 | #endif 96 | 97 | -------------------------------------------------------------------------------- /cocgi/libco/co_epoll.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Libco available. 3 | 4 | * Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef __CO_EPOLL_H__ 20 | #define __CO_EPOLL_H__ 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #if !defined( __APPLE__ ) && !defined( __FreeBSD__ ) 30 | 31 | #include 32 | 33 | struct co_epoll_res 34 | { 35 | int size; 36 | struct epoll_event *events; 37 | struct kevent *eventlist; 38 | }; 39 | int co_epoll_wait( int epfd,struct co_epoll_res *events,int maxevents,int timeout ); 40 | int co_epoll_ctl( int epfd,int op,int fd,struct epoll_event * ); 41 | int co_epoll_create( int size ); 42 | struct co_epoll_res *co_epoll_res_alloc( int n ); 43 | void co_epoll_res_free( struct co_epoll_res * ); 44 | 45 | #else 46 | 47 | #include 48 | enum EPOLL_EVENTS 49 | { 50 | EPOLLIN = 0X001, 51 | EPOLLPRI = 0X002, 52 | EPOLLOUT = 0X004, 53 | 54 | EPOLLERR = 0X008, 55 | EPOLLHUP = 0X010, 56 | 57 | EPOLLRDNORM = 0x40, 58 | EPOLLWRNORM = 0x004, 59 | }; 60 | #define EPOLL_CTL_ADD 1 61 | #define EPOLL_CTL_DEL 2 62 | #define EPOLL_CTL_MOD 3 63 | typedef union epoll_data 64 | { 65 | void *ptr; 66 | int fd; 67 | uint32_t u32; 68 | uint64_t u64; 69 | 70 | } epoll_data_t; 71 | 72 | struct epoll_event 73 | { 74 | uint32_t events; 75 | epoll_data_t data; 76 | }; 77 | 78 | struct co_epoll_res 79 | { 80 | int size; 81 | struct epoll_event *events; 82 | struct kevent *eventlist; 83 | }; 84 | int co_epoll_wait( int epfd,struct co_epoll_res *events,int maxevents,int timeout ); 85 | int co_epoll_ctl( int epfd,int op,int fd,struct epoll_event * ); 86 | int co_epoll_create( int size ); 87 | struct co_epoll_res *co_epoll_res_alloc( int n ); 88 | void co_epoll_res_free( struct co_epoll_res * ); 89 | 90 | #endif 91 | #endif 92 | 93 | 94 | -------------------------------------------------------------------------------- /cocgi/libco/co_hook_sys_call.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toniz/fastcgi-async-or-coroutine/6908ce75d6a9abf21a519fd661d4fa940cd14e9f/cocgi/libco/co_hook_sys_call.cpp -------------------------------------------------------------------------------- /cocgi/libco/co_routine.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Libco available. 3 | 4 | * Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef __CO_ROUTINE_H__ 20 | #define __CO_ROUTINE_H__ 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | //1.struct 27 | 28 | struct stCoRoutine_t; 29 | struct stShareStack_t; 30 | 31 | struct stCoRoutineAttr_t 32 | { 33 | int stack_size; 34 | stShareStack_t* share_stack; 35 | stCoRoutineAttr_t() 36 | { 37 | stack_size = 128 * 1024; 38 | share_stack = NULL; 39 | } 40 | }__attribute__ ((packed)); 41 | 42 | struct stCoEpoll_t; 43 | typedef int (*pfn_co_eventloop_t)(void *); 44 | typedef void *(*pfn_co_routine_t)( void * ); 45 | 46 | //2.co_routine 47 | 48 | int co_create( stCoRoutine_t **co,const stCoRoutineAttr_t *attr,void *(*routine)(void*),void *arg ); 49 | void co_resume( stCoRoutine_t *co ); 50 | void co_yield( stCoRoutine_t *co ); 51 | void co_yield_ct(); //ct = current thread 52 | void co_release( stCoRoutine_t *co ); 53 | 54 | stCoRoutine_t *co_self(); 55 | 56 | int co_poll( stCoEpoll_t *ctx,struct pollfd fds[], nfds_t nfds, int timeout_ms ); 57 | void co_eventloop( stCoEpoll_t *ctx,pfn_co_eventloop_t pfn,void *arg ); 58 | 59 | //3.specific 60 | 61 | int co_setspecific( pthread_key_t key, const void *value ); 62 | void * co_getspecific( pthread_key_t key ); 63 | 64 | //4.event 65 | 66 | stCoEpoll_t * co_get_epoll_ct(); //ct = current thread 67 | 68 | //5.hook syscall ( poll/read/write/recv/send/recvfrom/sendto ) 69 | 70 | void co_enable_hook_sys(); 71 | void co_disable_hook_sys(); 72 | bool co_is_enable_sys_hook(); 73 | 74 | //6.sync 75 | struct stCoCond_t; 76 | 77 | stCoCond_t *co_cond_alloc(); 78 | int co_cond_free( stCoCond_t * cc ); 79 | 80 | int co_cond_signal( stCoCond_t * ); 81 | int co_cond_broadcast( stCoCond_t * ); 82 | int co_cond_timedwait( stCoCond_t *,int timeout_ms ); 83 | 84 | //7.share stack 85 | stShareStack_t* co_alloc_sharestack(int iCount, int iStackSize); 86 | 87 | //8.init envlist for hook get/set env 88 | void co_set_env_list( const char *name[],size_t cnt); 89 | 90 | void co_log_err( const char *fmt,... ); 91 | #endif 92 | 93 | -------------------------------------------------------------------------------- /cocgi/libco/co_routine_inner.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Libco available. 3 | 4 | * Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | 20 | #ifndef __CO_ROUTINE_INNER_H__ 21 | 22 | #include "co_routine.h" 23 | #include "coctx.h" 24 | struct stCoRoutineEnv_t; 25 | struct stCoSpec_t 26 | { 27 | void *value; 28 | }; 29 | 30 | struct stStackMem_t 31 | { 32 | stCoRoutine_t* occupy_co; 33 | int stack_size; 34 | char* stack_bp; //stack_buffer + stack_size 35 | char* stack_buffer; 36 | 37 | }; 38 | 39 | struct stShareStack_t 40 | { 41 | unsigned int alloc_idx; 42 | int stack_size; 43 | int count; 44 | stStackMem_t** stack_array; 45 | }; 46 | 47 | 48 | 49 | struct stCoRoutine_t 50 | { 51 | stCoRoutineEnv_t *env; 52 | pfn_co_routine_t pfn; 53 | void *arg; 54 | coctx_t ctx; 55 | 56 | char cStart; 57 | char cEnd; 58 | char cIsMain; 59 | char cEnableSysHook; 60 | char cIsShareStack; 61 | 62 | void *pvEnv; 63 | 64 | //char sRunStack[ 1024 * 128 ]; 65 | stStackMem_t* stack_mem; 66 | 67 | 68 | //save satck buffer while confilct on same stack_buffer; 69 | char* stack_sp; 70 | unsigned int save_size; 71 | char* save_buffer; 72 | 73 | stCoSpec_t aSpec[1024]; 74 | 75 | }; 76 | 77 | 78 | 79 | //1.env 80 | void co_init_curr_thread_env(); 81 | stCoRoutineEnv_t * co_get_curr_thread_env(); 82 | 83 | //2.coroutine 84 | void co_free( stCoRoutine_t * co ); 85 | void co_yield_env( stCoRoutineEnv_t *env ); 86 | 87 | //3.func 88 | 89 | 90 | 91 | //----------------------------------------------------------------------------------------------- 92 | 93 | struct stTimeout_t; 94 | struct stTimeoutItem_t ; 95 | 96 | stTimeout_t *AllocTimeout( int iSize ); 97 | void FreeTimeout( stTimeout_t *apTimeout ); 98 | int AddTimeout( stTimeout_t *apTimeout,stTimeoutItem_t *apItem ,uint64_t allNow ); 99 | 100 | struct stCoEpoll_t; 101 | stCoEpoll_t * AllocEpoll(); 102 | void FreeEpoll( stCoEpoll_t *ctx ); 103 | 104 | stCoRoutine_t * GetCurrThreadCo(); 105 | void SetEpoll( stCoRoutineEnv_t *env,stCoEpoll_t *ev ); 106 | 107 | typedef void (*pfnCoRoutineFunc_t)(); 108 | 109 | #endif 110 | 111 | #define __CO_ROUTINE_INNER_H__ 112 | -------------------------------------------------------------------------------- /cocgi/libco/co_routine_specific.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Libco available. 3 | 4 | * Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #pragma once 20 | #include 21 | #include 22 | 23 | /* 24 | invoke only once in the whole program 25 | CoRoutineSetSpecificCallBack(CoRoutineGetSpecificFunc_t pfnGet,CoRoutineSetSpecificFunc_t pfnSet) 26 | 27 | struct MyData_t 28 | { 29 | int iValue; 30 | char szValue[100]; 31 | }; 32 | CO_ROUTINE_SPECIFIC( MyData_t,__routine ); 33 | 34 | int main() 35 | { 36 | CoRoutineSetSpecificCallBack( co_getspecific,co_setspecific ); 37 | 38 | __routine->iValue = 10; 39 | strcpy( __routine->szValue,"hello world" ); 40 | 41 | return 0; 42 | } 43 | */ 44 | extern int co_setspecific( pthread_key_t key, const void *value ); 45 | extern void * co_getspecific( pthread_key_t key ); 46 | 47 | #define CO_ROUTINE_SPECIFIC( name,y ) \ 48 | \ 49 | static pthread_once_t _routine_once_##name = PTHREAD_ONCE_INIT; \ 50 | static pthread_key_t _routine_key_##name;\ 51 | static int _routine_init_##name = 0;\ 52 | static void _routine_make_key_##name() \ 53 | {\ 54 | (void) pthread_key_create(&_routine_key_##name, NULL); \ 55 | }\ 56 | template \ 57 | class clsRoutineData_routine_##name\ 58 | {\ 59 | public:\ 60 | inline T *operator->()\ 61 | {\ 62 | if( !_routine_init_##name ) \ 63 | {\ 64 | pthread_once( &_routine_once_##name,_routine_make_key_##name );\ 65 | _routine_init_##name = 1;\ 66 | }\ 67 | T* p = (T*)co_getspecific( _routine_key_##name );\ 68 | if( !p )\ 69 | {\ 70 | p = (T*)calloc(1,sizeof( T ));\ 71 | int ret = co_setspecific( _routine_key_##name,p) ;\ 72 | if ( ret )\ 73 | {\ 74 | if ( p )\ 75 | {\ 76 | free(p);\ 77 | p = NULL;\ 78 | }\ 79 | }\ 80 | }\ 81 | return p;\ 82 | }\ 83 | };\ 84 | \ 85 | static clsRoutineData_routine_##name y; 86 | 87 | -------------------------------------------------------------------------------- /cocgi/libco/coctx.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Libco available. 3 | 4 | * Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include "coctx.h" 20 | #include 21 | 22 | 23 | #define ESP 0 24 | #define EIP 1 25 | #define EAX 2 26 | #define ECX 3 27 | // ----------- 28 | #define RSP 0 29 | #define RIP 1 30 | #define RBX 2 31 | #define RDI 3 32 | #define RSI 4 33 | 34 | #define RBP 5 35 | #define R12 6 36 | #define R13 7 37 | #define R14 8 38 | #define R15 9 39 | #define RDX 10 40 | #define RCX 11 41 | #define R8 12 42 | #define R9 13 43 | 44 | 45 | //----- -------- 46 | // 32 bit 47 | // | regs[0]: ret | 48 | // | regs[1]: ebx | 49 | // | regs[2]: ecx | 50 | // | regs[3]: edx | 51 | // | regs[4]: edi | 52 | // | regs[5]: esi | 53 | // | regs[6]: ebp | 54 | // | regs[7]: eax | = esp 55 | enum 56 | { 57 | kEIP = 0, 58 | kESP = 7, 59 | }; 60 | 61 | //------------- 62 | // 64 bit 63 | //low | regs[0]: r15 | 64 | // | regs[1]: r14 | 65 | // | regs[2]: r13 | 66 | // | regs[3]: r12 | 67 | // | regs[4]: r9 | 68 | // | regs[5]: r8 | 69 | // | regs[6]: rbp | 70 | // | regs[7]: rdi | 71 | // | regs[8]: rsi | 72 | // | regs[9]: ret | //ret func addr 73 | // | regs[10]: rdx | 74 | // | regs[11]: rcx | 75 | // | regs[12]: rbx | 76 | //hig | regs[13]: rsp | 77 | enum 78 | { 79 | kRDI = 7, 80 | kRSI = 8, 81 | kRETAddr = 9, 82 | kRSP = 13, 83 | }; 84 | 85 | //64 bit 86 | extern "C" 87 | { 88 | extern void coctx_swap( coctx_t *,coctx_t* ) asm("coctx_swap"); 89 | }; 90 | #if defined(__i386__) 91 | int coctx_init( coctx_t *ctx ) 92 | { 93 | memset( ctx,0,sizeof(*ctx)); 94 | return 0; 95 | } 96 | int coctx_make( coctx_t *ctx,coctx_pfn_t pfn,const void *s,const void *s1 ) 97 | { 98 | //make room for coctx_param 99 | char *sp = ctx->ss_sp + ctx->ss_size - sizeof(coctx_param_t); 100 | sp = (char*)((unsigned long)sp & -16L); 101 | 102 | 103 | coctx_param_t* param = (coctx_param_t*)sp ; 104 | param->s1 = s; 105 | param->s2 = s1; 106 | 107 | memset(ctx->regs, 0, sizeof(ctx->regs)); 108 | 109 | ctx->regs[ kESP ] = (char*)(sp) - sizeof(void*); 110 | ctx->regs[ kEIP ] = (char*)pfn; 111 | 112 | return 0; 113 | } 114 | #elif defined(__x86_64__) 115 | int coctx_make( coctx_t *ctx,coctx_pfn_t pfn,const void *s,const void *s1 ) 116 | { 117 | char *sp = ctx->ss_sp + ctx->ss_size; 118 | sp = (char*) ((unsigned long)sp & -16LL ); 119 | 120 | memset(ctx->regs, 0, sizeof(ctx->regs)); 121 | 122 | ctx->regs[ kRSP ] = sp - 8; 123 | 124 | ctx->regs[ kRETAddr] = (char*)pfn; 125 | 126 | ctx->regs[ kRDI ] = (char*)s; 127 | ctx->regs[ kRSI ] = (char*)s1; 128 | return 0; 129 | } 130 | 131 | int coctx_init( coctx_t *ctx ) 132 | { 133 | memset( ctx,0,sizeof(*ctx)); 134 | return 0; 135 | } 136 | 137 | #endif 138 | 139 | -------------------------------------------------------------------------------- /cocgi/libco/coctx.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Libco available. 3 | 4 | * Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef __CO_CTX_H__ 20 | #define __CO_CTX_H__ 21 | #include 22 | typedef void* (*coctx_pfn_t)( void* s, void* s2 ); 23 | struct coctx_param_t 24 | { 25 | const void *s1; 26 | const void *s2; 27 | }; 28 | struct coctx_t 29 | { 30 | #if defined(__i386__) 31 | void *regs[ 8 ]; 32 | #else 33 | void *regs[ 14 ]; 34 | #endif 35 | size_t ss_size; 36 | char *ss_sp; 37 | 38 | }; 39 | 40 | int coctx_init( coctx_t *ctx ); 41 | int coctx_make( coctx_t *ctx,coctx_pfn_t pfn,const void *s,const void *s1 ); 42 | #endif 43 | -------------------------------------------------------------------------------- /cocgi/libco/coctx_swap.S: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Libco available. 3 | 4 | * Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | .globl coctx_swap 20 | #if !defined( __APPLE__ ) && !defined( __FreeBSD__ ) 21 | .type coctx_swap, @function 22 | #endif 23 | coctx_swap: 24 | 25 | #if defined(__i386__) 26 | leal 4(%esp), %eax //sp 27 | movl 4(%esp), %esp 28 | leal 32(%esp), %esp //parm a : ®s[7] + sizeof(void*) 29 | 30 | pushl %eax //esp ->parm a 31 | 32 | pushl %ebp 33 | pushl %esi 34 | pushl %edi 35 | pushl %edx 36 | pushl %ecx 37 | pushl %ebx 38 | pushl -4(%eax) 39 | 40 | 41 | movl 4(%eax), %esp //parm b -> ®s[0] 42 | 43 | popl %eax //ret func addr 44 | popl %ebx 45 | popl %ecx 46 | popl %edx 47 | popl %edi 48 | popl %esi 49 | popl %ebp 50 | popl %esp 51 | pushl %eax //set ret func addr 52 | 53 | xorl %eax, %eax 54 | ret 55 | 56 | #elif defined(__x86_64__) 57 | leaq 8(%rsp),%rax 58 | leaq 112(%rdi),%rsp 59 | pushq %rax 60 | pushq %rbx 61 | pushq %rcx 62 | pushq %rdx 63 | 64 | pushq -8(%rax) //ret func addr 65 | 66 | pushq %rsi 67 | pushq %rdi 68 | pushq %rbp 69 | pushq %r8 70 | pushq %r9 71 | pushq %r12 72 | pushq %r13 73 | pushq %r14 74 | pushq %r15 75 | 76 | movq %rsi, %rsp 77 | popq %r15 78 | popq %r14 79 | popq %r13 80 | popq %r12 81 | popq %r9 82 | popq %r8 83 | popq %rbp 84 | popq %rdi 85 | popq %rsi 86 | popq %rax //ret func addr 87 | popq %rdx 88 | popq %rcx 89 | popq %rbx 90 | popq %rsp 91 | pushq %rax 92 | 93 | xorl %eax, %eax 94 | ret 95 | #endif 96 | -------------------------------------------------------------------------------- /cocgi/make.sh: -------------------------------------------------------------------------------- 1 | #scons: Reading SConscript files ... 2 | #scons: done reading SConscript files. 3 | #scons: Building targets ... 4 | g++ -o backend.o -c -fPIC -DLINUX -pipe -c -fno-inline -g -fno-strict-aliasing -O2 -export-dynamic -Wall -D_GNU_SOURCE -D_REENTRANT -m64 -Wno-deprecated -D_LINUX_OS_ -I. backend.cpp 5 | g++ -o cgicc_lib/CgiUtils.o -c -fPIC -DLINUX -pipe -c -fno-inline -g -fno-strict-aliasing -O2 -export-dynamic -Wall -D_GNU_SOURCE -D_REENTRANT -m64 -Wno-deprecated -D_LINUX_OS_ -I. cgicc_lib/CgiUtils.cpp 6 | g++ -o cgicc_lib/Cgicc.o -c -fPIC -DLINUX -pipe -c -fno-inline -g -fno-strict-aliasing -O2 -export-dynamic -Wall -D_GNU_SOURCE -D_REENTRANT -m64 -Wno-deprecated -D_LINUX_OS_ -I. cgicc_lib/Cgicc.cpp 7 | g++ -o cgicc_lib/FormEntry.o -c -fPIC -DLINUX -pipe -c -fno-inline -g -fno-strict-aliasing -O2 -export-dynamic -Wall -D_GNU_SOURCE -D_REENTRANT -m64 -Wno-deprecated -D_LINUX_OS_ -I. cgicc_lib/FormEntry.cpp 8 | g++ -o cgicc_lib/FormFile.o -c -fPIC -DLINUX -pipe -c -fno-inline -g -fno-strict-aliasing -O2 -export-dynamic -Wall -D_GNU_SOURCE -D_REENTRANT -m64 -Wno-deprecated -D_LINUX_OS_ -I. cgicc_lib/FormFile.cpp 9 | g++ -o cgicc_lib/HTTPCookie.o -c -fPIC -DLINUX -pipe -c -fno-inline -g -fno-strict-aliasing -O2 -export-dynamic -Wall -D_GNU_SOURCE -D_REENTRANT -m64 -Wno-deprecated -D_LINUX_OS_ -I. cgicc_lib/HTTPCookie.cpp 10 | g++ -o cgicc_lib/MStreamable.o -c -fPIC -DLINUX -pipe -c -fno-inline -g -fno-strict-aliasing -O2 -export-dynamic -Wall -D_GNU_SOURCE -D_REENTRANT -m64 -Wno-deprecated -D_LINUX_OS_ -I. cgicc_lib/MStreamable.cpp 11 | g++ -o libco/co_epoll.o -c -fPIC -DLINUX -pipe -c -fno-inline -g -fno-strict-aliasing -O2 -export-dynamic -Wall -D_GNU_SOURCE -D_REENTRANT -m64 -Wno-deprecated -D_LINUX_OS_ -I. libco/co_epoll.cpp 12 | g++ -o libco/co_routine.o -c -fPIC -DLINUX -pipe -c -fno-inline -g -fno-strict-aliasing -O2 -export-dynamic -Wall -D_GNU_SOURCE -D_REENTRANT -m64 -Wno-deprecated -D_LINUX_OS_ -I. libco/co_routine.cpp 13 | g++ -o libco/co_hook_sys_call.o -c -fPIC -DLINUX -pipe -c -fno-inline -g -fno-strict-aliasing -O2 -export-dynamic -Wall -D_GNU_SOURCE -D_REENTRANT -m64 -Wno-deprecated -D_LINUX_OS_ -I. libco/co_hook_sys_call.cpp 14 | g++ -o libco/coctx.o -c -fPIC -DLINUX -pipe -c -fno-inline -g -fno-strict-aliasing -O2 -export-dynamic -Wall -D_GNU_SOURCE -D_REENTRANT -m64 -Wno-deprecated -D_LINUX_OS_ -I. libco/coctx.cpp 15 | gcc -c -o libco/coctx_swap.o libco/coctx_swap.S 16 | g++ -o muduo_lib/Buffer.o -c -fPIC -DLINUX -pipe -c -fno-inline -g -fno-strict-aliasing -O2 -export-dynamic -Wall -D_GNU_SOURCE -D_REENTRANT -m64 -Wno-deprecated -D_LINUX_OS_ -I. muduo_lib/Buffer.cpp 17 | g++ -o fastcgi.o -c -fPIC -DLINUX -pipe -c -fno-inline -g -fno-strict-aliasing -O2 -export-dynamic -Wall -D_GNU_SOURCE -D_REENTRANT -m64 -Wno-deprecated -D_LINUX_OS_ -I. fastcgi.cpp 18 | g++ -o main.o -c -fPIC -DLINUX -pipe -c -fno-inline -g -fno-strict-aliasing -O2 -export-dynamic -Wall -D_GNU_SOURCE -D_REENTRANT -m64 -Wno-deprecated -D_LINUX_OS_ -I. main.cpp 19 | g++ -o cocgi -Wl,-rpath=/usr/lib64/ -Wl,-rpath=/usr/lib -Wl,-rpath=/usr/local/lib libco/co_epoll.o libco/co_routine.o libco/co_hook_sys_call.o libco/coctx.o libco/coctx_swap.o cgicc_lib/CgiUtils.o cgicc_lib/FormEntry.o cgicc_lib/FormFile.o cgicc_lib/HTTPCookie.o cgicc_lib/MStreamable.o cgicc_lib/Cgicc.o muduo_lib/Buffer.o backend.o fastcgi.o main.o -L. -L/usr/lib -L/usr/lib64 -L/usr/local/lib -lpthread -ldl 20 | #scons: done building targets. 21 | -------------------------------------------------------------------------------- /cocgi/muduo_lib/Buffer.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | 10 | #include "Buffer.h" 11 | #include 12 | #include 13 | 14 | using namespace muduo; 15 | using namespace muduo::net; 16 | 17 | const char Buffer::kCRLF[] = "\r\n"; 18 | 19 | const size_t Buffer::kCheapPrepend; 20 | const size_t Buffer::kInitialSize; 21 | 22 | ssize_t Buffer::readFd(int fd, int* savedErrno) 23 | { 24 | // saved an ioctl()/FIONREAD call to tell how much to read 25 | char extrabuf[65536]; 26 | struct iovec vec[2]; 27 | const size_t writable = writableBytes(); 28 | vec[0].iov_base = begin()+writerIndex_; 29 | vec[0].iov_len = writable; 30 | vec[1].iov_base = extrabuf; 31 | vec[1].iov_len = sizeof extrabuf; 32 | // when there is enough space in this buffer, don't read into extrabuf. 33 | // when extrabuf is used, we read 128k-1 bytes at most. 34 | const int iovcnt = (writable < sizeof extrabuf) ? 2 : 1; 35 | ssize_t n = readv(fd, vec, iovcnt); 36 | if (n < 0) 37 | { 38 | *savedErrno = errno; 39 | } 40 | else if ((size_t)n <= writable) 41 | { 42 | writerIndex_ += n; 43 | } 44 | else 45 | { 46 | writerIndex_ = buffer_.size(); 47 | append(extrabuf, n - writable); 48 | } 49 | // if (n == writable + sizeof extrabuf) 50 | // { 51 | // goto line_30; 52 | // } 53 | return n; 54 | } 55 | 56 | -------------------------------------------------------------------------------- /cocgi/type.h: -------------------------------------------------------------------------------- 1 | #ifndef COCGI_TYPE_H 2 | #define COCGI_TYPE_H 3 | #include 4 | #include 5 | #include 6 | 7 | #define hton16(A) ((((uint16_t)(A) & 0xff00) >> 8) | \ 8 | (((uint16_t)(A) & 0x00ff) << 8)) 9 | #define hton32(A) ((((uint32_t)(A) & 0xff000000) >> 24) | \ 10 | (((uint32_t)(A) & 0x00ff0000) >> 8) | \ 11 | (((uint32_t)(A) & 0x0000ff00) << 8) | \ 12 | (((uint32_t)(A) & 0x000000ff) << 24)) 13 | #define hton64(A) (((((uint64_t)A)<<56) & 0xFF00000000000000ULL) | \ 14 | ((((uint64_t)A)<<40) & 0x00FF000000000000ULL) | \ 15 | ((((uint64_t)A)<<24) & 0x0000FF0000000000ULL) | \ 16 | ((((uint64_t)A)<< 8) & 0x000000FF00000000ULL) | \ 17 | ((((uint64_t)A)>> 8) & 0x00000000FF000000ULL) | \ 18 | ((((uint64_t)A)>>24) & 0x0000000000FF0000ULL) | \ 19 | ((((uint64_t)A)>>40) & 0x000000000000FF00ULL) | \ 20 | ((((uint64_t)A)>>56) & 0x00000000000000FFULL)) 21 | #define ntoh16 hton16 22 | #define ntoh32 hton32 23 | #define ntoh64 hton64 24 | 25 | typedef std::map ParamMap; 26 | 27 | enum error_code_e 28 | { 29 | ERR_OK = 0, 30 | ERR_SOCKET_READ, 31 | ERR_SOCKET_WRITE, 32 | ERR_SOCKET_FINISH, 33 | ERR_SOCKET_EAGAIN, 34 | }; 35 | 36 | #endif // COCGI_TYPE_H 37 | -------------------------------------------------------------------------------- /doc/image/code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toniz/fastcgi-async-or-coroutine/6908ce75d6a9abf21a519fd661d4fa940cd14e9f/doc/image/code.png -------------------------------------------------------------------------------- /doc/image/fireframe1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toniz/fastcgi-async-or-coroutine/6908ce75d6a9abf21a519fd661d4fa940cd14e9f/doc/image/fireframe1.png -------------------------------------------------------------------------------- /doc/image/fireframe2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toniz/fastcgi-async-or-coroutine/6908ce75d6a9abf21a519fd661d4fa940cd14e9f/doc/image/fireframe2.png -------------------------------------------------------------------------------- /doc/image/image001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toniz/fastcgi-async-or-coroutine/6908ce75d6a9abf21a519fd661d4fa940cd14e9f/doc/image/image001.png -------------------------------------------------------------------------------- /doc/image/image002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toniz/fastcgi-async-or-coroutine/6908ce75d6a9abf21a519fd661d4fa940cd14e9f/doc/image/image002.png -------------------------------------------------------------------------------- /doc/image/image003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toniz/fastcgi-async-or-coroutine/6908ce75d6a9abf21a519fd661d4fa940cd14e9f/doc/image/image003.png -------------------------------------------------------------------------------- /doc/image/image004.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toniz/fastcgi-async-or-coroutine/6908ce75d6a9abf21a519fd661d4fa940cd14e9f/doc/image/image004.png -------------------------------------------------------------------------------- /doc/image/image005.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toniz/fastcgi-async-or-coroutine/6908ce75d6a9abf21a519fd661d4fa940cd14e9f/doc/image/image005.png -------------------------------------------------------------------------------- /doc/image/image006.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toniz/fastcgi-async-or-coroutine/6908ce75d6a9abf21a519fd661d4fa940cd14e9f/doc/image/image006.png -------------------------------------------------------------------------------- /doc/image/image007.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toniz/fastcgi-async-or-coroutine/6908ce75d6a9abf21a519fd661d4fa940cd14e9f/doc/image/image007.png -------------------------------------------------------------------------------- /doc/image/image008.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toniz/fastcgi-async-or-coroutine/6908ce75d6a9abf21a519fd661d4fa940cd14e9f/doc/image/image008.png -------------------------------------------------------------------------------- /doc/image/image009.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toniz/fastcgi-async-or-coroutine/6908ce75d6a9abf21a519fd661d4fa940cd14e9f/doc/image/image009.png -------------------------------------------------------------------------------- /doc/image/image010.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toniz/fastcgi-async-or-coroutine/6908ce75d6a9abf21a519fd661d4fa940cd14e9f/doc/image/image010.png -------------------------------------------------------------------------------- /doc/image/image011.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toniz/fastcgi-async-or-coroutine/6908ce75d6a9abf21a519fd661d4fa940cd14e9f/doc/image/image011.png -------------------------------------------------------------------------------- /doc/image/image012.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toniz/fastcgi-async-or-coroutine/6908ce75d6a9abf21a519fd661d4fa940cd14e9f/doc/image/image012.png -------------------------------------------------------------------------------- /doc/image/image013.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toniz/fastcgi-async-or-coroutine/6908ce75d6a9abf21a519fd661d4fa940cd14e9f/doc/image/image013.png -------------------------------------------------------------------------------- /doc/image/image014.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toniz/fastcgi-async-or-coroutine/6908ce75d6a9abf21a519fd661d4fa940cd14e9f/doc/image/image014.png -------------------------------------------------------------------------------- /doc/image/image015.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toniz/fastcgi-async-or-coroutine/6908ce75d6a9abf21a519fd661d4fa940cd14e9f/doc/image/image015.png -------------------------------------------------------------------------------- /doc/image/image016.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toniz/fastcgi-async-or-coroutine/6908ce75d6a9abf21a519fd661d4fa940cd14e9f/doc/image/image016.png -------------------------------------------------------------------------------- /doc/image/image017.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toniz/fastcgi-async-or-coroutine/6908ce75d6a9abf21a519fd661d4fa940cd14e9f/doc/image/image017.png -------------------------------------------------------------------------------- /doc/image/image018.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toniz/fastcgi-async-or-coroutine/6908ce75d6a9abf21a519fd661d4fa940cd14e9f/doc/image/image018.png -------------------------------------------------------------------------------- /doc/image/image019.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toniz/fastcgi-async-or-coroutine/6908ce75d6a9abf21a519fd661d4fa940cd14e9f/doc/image/image019.png -------------------------------------------------------------------------------- /doc/image/last01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toniz/fastcgi-async-or-coroutine/6908ce75d6a9abf21a519fd661d4fa940cd14e9f/doc/image/last01.jpg -------------------------------------------------------------------------------- /doc/image/last02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toniz/fastcgi-async-or-coroutine/6908ce75d6a9abf21a519fd661d4fa940cd14e9f/doc/image/last02.png -------------------------------------------------------------------------------- /doc/image/last03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toniz/fastcgi-async-or-coroutine/6908ce75d6a9abf21a519fd661d4fa940cd14e9f/doc/image/last03.png -------------------------------------------------------------------------------- /doc/libfcgi_vs_mucgi_performance.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toniz/fastcgi-async-or-coroutine/6908ce75d6a9abf21a519fd661d4fa940cd14e9f/doc/libfcgi_vs_mucgi_performance.md -------------------------------------------------------------------------------- /doc/nginx_configure.conf: -------------------------------------------------------------------------------- 1 | upstream mucgi 2 | { 3 | server 127.0.0.1:16888; 4 | keepalive 32; 5 | } 6 | 7 | upstream cocgi 8 | { 9 | server 127.0.0.1:6888; 10 | # keepalive 32; 11 | } 12 | 13 | server 14 | { 15 | listen *:80; 16 | server_name 127.0.0.1; 17 | location /cocgi 18 | { 19 | fastcgi_next_upstream error timeout invalid_header http_500 http_503 http_404; 20 | include fastcgi_params; 21 | # fastcgi_keep_conn on; 22 | fastcgi_pass cocgi; 23 | } 24 | 25 | location /mucgi 26 | { 27 | fastcgi_next_upstream error timeout invalid_header http_500 http_503 http_404; 28 | include fastcgi_params; 29 | fastcgi_keep_conn on; 30 | fastcgi_pass mucgi; 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /doc/nginx_shortlink_performance.md: -------------------------------------------------------------------------------- 1 | # NGINX短连接压力上不去问题分析 2 | --- 3 | 使用火焰图对比短连接和长链接的Cpu使用情况 4 | __短链接__ 5 | ![短链接](/doc/image/fireframe1.png) 6 | __长链接__ 7 | ![长链接](/doc/image/fireframe2.png) 8 | 9 | 可以看到_spin_unlock_irqrestore这个自旋锁占用了大部分的系统调用时间。所以可以怀疑是短连接是由于锁操作导致压力上不去。 10 | 11 | __在nginx的accept源码里面找到这一段:__ 12 | ![code](/doc/image/code.png) 13 | 14 | 也就是说,开启ngx_use_accept_mutex的时候,线程之间是互斥的。只有一个线程能够accept连接。由于处理速度慢, 15 | 导致accept队列里面很多已经完成三次握手的链接被直接丢掉(没日志,客户端直接报connect time断开)。 16 | nginx文档说开启这个变量是为了避免惊群,但事实上,nginx一般只配置Cpu个数X2的进程。 17 | 所以惊群其实影响不大。去掉nginx配置文件里面加上accept_mutex off(默认是on)。 18 | 19 | 再次压测,短连接直接占满CPU,性能达到每秒9万次。 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /mucgi/README.md: -------------------------------------------------------------------------------- 1 | # Asynchronous Fastcgi 2 | 3 | `mucgi` is a async fastcgi using Muduo Network Library. 4 | Use Some Cgicc Files to parse http request. 5 | Modify the [BackendProc Class](backend.cpp) then You can pass the http request to back-end service. 6 | 7 | --- 8 | 9 | ## Requirements 10 | Need Boost C++ Library 11 | 12 | ## Install 13 | ```sh 14 | yum install scons -y 15 | scons 16 | ``` 17 | 18 | __Or run:__ 19 | ```sh 20 | sh make.sh 21 | ``` 22 | 23 | ## Usage 24 | ```sh 25 | nohup ./mcgi [PORT] [THREAD_NUM] & 26 | ``` 27 | 28 | __Linux Version > 3.9, support for the SO_REUSEPORT socket option. We can add process on runtime.__ 29 | 30 | ```sh 31 | nohup ./mcgi 16888 10 & 32 | nohup ./mcgi 16888 10 & 33 | nohup ./mcgi 16888 10 & 34 | nohup ./mcgi 16888 10 & 35 | ... 36 | ``` 37 | * [nginx configure](/doc/nginx_configure.conf) 38 | > mucgi using long-link to improve performance. 39 | 40 | * Test 41 | ![测试](/doc/image/last03.png) 42 | > nohup.out not flush immediately, 43 | 44 | 45 | > Test on Centos 6/7 46 | 47 | -------------------------------------------------------------------------------- /mucgi/SConstruct: -------------------------------------------------------------------------------- 1 | env = Environment() 2 | 3 | env.Append(CPPDEFINES = ['_LINUX_OS_' ]) 4 | 5 | env.Append(CPPFLAGS=['-Wall', '-O3', '-g', '-std=c++0x', 6 | '-DCHECK_PTHREAD_RETURN_VALUE', 7 | '-DMUDUO_STD_STRING', 8 | '-DSO_REUSEPORT', 9 | '-D_FILE_OFFSET_BITS=64' , 10 | '-Wextra', '-Werror', '-Wno-unused-parameter', '-Woverloaded-virtual', 11 | '-Wpointer-arith', '-Wwrite-strings', '-march=native', '-rdynamic', '-Wshadow', 12 | '-finline-limit=1000', 13 | '-DNDEBUG', 14 | ]) 15 | 16 | 17 | env.Append(CPPPATH = ['.', 18 | '/usr/local/include', 19 | ]) 20 | 21 | env.Append(LIBS = [ 22 | 'boost_thread', 23 | 'boost_regex', 24 | 'pthread', 25 | ]) 26 | 27 | env.Append(LIBPATH = ['./', 28 | '/usr/lib', 29 | '/usr/lib64/', 30 | '/usr/local/lib', 31 | ]) 32 | 33 | env.Append(RPATH = ['/usr/lib/nptl', '/usr/lib64/', '/usr/lib', '/usr/local/lib']) 34 | 35 | Cgi = env.Program('mcgi', [ 36 | 'muduo_base/Date.cc', 37 | 'muduo_base/Logging.cc', 38 | 'muduo_base/LogStream.cc', 39 | 'muduo_base/Thread.cc', 40 | 'muduo_base/Exception.cc', 41 | 'muduo_base/Timestamp.cc', 42 | 'muduo_base/TimeZone.cc', 43 | 'muduo_base/LogFile.cc', 44 | 'muduo_base/FileUtil.cc', 45 | 'muduo_base/ProcessInfo.cc', 46 | 'muduo_net/Acceptor.cc', 47 | 'muduo_net/Buffer.cc', 48 | 'muduo_net/Channel.cc', 49 | 'muduo_net/Poller.cc', 50 | 'muduo_net/EventLoop.cc', 51 | 'muduo_net/EventLoopThread.cc', 52 | 'muduo_net/EventLoopThreadPool.cc', 53 | 'muduo_net/InetAddress.cc', 54 | 'muduo_net/Socket.cc', 55 | 'muduo_net/SocketsOps.cc', 56 | 'muduo_net/TcpConnection.cc', 57 | 'muduo_net/TcpServer.cc', 58 | 'muduo_net/Timer.cc', 59 | 'muduo_net/TimerQueue.cc', 60 | 'muduo_net/DefaultPoller.cc', 61 | 'muduo_net/EPollPoller.cc', 62 | 'muduo_net/PollPoller.cc', 63 | 64 | 'cgicc_lib/FormEntry.cpp', 65 | 'cgicc_lib/FormFile.cpp', 66 | 'cgicc_lib/CgiUtils.cpp', 67 | 'cgicc_lib/Cgicc.cpp', 68 | 'cgicc_lib/HTTPCookie.cpp', 69 | 'cgicc_lib/MStreamable.cpp', 70 | 71 | 'backend.cpp', 72 | 'fastcgi.cpp', 73 | 'main.cpp' 74 | ]) 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /mucgi/backend.cpp: -------------------------------------------------------------------------------- 1 | #include "backend.h" 2 | #include 3 | 4 | std::string BackendProc::printRequest(SSMap &qmap, SSMap &header) 5 | { 6 | for (SSMap::iterator it = qmap.begin(); it != qmap.end(); it++) 7 | { 8 | printf("Param: [%s] ==> [%s] \n", it->first.c_str(), it->second.c_str()); 9 | } 10 | 11 | for (SSMap::iterator it = header.begin(); it != header.end(); it++) 12 | { 13 | printf("Header:[%s] ==> [%s] \n", it->first.c_str(), it->second.c_str()); 14 | } 15 | 16 | std::string content = "OK!!"; 17 | std::string resp = "Content-Type: text/html; charset=UTF-8\r\n"; 18 | resp += "Content-Length: "; 19 | resp += content.length(); 20 | resp += "\r\n\r\n"; 21 | resp += content; 22 | 23 | return resp; 24 | } 25 | 26 | -------------------------------------------------------------------------------- /mucgi/backend.h: -------------------------------------------------------------------------------- 1 | #ifndef _BACKEND_PROC_H__ 2 | #define _BACKEND_PROC_H__ 3 | #include "type.h" 4 | 5 | class BackendProc 6 | { 7 | public: 8 | std::string printRequest(SSMap &qmap, SSMap &header); 9 | 10 | 11 | }; 12 | 13 | 14 | 15 | 16 | #endif /*_BACKEND_PROC_H__*/ 17 | 18 | -------------------------------------------------------------------------------- /mucgi/cgicc_lib/FormEntry.cpp: -------------------------------------------------------------------------------- 1 | /* -*-mode:c++; c-file-style: "gnu";-*- */ 2 | /* 3 | * $Id: FormEntry.cpp,v 1.13 2007/07/02 18:48:18 sebdiaz Exp $ 4 | * 5 | * Copyright (C) 1996 - 2004 Stephen F. Booth 6 | * 2007 Sebastien DIAZ 7 | * Part of the GNU cgicc library, http://www.gnu.org/software/cgicc 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 3 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA 22 | */ 23 | 24 | #ifdef __GNUG__ 25 | # pragma implementation 26 | #endif 27 | 28 | #include 29 | #include 30 | 31 | #include "cgicc_lib/FormEntry.h" 32 | 33 | // local macro for integer maximum 34 | #define MAX(a, b) ((a) > (b) ? (a) : (b)) 35 | 36 | cgicc::FormEntry& 37 | cgicc::FormEntry::operator= (const FormEntry& entry) 38 | { 39 | fName = entry.fName; 40 | fValue = entry.fValue; 41 | 42 | return *this; 43 | } 44 | 45 | long 46 | cgicc::FormEntry::getIntegerValue(long min, 47 | long max) const 48 | { 49 | long value = std::atol(fValue.c_str()); 50 | 51 | if(value > max) 52 | value = max; 53 | else if(value < min) 54 | value = min; 55 | 56 | return value; 57 | } 58 | 59 | long 60 | cgicc::FormEntry::getIntegerValue(long min, 61 | long max, 62 | bool& bounded) const 63 | { 64 | long value = std::atol(fValue.c_str()); 65 | 66 | bounded = false; 67 | 68 | if(value > max) { 69 | value = max; 70 | bounded = true; 71 | } 72 | else if(value < min) { 73 | value = min; 74 | bounded = true; 75 | } 76 | 77 | return value; 78 | } 79 | 80 | double 81 | cgicc::FormEntry::getDoubleValue(double min, 82 | double max) const 83 | { 84 | double value = std::atof(fValue.c_str()); 85 | if(value > max) 86 | value = max; 87 | else if(value < min) 88 | value = min; 89 | 90 | return value; 91 | } 92 | 93 | double 94 | cgicc::FormEntry::getDoubleValue(double min, 95 | double max, 96 | bool& bounded) const 97 | { 98 | double value = std::atof(fValue.c_str()); 99 | 100 | bounded = false; 101 | 102 | if(value > max) { 103 | value = max; 104 | bounded = true; 105 | } 106 | else if(value < min) { 107 | value = min; 108 | bounded = true; 109 | } 110 | 111 | return value; 112 | } 113 | 114 | std::string 115 | cgicc::FormEntry::makeString(std::string::size_type maxLen, 116 | bool allowNewlines) const 117 | { 118 | std::string::size_type len = 0; 119 | std::string::size_type avail = maxLen; 120 | std::string::size_type crCount = 0; 121 | std::string::size_type lfCount = 0; 122 | std::string::const_iterator src = fValue.begin(); 123 | std::string::const_iterator lim = fValue.end(); 124 | std::string dst; 125 | 126 | 127 | while(src != lim && len < avail) { 128 | 129 | // handle newlines 130 | if('\r' == *src || '\n' == *src) { 131 | crCount = 0; 132 | lfCount = 0; 133 | 134 | // Count the number of each kind of line break ('\r' and '\n') 135 | while( ('\r' == *src || '\n' == *src) && (src != lim)) { 136 | if('\r' == *src) 137 | crCount++; 138 | else 139 | lfCount++; 140 | ++src; 141 | } 142 | 143 | // if newlines are allowed, add them 144 | if(allowNewlines) { 145 | // output the larger value 146 | int lfsAdd = MAX(crCount, lfCount); 147 | dst.append(lfsAdd, '\n'); 148 | len += lfsAdd; 149 | } 150 | } 151 | // just append all other characters 152 | else { 153 | dst.append(1, *src); 154 | ++len; 155 | ++src; 156 | } 157 | } 158 | 159 | return dst; 160 | } 161 | -------------------------------------------------------------------------------- /mucgi/cgicc_lib/FormFile.cpp: -------------------------------------------------------------------------------- 1 | /* -*-mode:c++; c-file-style: "gnu";-*- */ 2 | /* 3 | * $Id: FormFile.cpp,v 1.10 2007/07/02 18:48:18 sebdiaz Exp $ 4 | * 5 | * Copyright (C) 1996 - 2004 Stephen F. Booth 6 | * 2007 Sebastien DIAZ 7 | * Part of the GNU cgicc library, http://www.gnu.org/software/cgicc 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 3 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA 22 | */ 23 | 24 | #ifdef __GNUG__ 25 | # pragma implementation 26 | #endif 27 | 28 | #include "cgicc_lib/FormFile.h" 29 | #include "cgicc_lib/CgiUtils.h" 30 | 31 | cgicc::FormFile::FormFile(const std::string& name, 32 | const std::string& filename, 33 | const std::string& dataType, 34 | const std::string& data) 35 | : fName(name), 36 | fFilename(filename), 37 | fData(data) 38 | { 39 | fDataType = dataType.empty() ? std::string("text/plain") : dataType; 40 | } 41 | 42 | bool 43 | cgicc::FormFile::operator== (const FormFile& file) const 44 | { 45 | return (stringsAreEqual(fName, file.fName) && 46 | stringsAreEqual(fFilename, file.fFilename) && 47 | stringsAreEqual(fDataType, file.fDataType)); 48 | } 49 | 50 | cgicc::FormFile& 51 | cgicc::FormFile::operator= (const FormFile& file) 52 | { 53 | fName = file.fName; 54 | fFilename = file.fFilename; 55 | fDataType = file.fDataType; 56 | fData = file.fData; 57 | 58 | return *this; 59 | } 60 | 61 | void 62 | cgicc::FormFile::writeToStream(std::ostream& out) const 63 | { 64 | out.write(getData().data(), getDataLength()); 65 | } 66 | -------------------------------------------------------------------------------- /mucgi/cgicc_lib/HTTPCookie.cpp: -------------------------------------------------------------------------------- 1 | /* -*-mode:c++; c-file-style: "gnu";-*- */ 2 | /* 3 | * $Id: HTTPCookie.cpp,v 1.11 2009/01/18 13:58:25 sebdiaz Exp $ 4 | * 5 | * Copyright (C) 1996 - 2004 Stephen F. Booth 6 | * 2007 Sebastien DIAZ 7 | * Part of the GNU cgicc library, http://www.gnu.org/software/cgicc 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 3 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA 22 | */ 23 | 24 | #ifdef __GNUG__ 25 | # pragma implementation 26 | #endif 27 | 28 | #include "cgicc_lib/HTTPCookie.h" 29 | #include "cgicc_lib/CgiUtils.h" 30 | 31 | // ============================================================ 32 | // Class HTTPCookie 33 | // ============================================================ 34 | cgicc::HTTPCookie::HTTPCookie() 35 | : fMaxAge(0), 36 | fSecure(false), 37 | fRemoved(false) 38 | {} 39 | 40 | cgicc::HTTPCookie::HTTPCookie(const std::string& name, 41 | const std::string& value) 42 | : fName(name), 43 | fValue(value), 44 | fMaxAge(0), 45 | fSecure(false), 46 | fRemoved(false) 47 | {} 48 | 49 | cgicc::HTTPCookie::HTTPCookie(const std::string& name, 50 | const std::string& value, 51 | const std::string& comment, 52 | const std::string& domain, 53 | unsigned long maxAge, 54 | const std::string& path, 55 | bool secure) 56 | : fName(name), 57 | fValue(value), 58 | fComment(comment), 59 | fDomain(domain), 60 | fMaxAge(maxAge), 61 | fPath(path), 62 | fSecure(secure), 63 | fRemoved(false) 64 | {} 65 | 66 | cgicc::HTTPCookie::HTTPCookie(const HTTPCookie& cookie) 67 | : MStreamable(), 68 | fName(cookie.fName), 69 | fValue(cookie.fValue), 70 | fComment(cookie.fComment), 71 | fDomain(cookie.fDomain), 72 | fMaxAge(cookie.fMaxAge), 73 | fPath(cookie.fPath), 74 | fSecure(cookie.fSecure), 75 | fRemoved(cookie.fRemoved) 76 | {} 77 | 78 | cgicc::HTTPCookie::~HTTPCookie() 79 | {} 80 | 81 | bool 82 | cgicc::HTTPCookie::operator== (const HTTPCookie& cookie) const 83 | { 84 | return (stringsAreEqual(fName, cookie.fName) 85 | && stringsAreEqual(fValue, cookie.fValue) 86 | && stringsAreEqual(fComment, cookie.fComment) 87 | && stringsAreEqual(fDomain, cookie.fDomain) 88 | && fMaxAge == cookie.fMaxAge 89 | && stringsAreEqual(fPath, cookie.fPath) 90 | && fSecure == cookie.fSecure 91 | && fRemoved == cookie.fRemoved); 92 | } 93 | 94 | void 95 | cgicc::HTTPCookie::render(std::ostream& out) const 96 | { 97 | out << "Set-Cookie:" << fName << '=' << fValue; 98 | if(false == fComment.empty()) 99 | out << "; Comment=" << fComment; 100 | if(false == fDomain.empty()) 101 | out << "; Domain=" << fDomain; 102 | if(fRemoved) 103 | out << "; Expires=Fri, 01-Jan-1971 01:00:00 GMT;"; 104 | else if(0 != fMaxAge) 105 | out << "; Max-Age=" << fMaxAge; 106 | if(false == fPath.empty()) 107 | out << "; Path=" << fPath; 108 | if(true == fSecure) 109 | out << "; Secure"; 110 | 111 | out << "; Version=1"; 112 | } 113 | -------------------------------------------------------------------------------- /mucgi/cgicc_lib/MStreamable.cpp: -------------------------------------------------------------------------------- 1 | /* -*-mode:c++; c-file-style: "gnu";-*- */ 2 | /* 3 | * $Id: MStreamable.cpp,v 1.9 2007/07/02 18:48:19 sebdiaz Exp $ 4 | * 5 | * Copyright (C) 1996 - 2004 Stephen F. Booth 6 | * 2007 Sebastien DIAZ 7 | * Part of the GNU cgicc library, http://www.gnu.org/software/cgicc 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 3 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA 22 | */ 23 | 24 | #ifdef __GNUG__ 25 | # pragma implementation 26 | #endif 27 | 28 | #include "cgicc_lib/MStreamable.h" 29 | 30 | // ============================================================ 31 | // Class MStreamable 32 | // ============================================================ 33 | std::ostream& 34 | cgicc::operator<<(std::ostream& out, 35 | const MStreamable& obj) 36 | { 37 | obj.render(out); 38 | return out; 39 | } 40 | -------------------------------------------------------------------------------- /mucgi/cgicc_lib/MStreamable.h: -------------------------------------------------------------------------------- 1 | /* -*-mode:c++; c-file-style: "gnu";-*- */ 2 | /* 3 | * $Id: MStreamable.h,v 1.12 2007/07/02 18:48:19 sebdiaz Exp $ 4 | * 5 | * Copyright (C) 1996 - 2004 Stephen F. Booth 6 | * 2007 Sebastien DIAZ 7 | * Part of the GNU cgicc library, http://www.gnu.org/software/cgicc 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 3 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA 22 | */ 23 | 24 | #ifndef _MSTREAMABLE_H_ 25 | #define _MSTREAMABLE_H_ 1 26 | 27 | #ifdef __GNUG__ 28 | # pragma interface 29 | #endif 30 | 31 | /*! \file MStreamable.h 32 | * \brief Abstract base class for all streamable objects. 33 | * 34 | * A streamable object is an object that can be written to an \c 35 | * ostream using the \c << operator. 36 | */ 37 | 38 | #include 39 | 40 | namespace cgicc { 41 | 42 | class MStreamable; 43 | 44 | /*! 45 | * Prototype for overloading streaming operator 46 | * \param out The ostream to which to write 47 | * \param obj The MStreamable object to write 48 | * \return A reference to \c out 49 | */ 50 | std::ostream& 51 | operator<<(std::ostream& out, const MStreamable& obj); 52 | 53 | // ============================================================ 54 | // Class MStreamable 55 | // ============================================================ 56 | 57 | /*! \class MStreamable MStreamable.h cgicc/MStreamable.h 58 | * \brief Mix-in streamable interface. 59 | * 60 | * Abstract mix-in class which makes classes streamable via 61 | * the \c << operator. 62 | * Written in the spirit of a Java interface. 63 | */ 64 | class MStreamable 65 | { 66 | 67 | friend std::ostream& 68 | operator<<(std::ostream& out, const MStreamable& obj); 69 | 70 | public: 71 | /*! 72 | * \brief Empty constructor 73 | * 74 | */ 75 | inline MStreamable() 76 | {} 77 | 78 | /*! 79 | * \brief Empty destructor 80 | * 81 | */ 82 | inline virtual ~MStreamable() 83 | {} 84 | 85 | /*! 86 | * \brief Write this object to a stream. 87 | * 88 | * Subclasses must implement this function. 89 | * \param out The ostream to which to write. 90 | */ 91 | virtual void 92 | render(std::ostream& out) const = 0; 93 | }; 94 | 95 | } // namespace cgicc 96 | 97 | #endif /* ! _MSTREAMABLE_H_ */ 98 | -------------------------------------------------------------------------------- /mucgi/fastcgi.h: -------------------------------------------------------------------------------- 1 | #ifndef MUDUO_FASTCGI_FASTCGI_H 2 | #define MUDUO_FASTCGI_FASTCGI_H 3 | 4 | #include "muduo_net/TcpConnection.h" 5 | #include 6 | 7 | using muduo::string; 8 | 9 | // one FastCgiCodec per TcpConnection 10 | // both lighttpd and nginx do not implement multiplexing, 11 | // so there is no concurrent requests of one connection. 12 | class FastCgiCodec : boost::noncopyable 13 | { 14 | public: 15 | typedef std::map ParamMap; 16 | typedef boost::function Callback; 19 | 20 | explicit FastCgiCodec(const Callback& cb) 21 | : cb_(cb), 22 | gotRequest_(false), 23 | keepConn_(false) 24 | { 25 | } 26 | 27 | void onMessage(const muduo::net::TcpConnectionPtr& conn, 28 | muduo::net::Buffer* buf, 29 | muduo::Timestamp receiveTime) 30 | { 31 | parseRequest(buf); 32 | if (gotRequest_) 33 | { 34 | cb_(conn, params_, &stdin_); 35 | stdin_.retrieveAll(); 36 | paramsStream_.retrieveAll(); 37 | params_.clear(); 38 | gotRequest_ = false; 39 | if (!keepConn_) 40 | { 41 | conn->shutdown(); 42 | } 43 | } 44 | } 45 | 46 | static void respond(std::string &out, muduo::net::Buffer* response); 47 | 48 | private: 49 | struct RecordHeader; 50 | bool parseRequest(muduo::net::Buffer* buf); 51 | bool onBeginRequest(const RecordHeader& header, const muduo::net::Buffer* buf); 52 | void onStdin(const char* content, uint16_t length); 53 | bool onParams(const char* content, uint16_t length); 54 | bool parseAllParams(); 55 | uint32_t readLen(); 56 | 57 | static void endStdout(muduo::net::Buffer* buf); 58 | static void endRequest(muduo::net::Buffer* buf); 59 | 60 | Callback cb_; 61 | bool gotRequest_; 62 | bool keepConn_; 63 | muduo::net::Buffer stdin_; 64 | muduo::net::Buffer paramsStream_; 65 | ParamMap params_; 66 | 67 | const static unsigned kRecordHeader; 68 | }; 69 | 70 | #endif // MUDUO_FASTCGI_FASTCGI_H 71 | -------------------------------------------------------------------------------- /mucgi/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "muduo_base/Logging.h" 4 | #include "muduo_net/EventLoop.h" 5 | #include "muduo_net/TcpServer.h" 6 | #include "cgicc_lib/Cgicc.h" 7 | #include "fastcgi.h" 8 | #include "backend.h" 9 | 10 | using namespace muduo::net; 11 | 12 | void onRequest(const TcpConnectionPtr& conn, FastCgiCodec::ParamMap& params, Buffer* in) 13 | { 14 | std::string queryString = params["QUERY_STRING"]; 15 | std::string queryType = params["CONTENT_TYPE"]; 16 | std::string queryCookie = params["HTTP_COOKIE"]; 17 | std::string postData; 18 | if (in->readableBytes() > 0) 19 | { 20 | postData = in->retrieveAllAsString(); 21 | } 22 | 23 | SSMap qmap; 24 | // Parse Url String 25 | // Parse Post Data With Standard content type = application/x-www-form-urlencoded 26 | cgicc::Cgicc cgi(queryString, queryCookie, postData, queryType); 27 | cgicc::const_form_iterator iterE; 28 | for(iterE = cgi.getElements().begin(); iterE != cgi.getElements().end(); ++iterE) 29 | { 30 | std::string key = boost::to_lower_copy(iterE->getName()); 31 | qmap.insert(SSMap::value_type(key, iterE->getValue())); 32 | LOG_DEBUG << "Query Element:" << key << " Value:" << iterE->getValue(); 33 | } 34 | 35 | // Parse File Uplod, File upload type = multipart/form-data 36 | cgicc::const_file_iterator iterF; 37 | for(iterF = cgi.getFiles().begin(); iterF != cgi.getFiles().end(); ++iterF) 38 | { 39 | qmap.insert(SSMap::value_type(iterF->getName(), iterF->getData())); 40 | } 41 | 42 | SSMap header; 43 | for (FastCgiCodec::ParamMap::const_iterator it = params.begin(); it != params.end(); ++it) 44 | { 45 | header[it->first] = it->second; 46 | LOG_DEBUG << "Query Headers " << it->first << " = " << it->second; 47 | } 48 | 49 | // Parse Cookie List 50 | cgicc::const_cookie_iterator iterV; 51 | for(iterV = cgi.getCookieList().begin(); iterV != cgi.getCookieList().end(); ++iterV) 52 | { 53 | header[iterV->getName()] = iterV->getValue(); 54 | LOG_DEBUG << "Cookie Param: Name["<< iterV->getName() << "] Value[" << iterV->getValue() << "]."; 55 | } 56 | 57 | // Call Backend Process 58 | BackendProc proc; 59 | std::string res = proc.printRequest(qmap, header); 60 | 61 | LOG_DEBUG << "Query Result: "<< res.length(); 62 | muduo::net::Buffer response; 63 | FastCgiCodec::respond(res, &response); 64 | conn->send(&response); 65 | } 66 | 67 | void onConnection(const TcpConnectionPtr& conn) 68 | { 69 | if (conn->connected()) 70 | { 71 | typedef boost::shared_ptr CodecPtr; 72 | CodecPtr codec(new FastCgiCodec(onRequest)); 73 | conn->setContext(codec); 74 | conn->setMessageCallback(boost::bind(&FastCgiCodec::onMessage, codec, _1, _2, _3)); 75 | conn->setTcpNoDelay(true); 76 | } 77 | } 78 | 79 | int main(int argc, char* argv[]) 80 | { 81 | int port = 19981; 82 | int threads = 0; 83 | std::string g_log_path; 84 | if (argc > 1) port = atoi(argv[1]); 85 | if (argc > 2) threads = atoi(argv[2]); 86 | 87 | muduo::Logger::setLogLevel(muduo::Logger::INFO); 88 | 89 | InetAddress addr(static_cast(port)); 90 | LOG_INFO << "FastCGI listens on " << addr.toIpPort() << " threads " << threads; 91 | 92 | muduo::net::EventLoop loop; 93 | TcpServer server(&loop, addr, "FastCGI", muduo::net::TcpServer::kReusePort); 94 | server.setConnectionCallback(onConnection); 95 | server.setThreadNum(threads); 96 | server.start(); 97 | loop.loop(); 98 | } 99 | -------------------------------------------------------------------------------- /mucgi/muduo_base/Atomic.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD-style license 2 | // that can be found in the License file. 3 | // 4 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 5 | 6 | #ifndef MUDUO_BASE_ATOMIC_H 7 | #define MUDUO_BASE_ATOMIC_H 8 | 9 | #include 10 | #include 11 | 12 | namespace muduo 13 | { 14 | 15 | namespace detail 16 | { 17 | template 18 | class AtomicIntegerT : boost::noncopyable 19 | { 20 | public: 21 | AtomicIntegerT() 22 | : value_(0) 23 | { 24 | } 25 | 26 | // uncomment if you need copying and assignment 27 | // 28 | // AtomicIntegerT(const AtomicIntegerT& that) 29 | // : value_(that.get()) 30 | // {} 31 | // 32 | // AtomicIntegerT& operator=(const AtomicIntegerT& that) 33 | // { 34 | // getAndSet(that.get()); 35 | // return *this; 36 | // } 37 | 38 | T get() 39 | { 40 | // in gcc >= 4.7: __atomic_load_n(&value_, __ATOMIC_SEQ_CST) 41 | return __sync_val_compare_and_swap(&value_, 0, 0); 42 | } 43 | 44 | T getAndAdd(T x) 45 | { 46 | // in gcc >= 4.7: __atomic_fetch_add(&value_, x, __ATOMIC_SEQ_CST) 47 | return __sync_fetch_and_add(&value_, x); 48 | } 49 | 50 | T addAndGet(T x) 51 | { 52 | return getAndAdd(x) + x; 53 | } 54 | 55 | T incrementAndGet() 56 | { 57 | return addAndGet(1); 58 | } 59 | 60 | T decrementAndGet() 61 | { 62 | return addAndGet(-1); 63 | } 64 | 65 | void add(T x) 66 | { 67 | getAndAdd(x); 68 | } 69 | 70 | void increment() 71 | { 72 | incrementAndGet(); 73 | } 74 | 75 | void decrement() 76 | { 77 | decrementAndGet(); 78 | } 79 | 80 | T getAndSet(T newValue) 81 | { 82 | // in gcc >= 4.7: __atomic_exchange_n(&value, newValue, __ATOMIC_SEQ_CST) 83 | return __sync_lock_test_and_set(&value_, newValue); 84 | } 85 | 86 | private: 87 | volatile T value_; 88 | }; 89 | } 90 | 91 | typedef detail::AtomicIntegerT AtomicInt32; 92 | typedef detail::AtomicIntegerT AtomicInt64; 93 | } 94 | 95 | #endif // MUDUO_BASE_ATOMIC_H 96 | -------------------------------------------------------------------------------- /mucgi/muduo_base/Condition.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD-style license 2 | // that can be found in the License file. 3 | // 4 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 5 | 6 | #ifndef MUDUO_BASE_CONDITION_H 7 | #define MUDUO_BASE_CONDITION_H 8 | 9 | #include "muduo_base/Mutex.h" 10 | 11 | #include 12 | #include 13 | 14 | namespace muduo 15 | { 16 | 17 | class Condition : boost::noncopyable 18 | { 19 | public: 20 | explicit Condition(MutexLock& mutex) 21 | : mutex_(mutex) 22 | { 23 | MCHECK(pthread_cond_init(&pcond_, NULL)); 24 | } 25 | 26 | ~Condition() 27 | { 28 | MCHECK(pthread_cond_destroy(&pcond_)); 29 | } 30 | 31 | void wait() 32 | { 33 | MutexLock::UnassignGuard ug(mutex_); 34 | MCHECK(pthread_cond_wait(&pcond_, mutex_.getPthreadMutex())); 35 | } 36 | 37 | // returns true if time out, false otherwise. 38 | bool waitForSeconds(double seconds); 39 | 40 | void notify() 41 | { 42 | MCHECK(pthread_cond_signal(&pcond_)); 43 | } 44 | 45 | void notifyAll() 46 | { 47 | MCHECK(pthread_cond_broadcast(&pcond_)); 48 | } 49 | 50 | private: 51 | MutexLock& mutex_; 52 | pthread_cond_t pcond_; 53 | }; 54 | 55 | } 56 | #endif // MUDUO_BASE_CONDITION_H 57 | -------------------------------------------------------------------------------- /mucgi/muduo_base/CurrentThread.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD-style license 2 | // that can be found in the License file. 3 | // 4 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 5 | 6 | #ifndef MUDUO_BASE_CURRENTTHREAD_H 7 | #define MUDUO_BASE_CURRENTTHREAD_H 8 | 9 | #include 10 | 11 | namespace muduo 12 | { 13 | namespace CurrentThread 14 | { 15 | // internal 16 | extern __thread int t_cachedTid; 17 | extern __thread char t_tidString[32]; 18 | extern __thread int t_tidStringLength; 19 | extern __thread const char* t_threadName; 20 | void cacheTid(); 21 | 22 | inline int tid() 23 | { 24 | if (__builtin_expect(t_cachedTid == 0, 0)) 25 | { 26 | cacheTid(); 27 | } 28 | return t_cachedTid; 29 | } 30 | 31 | inline const char* tidString() // for logging 32 | { 33 | return t_tidString; 34 | } 35 | 36 | inline int tidStringLength() // for logging 37 | { 38 | return t_tidStringLength; 39 | } 40 | 41 | inline const char* name() 42 | { 43 | return t_threadName; 44 | } 45 | 46 | bool isMainThread(); 47 | 48 | void sleepUsec(int64_t usec); 49 | } 50 | } 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /mucgi/muduo_base/Date.cc: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD-style license 2 | // that can be found in the License file. 3 | // 4 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 5 | 6 | #include "muduo_base/Date.h" 7 | #include // snprintf 8 | 9 | namespace muduo 10 | { 11 | namespace detail 12 | { 13 | 14 | char require_32_bit_integer_at_least[sizeof(int) >= sizeof(int32_t) ? 1 : -1]; 15 | 16 | // algorithm and explanation see: 17 | // http://www.faqs.org/faqs/calendars/faq/part2/ 18 | // http://blog.csdn.net/Solstice 19 | 20 | int getJulianDayNumber(int year, int month, int day) 21 | { 22 | (void) require_32_bit_integer_at_least; // no warning please 23 | int a = (14 - month) / 12; 24 | int y = year + 4800 - a; 25 | int m = month + 12 * a - 3; 26 | return day + (153*m + 2) / 5 + y*365 + y/4 - y/100 + y/400 - 32045; 27 | } 28 | 29 | struct Date::YearMonthDay getYearMonthDay(int julianDayNumber) 30 | { 31 | int a = julianDayNumber + 32044; 32 | int b = (4 * a + 3) / 146097; 33 | int c = a - ((b * 146097) / 4); 34 | int d = (4 * c + 3) / 1461; 35 | int e = c - ((1461 * d) / 4); 36 | int m = (5 * e + 2) / 153; 37 | Date::YearMonthDay ymd; 38 | ymd.day = e - ((153 * m + 2) / 5) + 1; 39 | ymd.month = m + 3 - 12 * (m / 10); 40 | ymd.year = b * 100 + d - 4800 + (m / 10); 41 | return ymd; 42 | } 43 | } 44 | const int Date::kJulianDayOf1970_01_01 = detail::getJulianDayNumber(1970, 1, 1); 45 | } 46 | 47 | using namespace muduo; 48 | using namespace muduo::detail; 49 | 50 | Date::Date(int y, int m, int d) 51 | : julianDayNumber_(getJulianDayNumber(y, m, d)) 52 | { 53 | } 54 | 55 | Date::Date(const struct tm& t) 56 | : julianDayNumber_(getJulianDayNumber( 57 | t.tm_year+1900, 58 | t.tm_mon+1, 59 | t.tm_mday)) 60 | { 61 | } 62 | 63 | string Date::toIsoString() const 64 | { 65 | char buf[32]; 66 | YearMonthDay ymd(yearMonthDay()); 67 | snprintf(buf, sizeof buf, "%4d-%02d-%02d", ymd.year, ymd.month, ymd.day); 68 | return buf; 69 | } 70 | 71 | Date::YearMonthDay Date::yearMonthDay() const 72 | { 73 | return getYearMonthDay(julianDayNumber_); 74 | } 75 | 76 | -------------------------------------------------------------------------------- /mucgi/muduo_base/Date.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD-style license 2 | // that can be found in the License file. 3 | // 4 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 5 | 6 | #ifndef MUDUO_BASE_DATE_H 7 | #define MUDUO_BASE_DATE_H 8 | 9 | #include "muduo_base/copyable.h" 10 | #include "muduo_base/Types.h" 11 | 12 | struct tm; 13 | 14 | namespace muduo 15 | { 16 | 17 | /// 18 | /// Date in Gregorian calendar. 19 | /// 20 | /// This class is immutable. 21 | /// It's recommended to pass it by value, since it's passed in register on x64. 22 | /// 23 | class Date : public muduo::copyable 24 | // public boost::less_than_comparable, 25 | // public boost::equality_comparable 26 | { 27 | public: 28 | 29 | struct YearMonthDay 30 | { 31 | int year; // [1900..2500] 32 | int month; // [1..12] 33 | int day; // [1..31] 34 | }; 35 | 36 | static const int kDaysPerWeek = 7; 37 | static const int kJulianDayOf1970_01_01; 38 | 39 | /// 40 | /// Constucts an invalid Date. 41 | /// 42 | Date() 43 | : julianDayNumber_(0) 44 | {} 45 | 46 | /// 47 | /// Constucts a yyyy-mm-dd Date. 48 | /// 49 | /// 1 <= month <= 12 50 | Date(int year, int month, int day); 51 | 52 | /// 53 | /// Constucts a Date from Julian Day Number. 54 | /// 55 | explicit Date(int julianDayNum) 56 | : julianDayNumber_(julianDayNum) 57 | {} 58 | 59 | /// 60 | /// Constucts a Date from struct tm 61 | /// 62 | explicit Date(const struct tm&); 63 | 64 | // default copy/assignment/dtor are Okay 65 | 66 | void swap(Date& that) 67 | { 68 | std::swap(julianDayNumber_, that.julianDayNumber_); 69 | } 70 | 71 | bool valid() const { return julianDayNumber_ > 0; } 72 | 73 | /// 74 | /// Converts to yyyy-mm-dd format. 75 | /// 76 | string toIsoString() const; 77 | 78 | struct YearMonthDay yearMonthDay() const; 79 | 80 | int year() const 81 | { 82 | return yearMonthDay().year; 83 | } 84 | 85 | int month() const 86 | { 87 | return yearMonthDay().month; 88 | } 89 | 90 | int day() const 91 | { 92 | return yearMonthDay().day; 93 | } 94 | 95 | // [0, 1, ..., 6] => [Sunday, Monday, ..., Saturday ] 96 | int weekDay() const 97 | { 98 | return (julianDayNumber_+1) % kDaysPerWeek; 99 | } 100 | 101 | int julianDayNumber() const { return julianDayNumber_; } 102 | 103 | private: 104 | int julianDayNumber_; 105 | }; 106 | 107 | inline bool operator<(Date x, Date y) 108 | { 109 | return x.julianDayNumber() < y.julianDayNumber(); 110 | } 111 | 112 | inline bool operator==(Date x, Date y) 113 | { 114 | return x.julianDayNumber() == y.julianDayNumber(); 115 | } 116 | 117 | } 118 | #endif // MUDUO_BASE_DATE_H 119 | -------------------------------------------------------------------------------- /mucgi/muduo_base/Exception.cc: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD-style license 2 | // that can be found in the License file. 3 | // 4 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 5 | 6 | #include "muduo_base/Exception.h" 7 | 8 | //#include 9 | #include 10 | #include 11 | 12 | using namespace muduo; 13 | 14 | Exception::Exception(const char* msg) 15 | : message_(msg) 16 | { 17 | fillStackTrace(); 18 | } 19 | 20 | Exception::Exception(const string& msg) 21 | : message_(msg) 22 | { 23 | fillStackTrace(); 24 | } 25 | 26 | Exception::~Exception() throw () 27 | { 28 | } 29 | 30 | const char* Exception::what() const throw() 31 | { 32 | return message_.c_str(); 33 | } 34 | 35 | const char* Exception::stackTrace() const throw() 36 | { 37 | return stack_.c_str(); 38 | } 39 | 40 | void Exception::fillStackTrace() 41 | { 42 | const int len = 200; 43 | void* buffer[len]; 44 | int nptrs = ::backtrace(buffer, len); 45 | char** strings = ::backtrace_symbols(buffer, nptrs); 46 | if (strings) 47 | { 48 | for (int i = 0; i < nptrs; ++i) 49 | { 50 | // TODO demangle funcion name with abi::__cxa_demangle 51 | stack_.append(strings[i]); 52 | stack_.push_back('\n'); 53 | } 54 | free(strings); 55 | } 56 | } 57 | 58 | -------------------------------------------------------------------------------- /mucgi/muduo_base/Exception.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD-style license 2 | // that can be found in the License file. 3 | // 4 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 5 | 6 | #ifndef MUDUO_BASE_EXCEPTION_H 7 | #define MUDUO_BASE_EXCEPTION_H 8 | 9 | #include "muduo_base/Types.h" 10 | #include 11 | 12 | namespace muduo 13 | { 14 | 15 | class Exception : public std::exception 16 | { 17 | public: 18 | explicit Exception(const char* what); 19 | explicit Exception(const string& what); 20 | virtual ~Exception() throw(); 21 | virtual const char* what() const throw(); 22 | const char* stackTrace() const throw(); 23 | 24 | private: 25 | void fillStackTrace(); 26 | 27 | string message_; 28 | string stack_; 29 | }; 30 | 31 | } 32 | 33 | #endif // MUDUO_BASE_EXCEPTION_H 34 | -------------------------------------------------------------------------------- /mucgi/muduo_base/FileUtil.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | 10 | #include "muduo_base/FileUtil.h" 11 | #include "muduo_base/Logging.h" // strerror_tl 12 | 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | using namespace muduo; 22 | 23 | FileUtil::AppendFile::AppendFile(StringArg filename) 24 | : fp_(::fopen(filename.c_str(), "ae")), // 'e' for O_CLOEXEC 25 | writtenBytes_(0) 26 | { 27 | assert(fp_); 28 | ::setbuffer(fp_, buffer_, sizeof buffer_); 29 | // posix_fadvise POSIX_FADV_DONTNEED ? 30 | } 31 | 32 | FileUtil::AppendFile::~AppendFile() 33 | { 34 | ::fclose(fp_); 35 | } 36 | 37 | void FileUtil::AppendFile::append(const char* logline, const size_t len) 38 | { 39 | size_t n = write(logline, len); 40 | size_t remain = len - n; 41 | while (remain > 0) 42 | { 43 | size_t x = write(logline + n, remain); 44 | if (x == 0) 45 | { 46 | int err = ferror(fp_); 47 | if (err) 48 | { 49 | fprintf(stderr, "AppendFile::append() failed %s\n", strerror_tl(err)); 50 | } 51 | break; 52 | } 53 | n += x; 54 | remain = len - n; // remain -= x 55 | } 56 | 57 | writtenBytes_ += len; 58 | } 59 | 60 | void FileUtil::AppendFile::flush() 61 | { 62 | ::fflush(fp_); 63 | } 64 | 65 | size_t FileUtil::AppendFile::write(const char* logline, size_t len) 66 | { 67 | // #undef fwrite_unlocked 68 | return ::fwrite_unlocked(logline, 1, len, fp_); 69 | } 70 | 71 | FileUtil::ReadSmallFile::ReadSmallFile(StringArg filename) 72 | : fd_(::open(filename.c_str(), O_RDONLY | O_CLOEXEC)), 73 | err_(0) 74 | { 75 | buf_[0] = '\0'; 76 | if (fd_ < 0) 77 | { 78 | err_ = errno; 79 | } 80 | } 81 | 82 | FileUtil::ReadSmallFile::~ReadSmallFile() 83 | { 84 | if (fd_ >= 0) 85 | { 86 | ::close(fd_); // FIXME: check EINTR 87 | } 88 | } 89 | 90 | // return errno 91 | template 92 | int FileUtil::ReadSmallFile::readToString(int maxSize, 93 | String* content, 94 | int64_t* fileSize, 95 | int64_t* modifyTime, 96 | int64_t* createTime) 97 | { 98 | BOOST_STATIC_ASSERT(sizeof(off_t) == 8); 99 | assert(content != NULL); 100 | int err = err_; 101 | if (fd_ >= 0) 102 | { 103 | content->clear(); 104 | 105 | if (fileSize) 106 | { 107 | struct stat statbuf; 108 | if (::fstat(fd_, &statbuf) == 0) 109 | { 110 | if (S_ISREG(statbuf.st_mode)) 111 | { 112 | *fileSize = statbuf.st_size; 113 | content->reserve(static_cast(std::min(implicit_cast(maxSize), *fileSize))); 114 | } 115 | else if (S_ISDIR(statbuf.st_mode)) 116 | { 117 | err = EISDIR; 118 | } 119 | if (modifyTime) 120 | { 121 | *modifyTime = statbuf.st_mtime; 122 | } 123 | if (createTime) 124 | { 125 | *createTime = statbuf.st_ctime; 126 | } 127 | } 128 | else 129 | { 130 | err = errno; 131 | } 132 | } 133 | 134 | while (content->size() < implicit_cast(maxSize)) 135 | { 136 | size_t toRead = std::min(implicit_cast(maxSize) - content->size(), sizeof(buf_)); 137 | ssize_t n = ::read(fd_, buf_, toRead); 138 | if (n > 0) 139 | { 140 | content->append(buf_, n); 141 | } 142 | else 143 | { 144 | if (n < 0) 145 | { 146 | err = errno; 147 | } 148 | break; 149 | } 150 | } 151 | } 152 | return err; 153 | } 154 | 155 | int FileUtil::ReadSmallFile::readToBuffer(int* size) 156 | { 157 | int err = err_; 158 | if (fd_ >= 0) 159 | { 160 | ssize_t n = ::pread(fd_, buf_, sizeof(buf_)-1, 0); 161 | if (n >= 0) 162 | { 163 | if (size) 164 | { 165 | *size = static_cast(n); 166 | } 167 | buf_[n] = '\0'; 168 | } 169 | else 170 | { 171 | err = errno; 172 | } 173 | } 174 | return err; 175 | } 176 | 177 | template int FileUtil::readFile(StringArg filename, 178 | int maxSize, 179 | string* content, 180 | int64_t*, int64_t*, int64_t*); 181 | 182 | template int FileUtil::ReadSmallFile::readToString( 183 | int maxSize, 184 | string* content, 185 | int64_t*, int64_t*, int64_t*); 186 | 187 | #ifndef MUDUO_STD_STRING 188 | template int FileUtil::readFile(StringArg filename, 189 | int maxSize, 190 | std::string* content, 191 | int64_t*, int64_t*, int64_t*); 192 | 193 | template int FileUtil::ReadSmallFile::readToString( 194 | int maxSize, 195 | std::string* content, 196 | int64_t*, int64_t*, int64_t*); 197 | #endif 198 | 199 | -------------------------------------------------------------------------------- /mucgi/muduo_base/FileUtil.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is a public header file, it must only include public header files. 10 | 11 | #ifndef MUDUO_BASE_FILEUTIL_H 12 | #define MUDUO_BASE_FILEUTIL_H 13 | 14 | #include "muduo_base/StringPiece.h" 15 | #include 16 | 17 | namespace muduo 18 | { 19 | 20 | namespace FileUtil 21 | { 22 | 23 | // read small file < 64KB 24 | class ReadSmallFile : boost::noncopyable 25 | { 26 | public: 27 | ReadSmallFile(StringArg filename); 28 | ~ReadSmallFile(); 29 | 30 | // return errno 31 | template 32 | int readToString(int maxSize, 33 | String* content, 34 | int64_t* fileSize, 35 | int64_t* modifyTime, 36 | int64_t* createTime); 37 | 38 | /// Read at maxium kBufferSize into buf_ 39 | // return errno 40 | int readToBuffer(int* size); 41 | 42 | const char* buffer() const { return buf_; } 43 | 44 | static const int kBufferSize = 64*1024; 45 | 46 | private: 47 | int fd_; 48 | int err_; 49 | char buf_[kBufferSize]; 50 | }; 51 | 52 | // read the file content, returns errno if error happens. 53 | template 54 | int readFile(StringArg filename, 55 | int maxSize, 56 | String* content, 57 | int64_t* fileSize = NULL, 58 | int64_t* modifyTime = NULL, 59 | int64_t* createTime = NULL) 60 | { 61 | ReadSmallFile file(filename); 62 | return file.readToString(maxSize, content, fileSize, modifyTime, createTime); 63 | } 64 | 65 | // not thread safe 66 | class AppendFile : boost::noncopyable 67 | { 68 | public: 69 | explicit AppendFile(StringArg filename); 70 | 71 | ~AppendFile(); 72 | 73 | void append(const char* logline, const size_t len); 74 | 75 | void flush(); 76 | 77 | size_t writtenBytes() const { return writtenBytes_; } 78 | 79 | private: 80 | 81 | size_t write(const char* logline, size_t len); 82 | 83 | FILE* fp_; 84 | char buffer_[64*1024]; 85 | size_t writtenBytes_; 86 | }; 87 | } 88 | 89 | } 90 | 91 | #endif // MUDUO_BASE_FILEUTIL_H 92 | 93 | -------------------------------------------------------------------------------- /mucgi/muduo_base/LogFile.cc: -------------------------------------------------------------------------------- 1 | #include "muduo_base/LogFile.h" 2 | 3 | #include "muduo_base/FileUtil.h" 4 | #include "muduo_base/ProcessInfo.h" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace muduo; 11 | 12 | LogFile::LogFile(const string& basename, 13 | size_t rollSize, 14 | bool threadSafe, 15 | int flushInterval, 16 | int checkEveryN) 17 | : basename_(basename), 18 | rollSize_(rollSize), 19 | flushInterval_(flushInterval), 20 | checkEveryN_(checkEveryN), 21 | count_(0), 22 | mutex_(threadSafe ? new MutexLock : NULL), 23 | startOfPeriod_(0), 24 | lastRoll_(0), 25 | lastFlush_(0) 26 | { 27 | assert(basename.find('/') == string::npos); 28 | rollFile(); 29 | } 30 | 31 | LogFile::~LogFile() 32 | { 33 | } 34 | 35 | void LogFile::append(const char* logline, int len) 36 | { 37 | if (mutex_) 38 | { 39 | MutexLockGuard lock(*mutex_); 40 | append_unlocked(logline, len); 41 | } 42 | else 43 | { 44 | append_unlocked(logline, len); 45 | } 46 | } 47 | 48 | void LogFile::flush() 49 | { 50 | if (mutex_) 51 | { 52 | MutexLockGuard lock(*mutex_); 53 | file_->flush(); 54 | } 55 | else 56 | { 57 | file_->flush(); 58 | } 59 | } 60 | 61 | void LogFile::append_unlocked(const char* logline, int len) 62 | { 63 | file_->append(logline, len); 64 | 65 | if (file_->writtenBytes() > rollSize_) 66 | { 67 | rollFile(); 68 | } 69 | else 70 | { 71 | ++count_; 72 | if (count_ >= checkEveryN_) 73 | { 74 | count_ = 0; 75 | time_t now = ::time(NULL); 76 | time_t thisPeriod_ = now / kRollPerSeconds_ * kRollPerSeconds_; 77 | if (thisPeriod_ != startOfPeriod_) 78 | { 79 | rollFile(); 80 | } 81 | else if (now - lastFlush_ > flushInterval_) 82 | { 83 | lastFlush_ = now; 84 | file_->flush(); 85 | } 86 | } 87 | } 88 | } 89 | 90 | bool LogFile::rollFile() 91 | { 92 | time_t now = 0; 93 | string filename = getLogFileName(basename_, &now); 94 | time_t start = now / kRollPerSeconds_ * kRollPerSeconds_; 95 | 96 | if (now > lastRoll_) 97 | { 98 | lastRoll_ = now; 99 | lastFlush_ = now; 100 | startOfPeriod_ = start; 101 | file_.reset(new FileUtil::AppendFile(filename)); 102 | return true; 103 | } 104 | return false; 105 | } 106 | 107 | string LogFile::getLogFileName(const string& basename, time_t* now) 108 | { 109 | string filename; 110 | filename.reserve(basename.size() + 64); 111 | filename = basename; 112 | 113 | char timebuf[32]; 114 | struct tm tm; 115 | *now = time(NULL); 116 | gmtime_r(now, &tm); // FIXME: localtime_r ? 117 | strftime(timebuf, sizeof timebuf, ".%Y%m%d-%H%M%S.", &tm); 118 | filename += timebuf; 119 | 120 | filename += ProcessInfo::hostname(); 121 | 122 | char pidbuf[32]; 123 | snprintf(pidbuf, sizeof pidbuf, ".%d", ProcessInfo::pid()); 124 | filename += pidbuf; 125 | 126 | filename += ".log"; 127 | 128 | return filename; 129 | } 130 | 131 | -------------------------------------------------------------------------------- /mucgi/muduo_base/LogFile.h: -------------------------------------------------------------------------------- 1 | #ifndef MUDUO_BASE_LOGFILE_H 2 | #define MUDUO_BASE_LOGFILE_H 3 | 4 | #include "muduo_base/Mutex.h" 5 | #include "muduo_base/Types.h" 6 | 7 | #include 8 | #include 9 | 10 | namespace muduo 11 | { 12 | 13 | namespace FileUtil 14 | { 15 | class AppendFile; 16 | } 17 | 18 | class LogFile : boost::noncopyable 19 | { 20 | public: 21 | LogFile(const string& basename, 22 | size_t rollSize, 23 | bool threadSafe = true, 24 | int flushInterval = 3, 25 | int checkEveryN = 1024); 26 | ~LogFile(); 27 | 28 | void append(const char* logline, int len); 29 | void flush(); 30 | bool rollFile(); 31 | 32 | private: 33 | void append_unlocked(const char* logline, int len); 34 | 35 | static string getLogFileName(const string& basename, time_t* now); 36 | 37 | const string basename_; 38 | const size_t rollSize_; 39 | const int flushInterval_; 40 | const int checkEveryN_; 41 | 42 | int count_; 43 | 44 | boost::scoped_ptr mutex_; 45 | time_t startOfPeriod_; 46 | time_t lastRoll_; 47 | time_t lastFlush_; 48 | boost::scoped_ptr file_; 49 | 50 | const static int kRollPerSeconds_ = 60*60*24; 51 | }; 52 | 53 | } 54 | #endif // MUDUO_BASE_LOGFILE_H 55 | -------------------------------------------------------------------------------- /mucgi/muduo_base/LogStream.cc: -------------------------------------------------------------------------------- 1 | #include "muduo_base/LogStream.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace muduo; 13 | using namespace muduo::detail; 14 | 15 | #if defined(__clang__) 16 | #pragma clang diagnostic ignored "-Wtautological-compare" 17 | #else 18 | #pragma GCC diagnostic ignored "-Wtype-limits" 19 | #endif 20 | 21 | namespace muduo 22 | { 23 | namespace detail 24 | { 25 | 26 | const char digits[] = "9876543210123456789"; 27 | const char* zero = digits + 9; 28 | BOOST_STATIC_ASSERT(sizeof(digits) == 20); 29 | 30 | const char digitsHex[] = "0123456789ABCDEF"; 31 | BOOST_STATIC_ASSERT(sizeof digitsHex == 17); 32 | 33 | // Efficient Integer to String Conversions, by Matthew Wilson. 34 | template 35 | size_t convert(char buf[], T value) 36 | { 37 | T i = value; 38 | char* p = buf; 39 | 40 | do 41 | { 42 | int lsd = static_cast(i % 10); 43 | i /= 10; 44 | *p++ = zero[lsd]; 45 | } while (i != 0); 46 | 47 | if (value < 0) 48 | { 49 | *p++ = '-'; 50 | } 51 | *p = '\0'; 52 | std::reverse(buf, p); 53 | 54 | return p - buf; 55 | } 56 | 57 | size_t convertHex(char buf[], uintptr_t value) 58 | { 59 | uintptr_t i = value; 60 | char* p = buf; 61 | 62 | do 63 | { 64 | int lsd = static_cast(i % 16); 65 | i /= 16; 66 | *p++ = digitsHex[lsd]; 67 | } while (i != 0); 68 | 69 | *p = '\0'; 70 | std::reverse(buf, p); 71 | 72 | return p - buf; 73 | } 74 | 75 | template class FixedBuffer; 76 | template class FixedBuffer; 77 | 78 | } 79 | } 80 | 81 | template 82 | const char* FixedBuffer::debugString() 83 | { 84 | *cur_ = '\0'; 85 | return data_; 86 | } 87 | 88 | template 89 | void FixedBuffer::cookieStart() 90 | { 91 | } 92 | 93 | template 94 | void FixedBuffer::cookieEnd() 95 | { 96 | } 97 | 98 | void LogStream::staticCheck() 99 | { 100 | BOOST_STATIC_ASSERT(kMaxNumericSize - 10 > std::numeric_limits::digits10); 101 | BOOST_STATIC_ASSERT(kMaxNumericSize - 10 > std::numeric_limits::digits10); 102 | BOOST_STATIC_ASSERT(kMaxNumericSize - 10 > std::numeric_limits::digits10); 103 | BOOST_STATIC_ASSERT(kMaxNumericSize - 10 > std::numeric_limits::digits10); 104 | } 105 | 106 | template 107 | void LogStream::formatInteger(T v) 108 | { 109 | if (buffer_.avail() >= kMaxNumericSize) 110 | { 111 | size_t len = convert(buffer_.current(), v); 112 | buffer_.add(len); 113 | } 114 | } 115 | 116 | LogStream& LogStream::operator<<(short v) 117 | { 118 | *this << static_cast(v); 119 | return *this; 120 | } 121 | 122 | LogStream& LogStream::operator<<(unsigned short v) 123 | { 124 | *this << static_cast(v); 125 | return *this; 126 | } 127 | 128 | LogStream& LogStream::operator<<(int v) 129 | { 130 | formatInteger(v); 131 | return *this; 132 | } 133 | 134 | LogStream& LogStream::operator<<(unsigned int v) 135 | { 136 | formatInteger(v); 137 | return *this; 138 | } 139 | 140 | LogStream& LogStream::operator<<(long v) 141 | { 142 | formatInteger(v); 143 | return *this; 144 | } 145 | 146 | LogStream& LogStream::operator<<(unsigned long v) 147 | { 148 | formatInteger(v); 149 | return *this; 150 | } 151 | 152 | LogStream& LogStream::operator<<(long long v) 153 | { 154 | formatInteger(v); 155 | return *this; 156 | } 157 | 158 | LogStream& LogStream::operator<<(unsigned long long v) 159 | { 160 | formatInteger(v); 161 | return *this; 162 | } 163 | 164 | LogStream& LogStream::operator<<(const void* p) 165 | { 166 | uintptr_t v = reinterpret_cast(p); 167 | if (buffer_.avail() >= kMaxNumericSize) 168 | { 169 | char* buf = buffer_.current(); 170 | buf[0] = '0'; 171 | buf[1] = 'x'; 172 | size_t len = convertHex(buf+2, v); 173 | buffer_.add(len+2); 174 | } 175 | return *this; 176 | } 177 | 178 | // FIXME: replace this with Grisu3 by Florian Loitsch. 179 | LogStream& LogStream::operator<<(double v) 180 | { 181 | if (buffer_.avail() >= kMaxNumericSize) 182 | { 183 | int len = snprintf(buffer_.current(), kMaxNumericSize, "%.12g", v); 184 | buffer_.add(len); 185 | } 186 | return *this; 187 | } 188 | 189 | template 190 | Fmt::Fmt(const char* fmt, T val) 191 | { 192 | BOOST_STATIC_ASSERT(boost::is_arithmetic::value == true); 193 | 194 | length_ = snprintf(buf_, sizeof buf_, fmt, val); 195 | assert(static_cast(length_) < sizeof buf_); 196 | } 197 | 198 | // Explicit instantiations 199 | 200 | template Fmt::Fmt(const char* fmt, char); 201 | 202 | template Fmt::Fmt(const char* fmt, short); 203 | template Fmt::Fmt(const char* fmt, unsigned short); 204 | template Fmt::Fmt(const char* fmt, int); 205 | template Fmt::Fmt(const char* fmt, unsigned int); 206 | template Fmt::Fmt(const char* fmt, long); 207 | template Fmt::Fmt(const char* fmt, unsigned long); 208 | template Fmt::Fmt(const char* fmt, long long); 209 | template Fmt::Fmt(const char* fmt, unsigned long long); 210 | 211 | template Fmt::Fmt(const char* fmt, float); 212 | template Fmt::Fmt(const char* fmt, double); 213 | -------------------------------------------------------------------------------- /mucgi/muduo_base/LogStream.h: -------------------------------------------------------------------------------- 1 | #ifndef MUDUO_BASE_LOGSTREAM_H 2 | #define MUDUO_BASE_LOGSTREAM_H 3 | 4 | #include "muduo_base/StringPiece.h" 5 | #include "muduo_base/Types.h" 6 | #include 7 | #include // memcpy 8 | #ifndef MUDUO_STD_STRING 9 | #include 10 | #endif 11 | #include 12 | 13 | namespace muduo 14 | { 15 | 16 | namespace detail 17 | { 18 | 19 | const int kSmallBuffer = 4000; 20 | const int kLargeBuffer = 4000*1000; 21 | 22 | template 23 | class FixedBuffer : boost::noncopyable 24 | { 25 | public: 26 | FixedBuffer() 27 | : cur_(data_) 28 | { 29 | setCookie(cookieStart); 30 | } 31 | 32 | ~FixedBuffer() 33 | { 34 | setCookie(cookieEnd); 35 | } 36 | 37 | void append(const char* /*restrict*/ buf, size_t len) 38 | { 39 | // FIXME: append partially 40 | if (implicit_cast(avail()) > len) 41 | { 42 | memcpy(cur_, buf, len); 43 | cur_ += len; 44 | } 45 | } 46 | 47 | const char* data() const { return data_; } 48 | int length() const { return static_cast(cur_ - data_); } 49 | 50 | // write to data_ directly 51 | char* current() { return cur_; } 52 | int avail() const { return static_cast(end() - cur_); } 53 | void add(size_t len) { cur_ += len; } 54 | 55 | void reset() { cur_ = data_; } 56 | void bzero() { ::bzero(data_, sizeof data_); } 57 | 58 | // for used by GDB 59 | const char* debugString(); 60 | void setCookie(void (*cookie)()) { cookie_ = cookie; } 61 | // for used by unit test 62 | string toString() const { return string(data_, length()); } 63 | StringPiece toStringPiece() const { return StringPiece(data_, length()); } 64 | 65 | private: 66 | const char* end() const { return data_ + sizeof data_; } 67 | // Must be outline function for cookies. 68 | static void cookieStart(); 69 | static void cookieEnd(); 70 | 71 | void (*cookie_)(); 72 | char data_[SIZE]; 73 | char* cur_; 74 | }; 75 | 76 | } 77 | 78 | class LogStream : boost::noncopyable 79 | { 80 | typedef LogStream self; 81 | public: 82 | typedef detail::FixedBuffer Buffer; 83 | 84 | self& operator<<(bool v) 85 | { 86 | buffer_.append(v ? "1" : "0", 1); 87 | return *this; 88 | } 89 | 90 | self& operator<<(short); 91 | self& operator<<(unsigned short); 92 | self& operator<<(int); 93 | self& operator<<(unsigned int); 94 | self& operator<<(long); 95 | self& operator<<(unsigned long); 96 | self& operator<<(long long); 97 | self& operator<<(unsigned long long); 98 | 99 | self& operator<<(const void*); 100 | 101 | self& operator<<(float v) 102 | { 103 | *this << static_cast(v); 104 | return *this; 105 | } 106 | self& operator<<(double); 107 | // self& operator<<(long double); 108 | 109 | self& operator<<(char v) 110 | { 111 | buffer_.append(&v, 1); 112 | return *this; 113 | } 114 | 115 | // self& operator<<(signed char); 116 | // self& operator<<(unsigned char); 117 | 118 | self& operator<<(const char* str) 119 | { 120 | if (str) 121 | { 122 | buffer_.append(str, strlen(str)); 123 | } 124 | else 125 | { 126 | buffer_.append("(null)", 6); 127 | } 128 | return *this; 129 | } 130 | 131 | self& operator<<(const unsigned char* str) 132 | { 133 | return operator<<(reinterpret_cast(str)); 134 | } 135 | 136 | self& operator<<(const string& v) 137 | { 138 | buffer_.append(v.c_str(), v.size()); 139 | return *this; 140 | } 141 | 142 | #ifndef MUDUO_STD_STRING 143 | self& operator<<(const std::string& v) 144 | { 145 | buffer_.append(v.c_str(), v.size()); 146 | return *this; 147 | } 148 | #endif 149 | 150 | self& operator<<(const StringPiece& v) 151 | { 152 | buffer_.append(v.data(), v.size()); 153 | return *this; 154 | } 155 | 156 | self& operator<<(const Buffer& v) 157 | { 158 | *this << v.toStringPiece(); 159 | return *this; 160 | } 161 | 162 | void append(const char* data, int len) { buffer_.append(data, len); } 163 | const Buffer& buffer() const { return buffer_; } 164 | void resetBuffer() { buffer_.reset(); } 165 | 166 | private: 167 | void staticCheck(); 168 | 169 | template 170 | void formatInteger(T); 171 | 172 | Buffer buffer_; 173 | 174 | static const int kMaxNumericSize = 32; 175 | }; 176 | 177 | class Fmt // : boost::noncopyable 178 | { 179 | public: 180 | template 181 | Fmt(const char* fmt, T val); 182 | 183 | const char* data() const { return buf_; } 184 | int length() const { return length_; } 185 | 186 | private: 187 | char buf_[32]; 188 | int length_; 189 | }; 190 | 191 | inline LogStream& operator<<(LogStream& s, const Fmt& fmt) 192 | { 193 | s.append(fmt.data(), fmt.length()); 194 | return s; 195 | } 196 | 197 | } 198 | #endif // MUDUO_BASE_LOGSTREAM_H 199 | 200 | -------------------------------------------------------------------------------- /mucgi/muduo_base/Logging.h: -------------------------------------------------------------------------------- 1 | #ifndef MUDUO_BASE_LOGGING_H 2 | #define MUDUO_BASE_LOGGING_H 3 | 4 | #include "muduo_base/LogStream.h" 5 | #include "muduo_base/Timestamp.h" 6 | 7 | namespace muduo 8 | { 9 | 10 | class TimeZone; 11 | 12 | class Logger 13 | { 14 | public: 15 | enum LogLevel 16 | { 17 | TRACE, 18 | DEBUG, 19 | INFO, 20 | WARN, 21 | ERROR, 22 | FATAL, 23 | NUM_LOG_LEVELS, 24 | }; 25 | 26 | // compile time calculation of basename of source file 27 | class SourceFile 28 | { 29 | public: 30 | template 31 | inline SourceFile(const char (&arr)[N]) 32 | : data_(arr), 33 | size_(N-1) 34 | { 35 | const char* slash = strrchr(data_, '/'); // builtin function 36 | if (slash) 37 | { 38 | data_ = slash + 1; 39 | size_ -= static_cast(data_ - arr); 40 | } 41 | } 42 | 43 | explicit SourceFile(const char* filename) 44 | : data_(filename) 45 | { 46 | const char* slash = strrchr(filename, '/'); 47 | if (slash) 48 | { 49 | data_ = slash + 1; 50 | } 51 | size_ = static_cast(strlen(data_)); 52 | } 53 | 54 | const char* data_; 55 | int size_; 56 | }; 57 | 58 | Logger(SourceFile file, int line); 59 | Logger(SourceFile file, int line, LogLevel level); 60 | Logger(SourceFile file, int line, LogLevel level, const char* func); 61 | Logger(SourceFile file, int line, bool toAbort); 62 | ~Logger(); 63 | 64 | LogStream& stream() { return impl_.stream_; } 65 | 66 | static LogLevel logLevel(); 67 | static void setLogLevel(LogLevel level); 68 | 69 | typedef void (*OutputFunc)(const char* msg, int len); 70 | typedef void (*FlushFunc)(); 71 | static void setOutput(OutputFunc); 72 | static void setFlush(FlushFunc); 73 | static void setTimeZone(const TimeZone& tz); 74 | 75 | private: 76 | 77 | class Impl 78 | { 79 | public: 80 | typedef Logger::LogLevel LogLevel; 81 | Impl(LogLevel level, int old_errno, const SourceFile& file, int line); 82 | void formatTime(); 83 | void finish(); 84 | 85 | Timestamp time_; 86 | LogStream stream_; 87 | LogLevel level_; 88 | int line_; 89 | SourceFile basename_; 90 | }; 91 | 92 | Impl impl_; 93 | 94 | }; 95 | 96 | extern Logger::LogLevel g_logLevel; 97 | 98 | inline Logger::LogLevel Logger::logLevel() 99 | { 100 | return g_logLevel; 101 | } 102 | 103 | // 104 | // CAUTION: do not write: 105 | // 106 | // if (good) 107 | // LOG_INFO << "Good news"; 108 | // else 109 | // LOG_WARN << "Bad news"; 110 | // 111 | // this expends to 112 | // 113 | // if (good) 114 | // if (logging_INFO) 115 | // logInfoStream << "Good news"; 116 | // else 117 | // logWarnStream << "Bad news"; 118 | // 119 | #define LOG_TRACE if (muduo::Logger::logLevel() <= muduo::Logger::TRACE) \ 120 | muduo::Logger(__FILE__, __LINE__, muduo::Logger::TRACE, __func__).stream() 121 | #define LOG_DEBUG if (muduo::Logger::logLevel() <= muduo::Logger::DEBUG) \ 122 | muduo::Logger(__FILE__, __LINE__, muduo::Logger::DEBUG, __func__).stream() 123 | #define LOG_INFO if (muduo::Logger::logLevel() <= muduo::Logger::INFO) \ 124 | muduo::Logger(__FILE__, __LINE__).stream() 125 | #define LOG_WARN muduo::Logger(__FILE__, __LINE__, muduo::Logger::WARN).stream() 126 | #define LOG_ERROR muduo::Logger(__FILE__, __LINE__, muduo::Logger::ERROR).stream() 127 | #define LOG_FATAL muduo::Logger(__FILE__, __LINE__, muduo::Logger::FATAL).stream() 128 | #define LOG_SYSERR muduo::Logger(__FILE__, __LINE__, false).stream() 129 | #define LOG_SYSFATAL muduo::Logger(__FILE__, __LINE__, true).stream() 130 | 131 | const char* strerror_tl(int savedErrno); 132 | 133 | // Taken from glog/logging.h 134 | // 135 | // Check that the input is non NULL. This very useful in constructor 136 | // initializer lists. 137 | 138 | #define CHECK_NOTNULL(val) \ 139 | ::muduo::CheckNotNull(__FILE__, __LINE__, "'" #val "' Must be non NULL", (val)) 140 | 141 | // A small helper for CHECK_NOTNULL(). 142 | template 143 | T* CheckNotNull(Logger::SourceFile file, int line, const char *names, T* ptr) 144 | { 145 | if (ptr == NULL) 146 | { 147 | Logger(file, line, Logger::FATAL).stream() << names; 148 | } 149 | return ptr; 150 | } 151 | 152 | } 153 | 154 | #endif // MUDUO_BASE_LOGGING_H 155 | -------------------------------------------------------------------------------- /mucgi/muduo_base/Mutex.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD-style license 2 | // that can be found in the License file. 3 | // 4 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 5 | 6 | #ifndef MUDUO_BASE_MUTEX_H 7 | #define MUDUO_BASE_MUTEX_H 8 | 9 | #include "muduo_base/CurrentThread.h" 10 | #include 11 | #include 12 | #include 13 | 14 | #ifdef CHECK_PTHREAD_RETURN_VALUE 15 | 16 | #ifdef NDEBUG 17 | __BEGIN_DECLS 18 | extern void __assert_perror_fail (int errnum, 19 | const char *file, 20 | unsigned int line, 21 | const char *function) 22 | __THROW __attribute__ ((__noreturn__)); 23 | __END_DECLS 24 | #endif 25 | 26 | #define MCHECK(ret) ({ __typeof__ (ret) errnum = (ret); \ 27 | if (__builtin_expect(errnum != 0, 0)) \ 28 | __assert_perror_fail (errnum, __FILE__, __LINE__, __func__);}) 29 | 30 | #else // CHECK_PTHREAD_RETURN_VALUE 31 | 32 | #define MCHECK(ret) ({ __typeof__ (ret) errnum = (ret); \ 33 | assert(errnum == 0); (void) errnum;}) 34 | 35 | #endif // CHECK_PTHREAD_RETURN_VALUE 36 | 37 | namespace muduo 38 | { 39 | 40 | // Use as data member of a class, eg. 41 | // 42 | // class Foo 43 | // { 44 | // public: 45 | // int size() const; 46 | // 47 | // private: 48 | // mutable MutexLock mutex_; 49 | // std::vector data_; // GUARDED BY mutex_ 50 | // }; 51 | class MutexLock : boost::noncopyable 52 | { 53 | public: 54 | MutexLock() 55 | : holder_(0) 56 | { 57 | MCHECK(pthread_mutex_init(&mutex_, NULL)); 58 | } 59 | 60 | ~MutexLock() 61 | { 62 | assert(holder_ == 0); 63 | MCHECK(pthread_mutex_destroy(&mutex_)); 64 | } 65 | 66 | // must be called when locked, i.e. for assertion 67 | bool isLockedByThisThread() const 68 | { 69 | return holder_ == CurrentThread::tid(); 70 | } 71 | 72 | void assertLocked() const 73 | { 74 | assert(isLockedByThisThread()); 75 | } 76 | 77 | // internal usage 78 | 79 | void lock() 80 | { 81 | MCHECK(pthread_mutex_lock(&mutex_)); 82 | assignHolder(); 83 | } 84 | 85 | void unlock() 86 | { 87 | unassignHolder(); 88 | MCHECK(pthread_mutex_unlock(&mutex_)); 89 | } 90 | 91 | pthread_mutex_t* getPthreadMutex() /* non-const */ 92 | { 93 | return &mutex_; 94 | } 95 | 96 | private: 97 | friend class Condition; 98 | 99 | class UnassignGuard : boost::noncopyable 100 | { 101 | public: 102 | UnassignGuard(MutexLock& owner) 103 | : owner_(owner) 104 | { 105 | owner_.unassignHolder(); 106 | } 107 | 108 | ~UnassignGuard() 109 | { 110 | owner_.assignHolder(); 111 | } 112 | 113 | private: 114 | MutexLock& owner_; 115 | }; 116 | 117 | void unassignHolder() 118 | { 119 | holder_ = 0; 120 | } 121 | 122 | void assignHolder() 123 | { 124 | holder_ = CurrentThread::tid(); 125 | } 126 | 127 | pthread_mutex_t mutex_; 128 | pid_t holder_; 129 | }; 130 | 131 | // Use as a stack variable, eg. 132 | // int Foo::size() const 133 | // { 134 | // MutexLockGuard lock(mutex_); 135 | // return data_.size(); 136 | // } 137 | class MutexLockGuard : boost::noncopyable 138 | { 139 | public: 140 | explicit MutexLockGuard(MutexLock& mutex) 141 | : mutex_(mutex) 142 | { 143 | mutex_.lock(); 144 | } 145 | 146 | ~MutexLockGuard() 147 | { 148 | mutex_.unlock(); 149 | } 150 | 151 | private: 152 | 153 | MutexLock& mutex_; 154 | }; 155 | 156 | } 157 | 158 | // Prevent misuse like: 159 | // MutexLockGuard(mutex_); 160 | // A tempory object doesn't hold the lock for long! 161 | #define MutexLockGuard(x) error "Missing guard object name" 162 | 163 | #endif // MUDUO_BASE_MUTEX_H 164 | -------------------------------------------------------------------------------- /mucgi/muduo_base/ProcessInfo.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is a public header file, it must only include public header files. 10 | 11 | #ifndef MUDUO_BASE_PROCESSINFO_H 12 | #define MUDUO_BASE_PROCESSINFO_H 13 | 14 | #include "muduo_base/StringPiece.h" 15 | #include "muduo_base/Types.h" 16 | #include "muduo_base/Timestamp.h" 17 | #include 18 | 19 | namespace muduo 20 | { 21 | 22 | namespace ProcessInfo 23 | { 24 | pid_t pid(); 25 | string pidString(); 26 | uid_t uid(); 27 | string username(); 28 | uid_t euid(); 29 | Timestamp startTime(); 30 | int clockTicksPerSecond(); 31 | int pageSize(); 32 | bool isDebugBuild(); // constexpr 33 | 34 | string hostname(); 35 | string procname(); 36 | StringPiece procname(const string& stat); 37 | 38 | /// read /proc/self/status 39 | string procStatus(); 40 | 41 | /// read /proc/self/stat 42 | string procStat(); 43 | 44 | /// read /proc/self/task/tid/stat 45 | string threadStat(); 46 | 47 | /// readlink /proc/self/exe 48 | string exePath(); 49 | 50 | int openedFiles(); 51 | int maxOpenFiles(); 52 | 53 | struct CpuTime 54 | { 55 | double userSeconds; 56 | double systemSeconds; 57 | 58 | CpuTime() : userSeconds(0.0), systemSeconds(0.0) { } 59 | }; 60 | CpuTime cpuTime(); 61 | 62 | int numThreads(); 63 | std::vector threads(); 64 | } 65 | 66 | } 67 | 68 | #endif // MUDUO_BASE_PROCESSINFO_H 69 | -------------------------------------------------------------------------------- /mucgi/muduo_base/Thread.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD-style license 2 | // that can be found in the License file. 3 | // 4 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 5 | 6 | #ifndef MUDUO_BASE_THREAD_H 7 | #define MUDUO_BASE_THREAD_H 8 | 9 | #include "muduo_base/Atomic.h" 10 | #include "muduo_base/Types.h" 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace muduo 18 | { 19 | 20 | class Thread : boost::noncopyable 21 | { 22 | public: 23 | typedef boost::function ThreadFunc; 24 | 25 | explicit Thread(const ThreadFunc&, const string& name = string()); 26 | #ifdef __GXX_EXPERIMENTAL_CXX0X__ 27 | explicit Thread(ThreadFunc&&, const string& name = string()); 28 | #endif 29 | ~Thread(); 30 | 31 | void start(); 32 | int join(); // return pthread_join() 33 | 34 | bool started() const { return started_; } 35 | // pthread_t pthreadId() const { return pthreadId_; } 36 | pid_t tid() const { return *tid_; } 37 | const string& name() const { return name_; } 38 | 39 | static int numCreated() { return numCreated_.get(); } 40 | 41 | private: 42 | void setDefaultName(); 43 | 44 | bool started_; 45 | bool joined_; 46 | pthread_t pthreadId_; 47 | boost::shared_ptr tid_; 48 | ThreadFunc func_; 49 | string name_; 50 | 51 | static AtomicInt32 numCreated_; 52 | }; 53 | 54 | } 55 | #endif 56 | -------------------------------------------------------------------------------- /mucgi/muduo_base/TimeZone.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD-style license 2 | // that can be found in the License file. 3 | // 4 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 5 | 6 | #ifndef MUDUO_BASE_TIMEZONE_H 7 | #define MUDUO_BASE_TIMEZONE_H 8 | 9 | #include "muduo_base/copyable.h" 10 | #include 11 | #include 12 | 13 | namespace muduo 14 | { 15 | 16 | // TimeZone for 1970~2030 17 | class TimeZone : public muduo::copyable 18 | { 19 | public: 20 | explicit TimeZone(const char* zonefile); 21 | TimeZone(int eastOfUtc, const char* tzname); // a fixed timezone 22 | TimeZone() {} // an invalid timezone 23 | 24 | // default copy ctor/assignment/dtor are Okay. 25 | 26 | bool valid() const 27 | { 28 | // 'explicit operator bool() const' in C++11 29 | return static_cast(data_); 30 | } 31 | 32 | struct tm toLocalTime(time_t secondsSinceEpoch) const; 33 | time_t fromLocalTime(const struct tm&) const; 34 | 35 | // gmtime(3) 36 | static struct tm toUtcTime(time_t secondsSinceEpoch, bool yday = false); 37 | // timegm(3) 38 | static time_t fromUtcTime(const struct tm&); 39 | // year in [1900..2500], month in [1..12], day in [1..31] 40 | static time_t fromUtcTime(int year, int month, int day, 41 | int hour, int minute, int seconds); 42 | 43 | struct Data; 44 | 45 | private: 46 | 47 | boost::shared_ptr data_; 48 | }; 49 | 50 | } 51 | #endif // MUDUO_BASE_TIMEZONE_H 52 | -------------------------------------------------------------------------------- /mucgi/muduo_base/Timestamp.cc: -------------------------------------------------------------------------------- 1 | #include "muduo_base/Timestamp.h" 2 | 3 | #include 4 | #include 5 | 6 | #ifndef __STDC_FORMAT_MACROS 7 | #define __STDC_FORMAT_MACROS 8 | #endif 9 | 10 | #include 11 | 12 | #include 13 | 14 | using namespace muduo; 15 | 16 | BOOST_STATIC_ASSERT(sizeof(Timestamp) == sizeof(int64_t)); 17 | 18 | string Timestamp::toString() const 19 | { 20 | char buf[32] = {0}; 21 | int64_t seconds = microSecondsSinceEpoch_ / kMicroSecondsPerSecond; 22 | int64_t microseconds = microSecondsSinceEpoch_ % kMicroSecondsPerSecond; 23 | snprintf(buf, sizeof(buf)-1, "%" PRId64 ".%06" PRId64 "", seconds, microseconds); 24 | return buf; 25 | } 26 | 27 | string Timestamp::toFormattedString(bool showMicroseconds) const 28 | { 29 | char buf[32] = {0}; 30 | time_t seconds = static_cast(microSecondsSinceEpoch_ / kMicroSecondsPerSecond); 31 | struct tm tm_time; 32 | gmtime_r(&seconds, &tm_time); 33 | 34 | if (showMicroseconds) 35 | { 36 | int microseconds = static_cast(microSecondsSinceEpoch_ % kMicroSecondsPerSecond); 37 | snprintf(buf, sizeof(buf), "%4d%02d%02d %02d:%02d:%02d.%06d", 38 | tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday, 39 | tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec, 40 | microseconds); 41 | } 42 | else 43 | { 44 | snprintf(buf, sizeof(buf), "%4d%02d%02d %02d:%02d:%02d", 45 | tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday, 46 | tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec); 47 | } 48 | return buf; 49 | } 50 | 51 | Timestamp Timestamp::now() 52 | { 53 | struct timeval tv; 54 | gettimeofday(&tv, NULL); 55 | int64_t seconds = tv.tv_sec; 56 | return Timestamp(seconds * kMicroSecondsPerSecond + tv.tv_usec); 57 | } 58 | 59 | -------------------------------------------------------------------------------- /mucgi/muduo_base/Timestamp.h: -------------------------------------------------------------------------------- 1 | #ifndef MUDUO_BASE_TIMESTAMP_H 2 | #define MUDUO_BASE_TIMESTAMP_H 3 | 4 | #include "muduo_base/copyable.h" 5 | #include "muduo_base/Types.h" 6 | 7 | #include 8 | 9 | namespace muduo 10 | { 11 | 12 | /// 13 | /// Time stamp in UTC, in microseconds resolution. 14 | /// 15 | /// This class is immutable. 16 | /// It's recommended to pass it by value, since it's passed in register on x64. 17 | /// 18 | class Timestamp : public muduo::copyable, 19 | public boost::less_than_comparable 20 | { 21 | public: 22 | /// 23 | /// Constucts an invalid Timestamp. 24 | /// 25 | Timestamp() 26 | : microSecondsSinceEpoch_(0) 27 | { 28 | } 29 | 30 | /// 31 | /// Constucts a Timestamp at specific time 32 | /// 33 | /// @param microSecondsSinceEpoch 34 | explicit Timestamp(int64_t microSecondsSinceEpochArg) 35 | : microSecondsSinceEpoch_(microSecondsSinceEpochArg) 36 | { 37 | } 38 | 39 | void swap(Timestamp& that) 40 | { 41 | std::swap(microSecondsSinceEpoch_, that.microSecondsSinceEpoch_); 42 | } 43 | 44 | // default copy/assignment/dtor are Okay 45 | 46 | string toString() const; 47 | string toFormattedString(bool showMicroseconds = true) const; 48 | 49 | bool valid() const { return microSecondsSinceEpoch_ > 0; } 50 | 51 | // for internal usage. 52 | int64_t microSecondsSinceEpoch() const { return microSecondsSinceEpoch_; } 53 | time_t secondsSinceEpoch() const 54 | { return static_cast(microSecondsSinceEpoch_ / kMicroSecondsPerSecond); } 55 | 56 | /// 57 | /// Get time of now. 58 | /// 59 | static Timestamp now(); 60 | static Timestamp invalid() 61 | { 62 | return Timestamp(); 63 | } 64 | 65 | static Timestamp fromUnixTime(time_t t) 66 | { 67 | return fromUnixTime(t, 0); 68 | } 69 | 70 | static Timestamp fromUnixTime(time_t t, int microseconds) 71 | { 72 | return Timestamp(static_cast(t) * kMicroSecondsPerSecond + microseconds); 73 | } 74 | 75 | static const int kMicroSecondsPerSecond = 1000 * 1000; 76 | 77 | private: 78 | int64_t microSecondsSinceEpoch_; 79 | }; 80 | 81 | inline bool operator<(Timestamp lhs, Timestamp rhs) 82 | { 83 | return lhs.microSecondsSinceEpoch() < rhs.microSecondsSinceEpoch(); 84 | } 85 | 86 | inline bool operator==(Timestamp lhs, Timestamp rhs) 87 | { 88 | return lhs.microSecondsSinceEpoch() == rhs.microSecondsSinceEpoch(); 89 | } 90 | 91 | /// 92 | /// Gets time difference of two timestamps, result in seconds. 93 | /// 94 | /// @param high, low 95 | /// @return (high-low) in seconds 96 | /// @c double has 52-bit precision, enough for one-microsecond 97 | /// resolution for next 100 years. 98 | inline double timeDifference(Timestamp high, Timestamp low) 99 | { 100 | int64_t diff = high.microSecondsSinceEpoch() - low.microSecondsSinceEpoch(); 101 | return static_cast(diff) / Timestamp::kMicroSecondsPerSecond; 102 | } 103 | 104 | /// 105 | /// Add @c seconds to given timestamp. 106 | /// 107 | /// @return timestamp+seconds as Timestamp 108 | /// 109 | inline Timestamp addTime(Timestamp timestamp, double seconds) 110 | { 111 | int64_t delta = static_cast(seconds * Timestamp::kMicroSecondsPerSecond); 112 | return Timestamp(timestamp.microSecondsSinceEpoch() + delta); 113 | } 114 | 115 | } 116 | #endif // MUDUO_BASE_TIMESTAMP_H 117 | -------------------------------------------------------------------------------- /mucgi/muduo_base/Types.h: -------------------------------------------------------------------------------- 1 | #ifndef MUDUO_BASE_TYPES_H 2 | #define MUDUO_BASE_TYPES_H 3 | 4 | #include 5 | #ifdef MUDUO_STD_STRING 6 | #include 7 | #else // !MUDUO_STD_STRING 8 | #include 9 | #include 10 | #endif 11 | 12 | #ifndef NDEBUG 13 | #include 14 | #endif 15 | 16 | /// 17 | /// The most common stuffs. 18 | /// 19 | namespace muduo 20 | { 21 | 22 | #ifdef MUDUO_STD_STRING 23 | using std::string; 24 | #else // !MUDUO_STD_STRING 25 | typedef __gnu_cxx::__sso_string string; 26 | #endif 27 | 28 | // Taken from google-protobuf stubs/common.h 29 | // 30 | // Protocol Buffers - Google's data interchange format 31 | // Copyright 2008 Google Inc. All rights reserved. 32 | // http://code.google.com/p/protobuf/ 33 | // 34 | // Redistribution and use in source and binary forms, with or without 35 | // modification, are permitted provided that the following conditions are 36 | // met: 37 | // 38 | // * Redistributions of source code must retain the above copyright 39 | // notice, this list of conditions and the following disclaimer. 40 | // * Redistributions in binary form must reproduce the above 41 | // copyright notice, this list of conditions and the following disclaimer 42 | // in the documentation and/or other materials provided with the 43 | // distribution. 44 | // * Neither the name of Google Inc. nor the names of its 45 | // contributors may be used to endorse or promote products derived from 46 | // this software without specific prior written permission. 47 | // 48 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 49 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 50 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 51 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 52 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 53 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 54 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 55 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 56 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 57 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 58 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 59 | 60 | // Author: kenton@google.com (Kenton Varda) and others 61 | // 62 | // Contains basic types and utilities used by the rest of the library. 63 | 64 | // 65 | // Use implicit_cast as a safe version of static_cast or const_cast 66 | // for upcasting in the type hierarchy (i.e. casting a pointer to Foo 67 | // to a pointer to SuperclassOfFoo or casting a pointer to Foo to 68 | // a const pointer to Foo). 69 | // When you use implicit_cast, the compiler checks that the cast is safe. 70 | // Such explicit implicit_casts are necessary in surprisingly many 71 | // situations where C++ demands an exact type match instead of an 72 | // argument type convertable to a target type. 73 | // 74 | // The From type can be inferred, so the preferred syntax for using 75 | // implicit_cast is the same as for static_cast etc.: 76 | // 77 | // implicit_cast(expr) 78 | // 79 | // implicit_cast would have been part of the C++ standard library, 80 | // but the proposal was submitted too late. It will probably make 81 | // its way into the language in the future. 82 | template 83 | inline To implicit_cast(From const &f) 84 | { 85 | return f; 86 | } 87 | 88 | // When you upcast (that is, cast a pointer from type Foo to type 89 | // SuperclassOfFoo), it's fine to use implicit_cast<>, since upcasts 90 | // always succeed. When you downcast (that is, cast a pointer from 91 | // type Foo to type SubclassOfFoo), static_cast<> isn't safe, because 92 | // how do you know the pointer is really of type SubclassOfFoo? It 93 | // could be a bare Foo, or of type DifferentSubclassOfFoo. Thus, 94 | // when you downcast, you should use this macro. In debug mode, we 95 | // use dynamic_cast<> to double-check the downcast is legal (we die 96 | // if it's not). In normal mode, we do the efficient static_cast<> 97 | // instead. Thus, it's important to test in debug mode to make sure 98 | // the cast is legal! 99 | // This is the only place in the code we should use dynamic_cast<>. 100 | // In particular, you SHOULDN'T be using dynamic_cast<> in order to 101 | // do RTTI (eg code like this: 102 | // if (dynamic_cast(foo)) HandleASubclass1Object(foo); 103 | // if (dynamic_cast(foo)) HandleASubclass2Object(foo); 104 | // You should design the code some other way not to need this. 105 | 106 | template // use like this: down_cast(foo); 107 | inline To down_cast(From* f) // so we only accept pointers 108 | { 109 | // Ensures that To is a sub-type of From *. This test is here only 110 | // for compile-time type checking, and has no overhead in an 111 | // optimized build at run-time, as it will be optimized away 112 | // completely. 113 | if (false) 114 | { 115 | implicit_cast(0); 116 | } 117 | 118 | #if !defined(NDEBUG) && !defined(GOOGLE_PROTOBUF_NO_RTTI) 119 | assert(f == NULL || dynamic_cast(f) != NULL); // RTTI: debug mode only! 120 | #endif 121 | return static_cast(f); 122 | } 123 | 124 | } 125 | 126 | #endif 127 | -------------------------------------------------------------------------------- /mucgi/muduo_base/WeakCallback.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | // 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | 9 | #ifndef MUDUO_BASE_WEAKCALLBACK_H 10 | #define MUDUO_BASE_WEAKCALLBACK_H 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | namespace muduo 17 | { 18 | 19 | // A barely usable WeakCallback 20 | 21 | #ifdef __GXX_EXPERIMENTAL_CXX0X__ 22 | 23 | // FIXME: support std::shared_ptr as well, maybe using template template parameters 24 | 25 | template 26 | class WeakCallback 27 | { 28 | public: 29 | 30 | WeakCallback(const boost::weak_ptr& object, 31 | const std::function& function) 32 | : object_(object), function_(function) 33 | { 34 | } 35 | 36 | // Default dtor, copy ctor and assignment are okay 37 | 38 | void operator()(ARGS&&... args) const 39 | { 40 | boost::shared_ptr ptr(object_.lock()); 41 | if (ptr) 42 | { 43 | function_(ptr.get(), std::forward(args)...); 44 | } 45 | // else 46 | // { 47 | // LOG_TRACE << "expired"; 48 | // } 49 | } 50 | 51 | private: 52 | 53 | boost::weak_ptr object_; 54 | std::function function_; 55 | }; 56 | 57 | template 58 | WeakCallback makeWeakCallback(const boost::shared_ptr& object, 59 | void (CLASS::*function)(ARGS...)) 60 | { 61 | return WeakCallback(object, function); 62 | } 63 | 64 | template 65 | WeakCallback makeWeakCallback(const boost::shared_ptr& object, 66 | void (CLASS::*function)(ARGS...) const) 67 | { 68 | return WeakCallback(object, function); 69 | } 70 | 71 | #else // __GXX_EXPERIMENTAL_CXX0X__ 72 | 73 | // the C++98/03 version doesn't support arguments. 74 | 75 | template 76 | class WeakCallback 77 | { 78 | public: 79 | 80 | WeakCallback(const boost::weak_ptr& object, 81 | const boost::function& function) 82 | : object_(object), function_(function) 83 | { 84 | } 85 | 86 | // Default dtor, copy ctor and assignment are okay 87 | 88 | void operator()() const 89 | { 90 | boost::shared_ptr ptr(object_.lock()); 91 | if (ptr) 92 | { 93 | function_(ptr.get()); 94 | } 95 | // else 96 | // { 97 | // LOG_TRACE << "expired"; 98 | // } 99 | } 100 | 101 | private: 102 | 103 | boost::weak_ptr object_; 104 | boost::function function_; 105 | }; 106 | 107 | template 108 | WeakCallback makeWeakCallback(const boost::shared_ptr& object, 109 | void (CLASS::*function)()) 110 | { 111 | return WeakCallback(object, function); 112 | } 113 | 114 | template 115 | WeakCallback makeWeakCallback(const boost::shared_ptr& object, 116 | void (CLASS::*function)() const) 117 | { 118 | return WeakCallback(object, function); 119 | } 120 | 121 | #endif // __GXX_EXPERIMENTAL_CXX0X__ 122 | } 123 | 124 | #endif 125 | -------------------------------------------------------------------------------- /mucgi/muduo_base/copyable.h: -------------------------------------------------------------------------------- 1 | #ifndef MUDUO_BASE_COPYABLE_H 2 | #define MUDUO_BASE_COPYABLE_H 3 | 4 | namespace muduo 5 | { 6 | 7 | /// A tag class emphasises the objects are copyable. 8 | /// The empty base class optimization applies. 9 | /// Any derived class of copyable should be a value type. 10 | class copyable 11 | { 12 | }; 13 | 14 | }; 15 | 16 | #endif // MUDUO_BASE_COPYABLE_H 17 | -------------------------------------------------------------------------------- /mucgi/muduo_net/Acceptor.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | 9 | #include "muduo_net/Acceptor.h" 10 | 11 | #include "muduo_base/Logging.h" 12 | #include "muduo_net/EventLoop.h" 13 | #include "muduo_net/InetAddress.h" 14 | #include "muduo_net/SocketsOps.h" 15 | 16 | #include 17 | 18 | #include 19 | #include 20 | //#include 21 | //#include 22 | 23 | using namespace muduo; 24 | using namespace muduo::net; 25 | 26 | Acceptor::Acceptor(EventLoop* loop, const InetAddress& listenAddr, bool reuseport) 27 | : loop_(loop), 28 | acceptSocket_(sockets::createNonblockingOrDie(listenAddr.family())), 29 | acceptChannel_(loop, acceptSocket_.fd()), 30 | listenning_(false), 31 | idleFd_(::open("/dev/null", O_RDONLY | O_CLOEXEC)) 32 | { 33 | assert(idleFd_ >= 0); 34 | acceptSocket_.setReuseAddr(true); 35 | acceptSocket_.setReusePort(reuseport); 36 | acceptSocket_.bindAddress(listenAddr); 37 | acceptChannel_.setReadCallback( 38 | boost::bind(&Acceptor::handleRead, this)); 39 | } 40 | 41 | Acceptor::~Acceptor() 42 | { 43 | acceptChannel_.disableAll(); 44 | acceptChannel_.remove(); 45 | ::close(idleFd_); 46 | } 47 | 48 | void Acceptor::listen() 49 | { 50 | loop_->assertInLoopThread(); 51 | listenning_ = true; 52 | acceptSocket_.listen(); 53 | acceptChannel_.enableReading(); 54 | } 55 | 56 | void Acceptor::handleRead() 57 | { 58 | loop_->assertInLoopThread(); 59 | InetAddress peerAddr; 60 | //FIXME loop until no more 61 | int connfd = acceptSocket_.accept(&peerAddr); 62 | if (connfd >= 0) 63 | { 64 | // string hostport = peerAddr.toIpPort(); 65 | // LOG_TRACE << "Accepts of " << hostport; 66 | if (newConnectionCallback_) 67 | { 68 | newConnectionCallback_(connfd, peerAddr); 69 | } 70 | else 71 | { 72 | sockets::close(connfd); 73 | } 74 | } 75 | else 76 | { 77 | LOG_SYSERR << "in Acceptor::handleRead"; 78 | // Read the section named "The special problem of 79 | // accept()ing when you can't" in libev's doc. 80 | // By Marc Lehmann, author of libev. 81 | if (errno == EMFILE) 82 | { 83 | ::close(idleFd_); 84 | idleFd_ = ::accept(acceptSocket_.fd(), NULL, NULL); 85 | ::close(idleFd_); 86 | idleFd_ = ::open("/dev/null", O_RDONLY | O_CLOEXEC); 87 | } 88 | } 89 | } 90 | 91 | -------------------------------------------------------------------------------- /mucgi/muduo_net/Acceptor.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is an internal header file, you should not include this. 10 | 11 | #ifndef MUDUO_NET_ACCEPTOR_H 12 | #define MUDUO_NET_ACCEPTOR_H 13 | 14 | #include 15 | #include 16 | 17 | #include "muduo_net/Channel.h" 18 | #include "muduo_net/Socket.h" 19 | 20 | namespace muduo 21 | { 22 | namespace net 23 | { 24 | 25 | class EventLoop; 26 | class InetAddress; 27 | 28 | /// 29 | /// Acceptor of incoming TCP connections. 30 | /// 31 | class Acceptor : boost::noncopyable 32 | { 33 | public: 34 | typedef boost::function NewConnectionCallback; 36 | 37 | Acceptor(EventLoop* loop, const InetAddress& listenAddr, bool reuseport); 38 | ~Acceptor(); 39 | 40 | void setNewConnectionCallback(const NewConnectionCallback& cb) 41 | { newConnectionCallback_ = cb; } 42 | 43 | bool listenning() const { return listenning_; } 44 | void listen(); 45 | 46 | private: 47 | void handleRead(); 48 | 49 | EventLoop* loop_; 50 | Socket acceptSocket_; 51 | Channel acceptChannel_; 52 | NewConnectionCallback newConnectionCallback_; 53 | bool listenning_; 54 | int idleFd_; 55 | }; 56 | 57 | } 58 | } 59 | 60 | #endif // MUDUO_NET_ACCEPTOR_H 61 | -------------------------------------------------------------------------------- /mucgi/muduo_net/Buffer.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | 10 | #include "muduo_net/Buffer.h" 11 | 12 | #include "muduo_net/SocketsOps.h" 13 | 14 | #include 15 | #include 16 | 17 | using namespace muduo; 18 | using namespace muduo::net; 19 | 20 | const char Buffer::kCRLF[] = "\r\n"; 21 | 22 | const size_t Buffer::kCheapPrepend; 23 | const size_t Buffer::kInitialSize; 24 | 25 | ssize_t Buffer::readFd(int fd, int* savedErrno) 26 | { 27 | // saved an ioctl()/FIONREAD call to tell how much to read 28 | char extrabuf[65536]; 29 | struct iovec vec[2]; 30 | const size_t writable = writableBytes(); 31 | vec[0].iov_base = begin()+writerIndex_; 32 | vec[0].iov_len = writable; 33 | vec[1].iov_base = extrabuf; 34 | vec[1].iov_len = sizeof extrabuf; 35 | // when there is enough space in this buffer, don't read into extrabuf. 36 | // when extrabuf is used, we read 128k-1 bytes at most. 37 | const int iovcnt = (writable < sizeof extrabuf) ? 2 : 1; 38 | const ssize_t n = sockets::readv(fd, vec, iovcnt); 39 | if (n < 0) 40 | { 41 | *savedErrno = errno; 42 | } 43 | else if (implicit_cast(n) <= writable) 44 | { 45 | writerIndex_ += n; 46 | } 47 | else 48 | { 49 | writerIndex_ = buffer_.size(); 50 | append(extrabuf, n - writable); 51 | } 52 | // if (n == writable + sizeof extrabuf) 53 | // { 54 | // goto line_30; 55 | // } 56 | return n; 57 | } 58 | 59 | -------------------------------------------------------------------------------- /mucgi/muduo_net/Callbacks.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is a public header file, it must only include public header files. 10 | 11 | #ifndef MUDUO_NET_CALLBACKS_H 12 | #define MUDUO_NET_CALLBACKS_H 13 | 14 | #include 15 | #include 16 | 17 | #include "muduo_base/Timestamp.h" 18 | 19 | namespace muduo 20 | { 21 | 22 | // Adapted from google-protobuf stubs/common.h 23 | // see License in muduo/base/Types.h 24 | template 25 | inline ::boost::shared_ptr down_pointer_cast(const ::boost::shared_ptr& f) 26 | { 27 | if (false) 28 | { 29 | implicit_cast(0); 30 | } 31 | 32 | #ifndef NDEBUG 33 | assert(f == NULL || dynamic_cast(get_pointer(f)) != NULL); 34 | #endif 35 | return ::boost::static_pointer_cast(f); 36 | } 37 | 38 | namespace net 39 | { 40 | 41 | // All client visible callbacks go here. 42 | 43 | class Buffer; 44 | class TcpConnection; 45 | typedef boost::shared_ptr TcpConnectionPtr; 46 | typedef boost::function TimerCallback; 47 | typedef boost::function ConnectionCallback; 48 | typedef boost::function CloseCallback; 49 | typedef boost::function WriteCompleteCallback; 50 | typedef boost::function HighWaterMarkCallback; 51 | 52 | // the data has been read to (buf, len) 53 | typedef boost::function MessageCallback; 56 | 57 | void defaultConnectionCallback(const TcpConnectionPtr& conn); 58 | void defaultMessageCallback(const TcpConnectionPtr& conn, 59 | Buffer* buffer, 60 | Timestamp receiveTime); 61 | 62 | } 63 | } 64 | 65 | #endif // MUDUO_NET_CALLBACKS_H 66 | -------------------------------------------------------------------------------- /mucgi/muduo_net/Channel.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | 9 | #include "muduo_base/Logging.h" 10 | #include "muduo_net/Channel.h" 11 | #include "muduo_net/EventLoop.h" 12 | 13 | #include 14 | 15 | #include 16 | 17 | using namespace muduo; 18 | using namespace muduo::net; 19 | 20 | const int Channel::kNoneEvent = 0; 21 | const int Channel::kReadEvent = POLLIN | POLLPRI; 22 | const int Channel::kWriteEvent = POLLOUT; 23 | 24 | Channel::Channel(EventLoop* loop, int fd__) 25 | : loop_(loop), 26 | fd_(fd__), 27 | events_(0), 28 | revents_(0), 29 | index_(-1), 30 | logHup_(true), 31 | tied_(false), 32 | eventHandling_(false), 33 | addedToLoop_(false) 34 | { 35 | } 36 | 37 | Channel::~Channel() 38 | { 39 | assert(!eventHandling_); 40 | assert(!addedToLoop_); 41 | if (loop_->isInLoopThread()) 42 | { 43 | assert(!loop_->hasChannel(this)); 44 | } 45 | } 46 | 47 | void Channel::tie(const boost::shared_ptr& obj) 48 | { 49 | tie_ = obj; 50 | tied_ = true; 51 | } 52 | 53 | void Channel::update() 54 | { 55 | addedToLoop_ = true; 56 | loop_->updateChannel(this); 57 | } 58 | 59 | void Channel::remove() 60 | { 61 | assert(isNoneEvent()); 62 | addedToLoop_ = false; 63 | loop_->removeChannel(this); 64 | } 65 | 66 | void Channel::handleEvent(Timestamp receiveTime) 67 | { 68 | boost::shared_ptr guard; 69 | if (tied_) 70 | { 71 | guard = tie_.lock(); 72 | if (guard) 73 | { 74 | handleEventWithGuard(receiveTime); 75 | } 76 | } 77 | else 78 | { 79 | handleEventWithGuard(receiveTime); 80 | } 81 | } 82 | 83 | void Channel::handleEventWithGuard(Timestamp receiveTime) 84 | { 85 | eventHandling_ = true; 86 | LOG_TRACE << reventsToString(); 87 | if ((revents_ & POLLHUP) && !(revents_ & POLLIN)) 88 | { 89 | if (logHup_) 90 | { 91 | LOG_WARN << "fd = " << fd_ << " Channel::handle_event() POLLHUP"; 92 | } 93 | if (closeCallback_) closeCallback_(); 94 | } 95 | 96 | if (revents_ & POLLNVAL) 97 | { 98 | LOG_WARN << "fd = " << fd_ << " Channel::handle_event() POLLNVAL"; 99 | } 100 | 101 | if (revents_ & (POLLERR | POLLNVAL)) 102 | { 103 | if (errorCallback_) errorCallback_(); 104 | } 105 | if (revents_ & (POLLIN | POLLPRI | POLLRDHUP)) 106 | { 107 | if (readCallback_) readCallback_(receiveTime); 108 | } 109 | if (revents_ & POLLOUT) 110 | { 111 | if (writeCallback_) writeCallback_(); 112 | } 113 | eventHandling_ = false; 114 | } 115 | 116 | string Channel::reventsToString() const 117 | { 118 | return eventsToString(fd_, revents_); 119 | } 120 | 121 | string Channel::eventsToString() const 122 | { 123 | return eventsToString(fd_, events_); 124 | } 125 | 126 | string Channel::eventsToString(int fd, int ev) 127 | { 128 | std::ostringstream oss; 129 | oss << fd << ": "; 130 | if (ev & POLLIN) 131 | oss << "IN "; 132 | if (ev & POLLPRI) 133 | oss << "PRI "; 134 | if (ev & POLLOUT) 135 | oss << "OUT "; 136 | if (ev & POLLHUP) 137 | oss << "HUP "; 138 | if (ev & POLLRDHUP) 139 | oss << "RDHUP "; 140 | if (ev & POLLERR) 141 | oss << "ERR "; 142 | if (ev & POLLNVAL) 143 | oss << "NVAL "; 144 | 145 | return oss.str().c_str(); 146 | } 147 | -------------------------------------------------------------------------------- /mucgi/muduo_net/Channel.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is an internal header file, you should not include this. 10 | 11 | #ifndef MUDUO_NET_CHANNEL_H 12 | #define MUDUO_NET_CHANNEL_H 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "muduo_base/Timestamp.h" 20 | 21 | namespace muduo 22 | { 23 | namespace net 24 | { 25 | 26 | class EventLoop; 27 | 28 | /// 29 | /// A selectable I/O channel. 30 | /// 31 | /// This class doesn't own the file descriptor. 32 | /// The file descriptor could be a socket, 33 | /// an eventfd, a timerfd, or a signalfd 34 | class Channel : boost::noncopyable 35 | { 36 | public: 37 | typedef boost::function EventCallback; 38 | typedef boost::function ReadEventCallback; 39 | 40 | Channel(EventLoop* loop, int fd); 41 | ~Channel(); 42 | 43 | void handleEvent(Timestamp receiveTime); 44 | void setReadCallback(const ReadEventCallback& cb) 45 | { readCallback_ = cb; } 46 | void setWriteCallback(const EventCallback& cb) 47 | { writeCallback_ = cb; } 48 | void setCloseCallback(const EventCallback& cb) 49 | { closeCallback_ = cb; } 50 | void setErrorCallback(const EventCallback& cb) 51 | { errorCallback_ = cb; } 52 | #ifdef __GXX_EXPERIMENTAL_CXX0X__ 53 | void setReadCallback(ReadEventCallback&& cb) 54 | { readCallback_ = std::move(cb); } 55 | void setWriteCallback(EventCallback&& cb) 56 | { writeCallback_ = std::move(cb); } 57 | void setCloseCallback(EventCallback&& cb) 58 | { closeCallback_ = std::move(cb); } 59 | void setErrorCallback(EventCallback&& cb) 60 | { errorCallback_ = std::move(cb); } 61 | #endif 62 | 63 | /// Tie this channel to the owner object managed by shared_ptr, 64 | /// prevent the owner object being destroyed in handleEvent. 65 | void tie(const boost::shared_ptr&); 66 | 67 | int fd() const { return fd_; } 68 | int events() const { return events_; } 69 | void set_revents(int revt) { revents_ = revt; } // used by pollers 70 | // int revents() const { return revents_; } 71 | bool isNoneEvent() const { return events_ == kNoneEvent; } 72 | 73 | void enableReading() { events_ |= kReadEvent; update(); } 74 | void disableReading() { events_ &= ~kReadEvent; update(); } 75 | void enableWriting() { events_ |= kWriteEvent; update(); } 76 | void disableWriting() { events_ &= ~kWriteEvent; update(); } 77 | void disableAll() { events_ = kNoneEvent; update(); } 78 | bool isWriting() const { return events_ & kWriteEvent; } 79 | bool isReading() const { return events_ & kReadEvent; } 80 | 81 | // for Poller 82 | int index() { return index_; } 83 | void set_index(int idx) { index_ = idx; } 84 | 85 | // for debug 86 | string reventsToString() const; 87 | string eventsToString() const; 88 | 89 | void doNotLogHup() { logHup_ = false; } 90 | 91 | EventLoop* ownerLoop() { return loop_; } 92 | void remove(); 93 | 94 | private: 95 | static string eventsToString(int fd, int ev); 96 | 97 | void update(); 98 | void handleEventWithGuard(Timestamp receiveTime); 99 | 100 | static const int kNoneEvent; 101 | static const int kReadEvent; 102 | static const int kWriteEvent; 103 | 104 | EventLoop* loop_; 105 | const int fd_; 106 | int events_; 107 | int revents_; // it's the received event types of epoll or poll 108 | int index_; // used by Poller. 109 | bool logHup_; 110 | 111 | boost::weak_ptr tie_; 112 | bool tied_; 113 | bool eventHandling_; 114 | bool addedToLoop_; 115 | ReadEventCallback readCallback_; 116 | EventCallback writeCallback_; 117 | EventCallback closeCallback_; 118 | EventCallback errorCallback_; 119 | }; 120 | 121 | } 122 | } 123 | #endif // MUDUO_NET_CHANNEL_H 124 | -------------------------------------------------------------------------------- /mucgi/muduo_net/DefaultPoller.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | 9 | #include "muduo_net/Poller.h" 10 | #include "muduo_net/PollPoller.h" 11 | #include "muduo_net/EPollPoller.h" 12 | 13 | #include 14 | 15 | using namespace muduo::net; 16 | 17 | Poller* Poller::newDefaultPoller(EventLoop* loop) 18 | { 19 | if (::getenv("MUDUO_USE_POLL")) 20 | { 21 | return new PollPoller(loop); 22 | } 23 | else 24 | { 25 | return new EPollPoller(loop); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /mucgi/muduo_net/EPollPoller.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is an internal header file, you should not include this. 10 | 11 | #ifndef MUDUO_NET_POLLER_EPOLLPOLLER_H 12 | #define MUDUO_NET_POLLER_EPOLLPOLLER_H 13 | 14 | #include "muduo_net/Poller.h" 15 | 16 | #include 17 | 18 | struct epoll_event; 19 | 20 | namespace muduo 21 | { 22 | namespace net 23 | { 24 | 25 | /// 26 | /// IO Multiplexing with epoll(4). 27 | /// 28 | class EPollPoller : public Poller 29 | { 30 | public: 31 | EPollPoller(EventLoop* loop); 32 | virtual ~EPollPoller(); 33 | 34 | virtual Timestamp poll(int timeoutMs, ChannelList* activeChannels); 35 | virtual void updateChannel(Channel* channel); 36 | virtual void removeChannel(Channel* channel); 37 | 38 | private: 39 | static const int kInitEventListSize = 16; 40 | 41 | static const char* operationToString(int op); 42 | 43 | void fillActiveChannels(int numEvents, 44 | ChannelList* activeChannels) const; 45 | void update(int operation, Channel* channel); 46 | 47 | typedef std::vector EventList; 48 | 49 | int epollfd_; 50 | EventList events_; 51 | }; 52 | 53 | } 54 | } 55 | #endif // MUDUO_NET_POLLER_EPOLLPOLLER_H 56 | -------------------------------------------------------------------------------- /mucgi/muduo_net/Endian.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is a public header file, it must only include public header files. 10 | 11 | #ifndef MUDUO_NET_ENDIAN_H 12 | #define MUDUO_NET_ENDIAN_H 13 | 14 | #include 15 | #include 16 | 17 | namespace muduo 18 | { 19 | namespace net 20 | { 21 | namespace sockets 22 | { 23 | 24 | // the inline assembler code makes type blur, 25 | // so we disable warnings for a while. 26 | #if defined(__clang__) || __GNUC_PREREQ (4,6) 27 | #pragma GCC diagnostic push 28 | #endif 29 | #pragma GCC diagnostic ignored "-Wconversion" 30 | #pragma GCC diagnostic ignored "-Wold-style-cast" 31 | inline uint64_t hostToNetwork64(uint64_t host64) 32 | { 33 | return htobe64(host64); 34 | } 35 | 36 | inline uint32_t hostToNetwork32(uint32_t host32) 37 | { 38 | return htobe32(host32); 39 | } 40 | 41 | inline uint16_t hostToNetwork16(uint16_t host16) 42 | { 43 | return htobe16(host16); 44 | } 45 | 46 | inline uint64_t networkToHost64(uint64_t net64) 47 | { 48 | return be64toh(net64); 49 | } 50 | 51 | inline uint32_t networkToHost32(uint32_t net32) 52 | { 53 | return be32toh(net32); 54 | } 55 | 56 | inline uint16_t networkToHost16(uint16_t net16) 57 | { 58 | return be16toh(net16); 59 | } 60 | #if defined(__clang__) || __GNUC_PREREQ (4,6) 61 | #pragma GCC diagnostic pop 62 | #else 63 | #pragma GCC diagnostic warning "-Wconversion" 64 | #pragma GCC diagnostic warning "-Wold-style-cast" 65 | #endif 66 | 67 | 68 | } 69 | } 70 | } 71 | 72 | #endif // MUDUO_NET_ENDIAN_H 73 | -------------------------------------------------------------------------------- /mucgi/muduo_net/EventLoop.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is a public header file, it must only include public header files. 10 | 11 | #ifndef MUDUO_NET_EVENTLOOP_H 12 | #define MUDUO_NET_EVENTLOOP_H 13 | 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include "muduo_base/Mutex.h" 22 | #include "muduo_base/CurrentThread.h" 23 | #include "muduo_base/Timestamp.h" 24 | #include "muduo_net/Callbacks.h" 25 | #include "muduo_net/TimerId.h" 26 | 27 | namespace muduo 28 | { 29 | namespace net 30 | { 31 | 32 | class Channel; 33 | class Poller; 34 | class TimerQueue; 35 | 36 | /// 37 | /// Reactor, at most one per thread. 38 | /// 39 | /// This is an interface class, so don't expose too much details. 40 | class EventLoop : boost::noncopyable 41 | { 42 | public: 43 | typedef boost::function Functor; 44 | 45 | EventLoop(); 46 | ~EventLoop(); // force out-line dtor, for scoped_ptr members. 47 | 48 | /// 49 | /// Loops forever. 50 | /// 51 | /// Must be called in the same thread as creation of the object. 52 | /// 53 | void loop(); 54 | 55 | /// Quits loop. 56 | /// 57 | /// This is not 100% thread safe, if you call through a raw pointer, 58 | /// better to call through shared_ptr for 100% safety. 59 | void quit(); 60 | 61 | /// 62 | /// Time when poll returns, usually means data arrival. 63 | /// 64 | Timestamp pollReturnTime() const { return pollReturnTime_; } 65 | 66 | int64_t iteration() const { return iteration_; } 67 | 68 | /// Runs callback immediately in the loop thread. 69 | /// It wakes up the loop, and run the cb. 70 | /// If in the same loop thread, cb is run within the function. 71 | /// Safe to call from other threads. 72 | void runInLoop(const Functor& cb); 73 | /// Queues callback in the loop thread. 74 | /// Runs after finish pooling. 75 | /// Safe to call from other threads. 76 | void queueInLoop(const Functor& cb); 77 | 78 | size_t queueSize() const; 79 | 80 | #ifdef __GXX_EXPERIMENTAL_CXX0X__ 81 | void runInLoop(Functor&& cb); 82 | void queueInLoop(Functor&& cb); 83 | #endif 84 | 85 | // timers 86 | 87 | /// 88 | /// Runs callback at 'time'. 89 | /// Safe to call from other threads. 90 | /// 91 | TimerId runAt(const Timestamp& time, const TimerCallback& cb); 92 | /// 93 | /// Runs callback after @c delay seconds. 94 | /// Safe to call from other threads. 95 | /// 96 | TimerId runAfter(double delay, const TimerCallback& cb); 97 | /// 98 | /// Runs callback every @c interval seconds. 99 | /// Safe to call from other threads. 100 | /// 101 | TimerId runEvery(double interval, const TimerCallback& cb); 102 | /// 103 | /// Cancels the timer. 104 | /// Safe to call from other threads. 105 | /// 106 | void cancel(TimerId timerId); 107 | 108 | #ifdef __GXX_EXPERIMENTAL_CXX0X__ 109 | TimerId runAt(const Timestamp& time, TimerCallback&& cb); 110 | TimerId runAfter(double delay, TimerCallback&& cb); 111 | TimerId runEvery(double interval, TimerCallback&& cb); 112 | #endif 113 | 114 | // internal usage 115 | void wakeup(); 116 | void updateChannel(Channel* channel); 117 | void removeChannel(Channel* channel); 118 | bool hasChannel(Channel* channel); 119 | 120 | // pid_t threadId() const { return threadId_; } 121 | void assertInLoopThread() 122 | { 123 | if (!isInLoopThread()) 124 | { 125 | abortNotInLoopThread(); 126 | } 127 | } 128 | bool isInLoopThread() const { return threadId_ == CurrentThread::tid(); } 129 | // bool callingPendingFunctors() const { return callingPendingFunctors_; } 130 | bool eventHandling() const { return eventHandling_; } 131 | 132 | void setContext(const boost::any& context) 133 | { context_ = context; } 134 | 135 | const boost::any& getContext() const 136 | { return context_; } 137 | 138 | boost::any* getMutableContext() 139 | { return &context_; } 140 | 141 | static EventLoop* getEventLoopOfCurrentThread(); 142 | 143 | private: 144 | void abortNotInLoopThread(); 145 | void handleRead(); // waked up 146 | void doPendingFunctors(); 147 | 148 | void printActiveChannels() const; // DEBUG 149 | 150 | typedef std::vector ChannelList; 151 | 152 | bool looping_; /* atomic */ 153 | bool quit_; /* atomic and shared between threads, okay on x86, I guess. */ 154 | bool eventHandling_; /* atomic */ 155 | bool callingPendingFunctors_; /* atomic */ 156 | int64_t iteration_; 157 | const pid_t threadId_; 158 | Timestamp pollReturnTime_; 159 | boost::scoped_ptr poller_; 160 | boost::scoped_ptr timerQueue_; 161 | int wakeupFd_; 162 | // unlike in TimerQueue, which is an internal class, 163 | // we don't expose Channel to client. 164 | boost::scoped_ptr wakeupChannel_; 165 | boost::any context_; 166 | 167 | // scratch variables 168 | ChannelList activeChannels_; 169 | Channel* currentActiveChannel_; 170 | 171 | mutable MutexLock mutex_; 172 | std::vector pendingFunctors_; // @GuardedBy mutex_ 173 | }; 174 | 175 | } 176 | } 177 | #endif // MUDUO_NET_EVENTLOOP_H 178 | -------------------------------------------------------------------------------- /mucgi/muduo_net/EventLoopThread.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | 9 | #include "muduo_net/EventLoopThread.h" 10 | 11 | #include "muduo_net/EventLoop.h" 12 | 13 | #include 14 | 15 | using namespace muduo; 16 | using namespace muduo::net; 17 | 18 | 19 | EventLoopThread::EventLoopThread(const ThreadInitCallback& cb, 20 | const string& name) 21 | : loop_(NULL), 22 | exiting_(false), 23 | thread_(boost::bind(&EventLoopThread::threadFunc, this), name), 24 | mutex_(), 25 | cond_(mutex_), 26 | callback_(cb) 27 | { 28 | } 29 | 30 | EventLoopThread::~EventLoopThread() 31 | { 32 | exiting_ = true; 33 | if (loop_ != NULL) // not 100% race-free, eg. threadFunc could be running callback_. 34 | { 35 | // still a tiny chance to call destructed object, if threadFunc exits just now. 36 | // but when EventLoopThread destructs, usually programming is exiting anyway. 37 | loop_->quit(); 38 | thread_.join(); 39 | } 40 | } 41 | 42 | EventLoop* EventLoopThread::startLoop() 43 | { 44 | assert(!thread_.started()); 45 | thread_.start(); 46 | 47 | { 48 | MutexLockGuard lock(mutex_); 49 | while (loop_ == NULL) 50 | { 51 | cond_.wait(); 52 | } 53 | } 54 | 55 | return loop_; 56 | } 57 | 58 | void EventLoopThread::threadFunc() 59 | { 60 | EventLoop loop; 61 | 62 | if (callback_) 63 | { 64 | callback_(&loop); 65 | } 66 | 67 | { 68 | MutexLockGuard lock(mutex_); 69 | loop_ = &loop; 70 | cond_.notify(); 71 | } 72 | 73 | loop.loop(); 74 | //assert(exiting_); 75 | loop_ = NULL; 76 | } 77 | 78 | -------------------------------------------------------------------------------- /mucgi/muduo_net/EventLoopThread.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is a public header file, it must only include public header files. 10 | 11 | #ifndef MUDUO_NET_EVENTLOOPTHREAD_H 12 | #define MUDUO_NET_EVENTLOOPTHREAD_H 13 | 14 | #include "muduo_base/Condition.h" 15 | #include "muduo_base/Mutex.h" 16 | #include "muduo_base/Thread.h" 17 | 18 | #include 19 | 20 | namespace muduo 21 | { 22 | namespace net 23 | { 24 | 25 | class EventLoop; 26 | 27 | class EventLoopThread : boost::noncopyable 28 | { 29 | public: 30 | typedef boost::function ThreadInitCallback; 31 | 32 | EventLoopThread(const ThreadInitCallback& cb = ThreadInitCallback(), 33 | const string& name = string()); 34 | ~EventLoopThread(); 35 | EventLoop* startLoop(); 36 | 37 | private: 38 | void threadFunc(); 39 | 40 | EventLoop* loop_; 41 | bool exiting_; 42 | Thread thread_; 43 | MutexLock mutex_; 44 | Condition cond_; 45 | ThreadInitCallback callback_; 46 | }; 47 | 48 | } 49 | } 50 | 51 | #endif // MUDUO_NET_EVENTLOOPTHREAD_H 52 | 53 | -------------------------------------------------------------------------------- /mucgi/muduo_net/EventLoopThreadPool.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | 9 | #include "muduo_net/EventLoopThreadPool.h" 10 | 11 | #include "muduo_net/EventLoop.h" 12 | #include "muduo_net/EventLoopThread.h" 13 | 14 | #include 15 | 16 | #include 17 | 18 | using namespace muduo; 19 | using namespace muduo::net; 20 | 21 | 22 | EventLoopThreadPool::EventLoopThreadPool(EventLoop* baseLoop, const string& nameArg) 23 | : baseLoop_(baseLoop), 24 | name_(nameArg), 25 | started_(false), 26 | numThreads_(0), 27 | next_(0) 28 | { 29 | } 30 | 31 | EventLoopThreadPool::~EventLoopThreadPool() 32 | { 33 | // Don't delete loop, it's stack variable 34 | } 35 | 36 | void EventLoopThreadPool::start(const ThreadInitCallback& cb) 37 | { 38 | assert(!started_); 39 | baseLoop_->assertInLoopThread(); 40 | 41 | started_ = true; 42 | 43 | for (int i = 0; i < numThreads_; ++i) 44 | { 45 | char buf[name_.size() + 32]; 46 | snprintf(buf, sizeof buf, "%s%d", name_.c_str(), i); 47 | EventLoopThread* t = new EventLoopThread(cb, buf); 48 | threads_.push_back(t); 49 | loops_.push_back(t->startLoop()); 50 | } 51 | if (numThreads_ == 0 && cb) 52 | { 53 | cb(baseLoop_); 54 | } 55 | } 56 | 57 | EventLoop* EventLoopThreadPool::getNextLoop() 58 | { 59 | baseLoop_->assertInLoopThread(); 60 | assert(started_); 61 | EventLoop* loop = baseLoop_; 62 | 63 | if (!loops_.empty()) 64 | { 65 | // round-robin 66 | loop = loops_[next_]; 67 | ++next_; 68 | if (implicit_cast(next_) >= loops_.size()) 69 | { 70 | next_ = 0; 71 | } 72 | } 73 | return loop; 74 | } 75 | 76 | EventLoop* EventLoopThreadPool::getLoopForHash(size_t hashCode) 77 | { 78 | baseLoop_->assertInLoopThread(); 79 | EventLoop* loop = baseLoop_; 80 | 81 | if (!loops_.empty()) 82 | { 83 | loop = loops_[hashCode % loops_.size()]; 84 | } 85 | return loop; 86 | } 87 | 88 | std::vector EventLoopThreadPool::getAllLoops() 89 | { 90 | baseLoop_->assertInLoopThread(); 91 | assert(started_); 92 | if (loops_.empty()) 93 | { 94 | return std::vector(1, baseLoop_); 95 | } 96 | else 97 | { 98 | return loops_; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /mucgi/muduo_net/EventLoopThreadPool.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is an internal header file, you should not include this. 10 | 11 | #ifndef MUDUO_NET_EVENTLOOPTHREADPOOL_H 12 | #define MUDUO_NET_EVENTLOOPTHREADPOOL_H 13 | 14 | #include "muduo_base/Types.h" 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | namespace muduo 22 | { 23 | 24 | namespace net 25 | { 26 | 27 | class EventLoop; 28 | class EventLoopThread; 29 | 30 | class EventLoopThreadPool : boost::noncopyable 31 | { 32 | public: 33 | typedef boost::function ThreadInitCallback; 34 | 35 | EventLoopThreadPool(EventLoop* baseLoop, const string& nameArg); 36 | ~EventLoopThreadPool(); 37 | void setThreadNum(int numThreads) { numThreads_ = numThreads; } 38 | void start(const ThreadInitCallback& cb = ThreadInitCallback()); 39 | 40 | // valid after calling start() 41 | /// round-robin 42 | EventLoop* getNextLoop(); 43 | 44 | /// with the same hash code, it will always return the same EventLoop 45 | EventLoop* getLoopForHash(size_t hashCode); 46 | 47 | std::vector getAllLoops(); 48 | 49 | bool started() const 50 | { return started_; } 51 | 52 | const string& name() const 53 | { return name_; } 54 | 55 | private: 56 | 57 | EventLoop* baseLoop_; 58 | string name_; 59 | bool started_; 60 | int numThreads_; 61 | int next_; 62 | boost::ptr_vector threads_; 63 | std::vector loops_; 64 | }; 65 | 66 | } 67 | } 68 | 69 | #endif // MUDUO_NET_EVENTLOOPTHREADPOOL_H 70 | -------------------------------------------------------------------------------- /mucgi/muduo_net/InetAddress.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | 9 | #include "muduo_net/InetAddress.h" 10 | 11 | #include "muduo_base/Logging.h" 12 | #include "muduo_net/Endian.h" 13 | #include "muduo_net/SocketsOps.h" 14 | 15 | #include 16 | #include // bzero 17 | #include 18 | 19 | #include 20 | 21 | // INADDR_ANY use (type)value casting. 22 | #pragma GCC diagnostic ignored "-Wold-style-cast" 23 | static const in_addr_t kInaddrAny = INADDR_ANY; 24 | static const in_addr_t kInaddrLoopback = INADDR_LOOPBACK; 25 | #pragma GCC diagnostic error "-Wold-style-cast" 26 | 27 | // /* Structure describing an Internet socket address. */ 28 | // struct sockaddr_in { 29 | // sa_family_t sin_family; /* address family: AF_INET */ 30 | // uint16_t sin_port; /* port in network byte order */ 31 | // struct in_addr sin_addr; /* internet address */ 32 | // }; 33 | 34 | // /* Internet address. */ 35 | // typedef uint32_t in_addr_t; 36 | // struct in_addr { 37 | // in_addr_t s_addr; /* address in network byte order */ 38 | // }; 39 | 40 | // struct sockaddr_in6 { 41 | // sa_family_t sin6_family; /* address family: AF_INET6 */ 42 | // uint16_t sin6_port; /* port in network byte order */ 43 | // uint32_t sin6_flowinfo; /* IPv6 flow information */ 44 | // struct in6_addr sin6_addr; /* IPv6 address */ 45 | // uint32_t sin6_scope_id; /* IPv6 scope-id */ 46 | // }; 47 | 48 | using namespace muduo; 49 | using namespace muduo::net; 50 | 51 | BOOST_STATIC_ASSERT(sizeof(InetAddress) == sizeof(struct sockaddr_in6)); 52 | BOOST_STATIC_ASSERT(offsetof(sockaddr_in, sin_family) == 0); 53 | BOOST_STATIC_ASSERT(offsetof(sockaddr_in6, sin6_family) == 0); 54 | BOOST_STATIC_ASSERT(offsetof(sockaddr_in, sin_port) == 2); 55 | BOOST_STATIC_ASSERT(offsetof(sockaddr_in6, sin6_port) == 2); 56 | 57 | #if !(__GNUC_PREREQ (4,6)) 58 | #pragma GCC diagnostic ignored "-Winvalid-offsetof" 59 | #endif 60 | InetAddress::InetAddress(uint16_t port, bool loopbackOnly, bool ipv6) 61 | { 62 | BOOST_STATIC_ASSERT(offsetof(InetAddress, addr6_) == 0); 63 | BOOST_STATIC_ASSERT(offsetof(InetAddress, addr_) == 0); 64 | if (ipv6) 65 | { 66 | bzero(&addr6_, sizeof addr6_); 67 | addr6_.sin6_family = AF_INET6; 68 | in6_addr ip = loopbackOnly ? in6addr_loopback : in6addr_any; 69 | addr6_.sin6_addr = ip; 70 | addr6_.sin6_port = sockets::hostToNetwork16(port); 71 | } 72 | else 73 | { 74 | bzero(&addr_, sizeof addr_); 75 | addr_.sin_family = AF_INET; 76 | in_addr_t ip = loopbackOnly ? kInaddrLoopback : kInaddrAny; 77 | addr_.sin_addr.s_addr = sockets::hostToNetwork32(ip); 78 | addr_.sin_port = sockets::hostToNetwork16(port); 79 | } 80 | } 81 | 82 | InetAddress::InetAddress(StringArg ip, uint16_t port, bool ipv6) 83 | { 84 | if (ipv6) 85 | { 86 | bzero(&addr6_, sizeof addr6_); 87 | sockets::fromIpPort(ip.c_str(), port, &addr6_); 88 | } 89 | else 90 | { 91 | bzero(&addr_, sizeof addr_); 92 | sockets::fromIpPort(ip.c_str(), port, &addr_); 93 | } 94 | } 95 | 96 | string InetAddress::toIpPort() const 97 | { 98 | char buf[64] = ""; 99 | sockets::toIpPort(buf, sizeof buf, getSockAddr()); 100 | return buf; 101 | } 102 | 103 | string InetAddress::toIp() const 104 | { 105 | char buf[64] = ""; 106 | sockets::toIp(buf, sizeof buf, getSockAddr()); 107 | return buf; 108 | } 109 | 110 | uint32_t InetAddress::ipNetEndian() const 111 | { 112 | assert(family() == AF_INET); 113 | return addr_.sin_addr.s_addr; 114 | } 115 | 116 | uint16_t InetAddress::toPort() const 117 | { 118 | return sockets::networkToHost16(portNetEndian()); 119 | } 120 | 121 | static __thread char t_resolveBuffer[64 * 1024]; 122 | 123 | bool InetAddress::resolve(StringArg hostname, InetAddress* out) 124 | { 125 | assert(out != NULL); 126 | struct hostent hent; 127 | struct hostent* he = NULL; 128 | int herrno = 0; 129 | bzero(&hent, sizeof(hent)); 130 | 131 | int ret = gethostbyname_r(hostname.c_str(), &hent, t_resolveBuffer, sizeof t_resolveBuffer, &he, &herrno); 132 | if (ret == 0 && he != NULL) 133 | { 134 | assert(he->h_addrtype == AF_INET && he->h_length == sizeof(uint32_t)); 135 | out->addr_.sin_addr = *reinterpret_cast(he->h_addr); 136 | return true; 137 | } 138 | else 139 | { 140 | if (ret) 141 | { 142 | LOG_SYSERR << "InetAddress::resolve"; 143 | } 144 | return false; 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /mucgi/muduo_net/InetAddress.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is a public header file, it must only include public header files. 10 | 11 | #ifndef MUDUO_NET_INETADDRESS_H 12 | #define MUDUO_NET_INETADDRESS_H 13 | 14 | #include "muduo_base/copyable.h" 15 | #include "muduo_base/StringPiece.h" 16 | 17 | #include 18 | 19 | namespace muduo 20 | { 21 | namespace net 22 | { 23 | namespace sockets 24 | { 25 | const struct sockaddr* sockaddr_cast(const struct sockaddr_in6* addr); 26 | } 27 | 28 | /// 29 | /// Wrapper of sockaddr_in. 30 | /// 31 | /// This is an POD interface class. 32 | class InetAddress : public muduo::copyable 33 | { 34 | public: 35 | /// Constructs an endpoint with given port number. 36 | /// Mostly used in TcpServer listening. 37 | explicit InetAddress(uint16_t port = 0, bool loopbackOnly = false, bool ipv6 = false); 38 | 39 | /// Constructs an endpoint with given ip and port. 40 | /// @c ip should be "1.2.3.4" 41 | InetAddress(StringArg ip, uint16_t port, bool ipv6 = false); 42 | 43 | /// Constructs an endpoint with given struct @c sockaddr_in 44 | /// Mostly used when accepting new connections 45 | explicit InetAddress(const struct sockaddr_in& addr) 46 | : addr_(addr) 47 | { } 48 | 49 | explicit InetAddress(const struct sockaddr_in6& addr) 50 | : addr6_(addr) 51 | { } 52 | 53 | sa_family_t family() const { return addr_.sin_family; } 54 | string toIp() const; 55 | string toIpPort() const; 56 | uint16_t toPort() const; 57 | 58 | // default copy/assignment are Okay 59 | 60 | const struct sockaddr* getSockAddr() const { return sockets::sockaddr_cast(&addr6_); } 61 | void setSockAddrInet6(const struct sockaddr_in6& addr6) { addr6_ = addr6; } 62 | 63 | uint32_t ipNetEndian() const; 64 | uint16_t portNetEndian() const { return addr_.sin_port; } 65 | 66 | // resolve hostname to IP address, not changing port or sin_family 67 | // return true on success. 68 | // thread safe 69 | static bool resolve(StringArg hostname, InetAddress* result); 70 | // static std::vector resolveAll(const char* hostname, uint16_t port = 0); 71 | 72 | private: 73 | union 74 | { 75 | struct sockaddr_in addr_; 76 | struct sockaddr_in6 addr6_; 77 | }; 78 | }; 79 | 80 | } 81 | } 82 | 83 | #endif // MUDUO_NET_INETADDRESS_H 84 | -------------------------------------------------------------------------------- /mucgi/muduo_net/PollPoller.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | 9 | #include "muduo_net/PollPoller.h" 10 | 11 | #include "muduo_base/Logging.h" 12 | #include "muduo_base/Types.h" 13 | #include "muduo_net/Channel.h" 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | using namespace muduo; 20 | using namespace muduo::net; 21 | 22 | PollPoller::PollPoller(EventLoop* loop) 23 | : Poller(loop) 24 | { 25 | } 26 | 27 | PollPoller::~PollPoller() 28 | { 29 | } 30 | 31 | Timestamp PollPoller::poll(int timeoutMs, ChannelList* activeChannels) 32 | { 33 | // XXX pollfds_ shouldn't change 34 | int numEvents = ::poll(&*pollfds_.begin(), pollfds_.size(), timeoutMs); 35 | int savedErrno = errno; 36 | Timestamp now(Timestamp::now()); 37 | if (numEvents > 0) 38 | { 39 | LOG_TRACE << numEvents << " events happended"; 40 | fillActiveChannels(numEvents, activeChannels); 41 | } 42 | else if (numEvents == 0) 43 | { 44 | LOG_TRACE << " nothing happended"; 45 | } 46 | else 47 | { 48 | if (savedErrno != EINTR) 49 | { 50 | errno = savedErrno; 51 | LOG_SYSERR << "PollPoller::poll()"; 52 | } 53 | } 54 | return now; 55 | } 56 | 57 | void PollPoller::fillActiveChannels(int numEvents, 58 | ChannelList* activeChannels) const 59 | { 60 | for (PollFdList::const_iterator pfd = pollfds_.begin(); 61 | pfd != pollfds_.end() && numEvents > 0; ++pfd) 62 | { 63 | if (pfd->revents > 0) 64 | { 65 | --numEvents; 66 | ChannelMap::const_iterator ch = channels_.find(pfd->fd); 67 | assert(ch != channels_.end()); 68 | Channel* channel = ch->second; 69 | assert(channel->fd() == pfd->fd); 70 | channel->set_revents(pfd->revents); 71 | // pfd->revents = 0; 72 | activeChannels->push_back(channel); 73 | } 74 | } 75 | } 76 | 77 | void PollPoller::updateChannel(Channel* channel) 78 | { 79 | Poller::assertInLoopThread(); 80 | LOG_TRACE << "fd = " << channel->fd() << " events = " << channel->events(); 81 | if (channel->index() < 0) 82 | { 83 | // a new one, add to pollfds_ 84 | assert(channels_.find(channel->fd()) == channels_.end()); 85 | struct pollfd pfd; 86 | pfd.fd = channel->fd(); 87 | pfd.events = static_cast(channel->events()); 88 | pfd.revents = 0; 89 | pollfds_.push_back(pfd); 90 | int idx = static_cast(pollfds_.size())-1; 91 | channel->set_index(idx); 92 | channels_[pfd.fd] = channel; 93 | } 94 | else 95 | { 96 | // update existing one 97 | assert(channels_.find(channel->fd()) != channels_.end()); 98 | assert(channels_[channel->fd()] == channel); 99 | int idx = channel->index(); 100 | assert(0 <= idx && idx < static_cast(pollfds_.size())); 101 | struct pollfd& pfd = pollfds_[idx]; 102 | assert(pfd.fd == channel->fd() || pfd.fd == -channel->fd()-1); 103 | pfd.events = static_cast(channel->events()); 104 | pfd.revents = 0; 105 | if (channel->isNoneEvent()) 106 | { 107 | // ignore this pollfd 108 | pfd.fd = -channel->fd()-1; 109 | } 110 | } 111 | } 112 | 113 | void PollPoller::removeChannel(Channel* channel) 114 | { 115 | Poller::assertInLoopThread(); 116 | LOG_TRACE << "fd = " << channel->fd(); 117 | assert(channels_.find(channel->fd()) != channels_.end()); 118 | assert(channels_[channel->fd()] == channel); 119 | assert(channel->isNoneEvent()); 120 | int idx = channel->index(); 121 | assert(0 <= idx && idx < static_cast(pollfds_.size())); 122 | const struct pollfd& pfd = pollfds_[idx]; (void)pfd; 123 | assert(pfd.fd == -channel->fd()-1 && pfd.events == channel->events()); 124 | size_t n = channels_.erase(channel->fd()); 125 | assert(n == 1); (void)n; 126 | if (implicit_cast(idx) == pollfds_.size()-1) 127 | { 128 | pollfds_.pop_back(); 129 | } 130 | else 131 | { 132 | int channelAtEnd = pollfds_.back().fd; 133 | iter_swap(pollfds_.begin()+idx, pollfds_.end()-1); 134 | if (channelAtEnd < 0) 135 | { 136 | channelAtEnd = -channelAtEnd-1; 137 | } 138 | channels_[channelAtEnd]->set_index(idx); 139 | pollfds_.pop_back(); 140 | } 141 | } 142 | 143 | -------------------------------------------------------------------------------- /mucgi/muduo_net/PollPoller.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is an internal header file, you should not include this. 10 | 11 | #ifndef MUDUO_NET_POLLER_POLLPOLLER_H 12 | #define MUDUO_NET_POLLER_POLLPOLLER_H 13 | 14 | #include "muduo_net/Poller.h" 15 | 16 | #include 17 | 18 | struct pollfd; 19 | 20 | namespace muduo 21 | { 22 | namespace net 23 | { 24 | 25 | /// 26 | /// IO Multiplexing with poll(2). 27 | /// 28 | class PollPoller : public Poller 29 | { 30 | public: 31 | 32 | PollPoller(EventLoop* loop); 33 | virtual ~PollPoller(); 34 | 35 | virtual Timestamp poll(int timeoutMs, ChannelList* activeChannels); 36 | virtual void updateChannel(Channel* channel); 37 | virtual void removeChannel(Channel* channel); 38 | 39 | private: 40 | void fillActiveChannels(int numEvents, 41 | ChannelList* activeChannels) const; 42 | 43 | typedef std::vector PollFdList; 44 | PollFdList pollfds_; 45 | }; 46 | 47 | } 48 | } 49 | #endif // MUDUO_NET_POLLER_POLLPOLLER_H 50 | -------------------------------------------------------------------------------- /mucgi/muduo_net/Poller.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | 9 | #include "muduo_net/Poller.h" 10 | 11 | #include "muduo_net/Channel.h" 12 | 13 | using namespace muduo; 14 | using namespace muduo::net; 15 | 16 | Poller::Poller(EventLoop* loop) 17 | : ownerLoop_(loop) 18 | { 19 | } 20 | 21 | Poller::~Poller() 22 | { 23 | } 24 | 25 | bool Poller::hasChannel(Channel* channel) const 26 | { 27 | assertInLoopThread(); 28 | ChannelMap::const_iterator it = channels_.find(channel->fd()); 29 | return it != channels_.end() && it->second == channel; 30 | } 31 | 32 | -------------------------------------------------------------------------------- /mucgi/muduo_net/Poller.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is an internal header file, you should not include this. 10 | 11 | #ifndef MUDUO_NET_POLLER_H 12 | #define MUDUO_NET_POLLER_H 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #include "muduo_base/Timestamp.h" 19 | #include "muduo_net/EventLoop.h" 20 | 21 | namespace muduo 22 | { 23 | namespace net 24 | { 25 | 26 | class Channel; 27 | 28 | /// 29 | /// Base class for IO Multiplexing 30 | /// 31 | /// This class doesn't own the Channel objects. 32 | class Poller : boost::noncopyable 33 | { 34 | public: 35 | typedef std::vector ChannelList; 36 | 37 | Poller(EventLoop* loop); 38 | virtual ~Poller(); 39 | 40 | /// Polls the I/O events. 41 | /// Must be called in the loop thread. 42 | virtual Timestamp poll(int timeoutMs, ChannelList* activeChannels) = 0; 43 | 44 | /// Changes the interested I/O events. 45 | /// Must be called in the loop thread. 46 | virtual void updateChannel(Channel* channel) = 0; 47 | 48 | /// Remove the channel, when it destructs. 49 | /// Must be called in the loop thread. 50 | virtual void removeChannel(Channel* channel) = 0; 51 | 52 | virtual bool hasChannel(Channel* channel) const; 53 | 54 | static Poller* newDefaultPoller(EventLoop* loop); 55 | 56 | void assertInLoopThread() const 57 | { 58 | ownerLoop_->assertInLoopThread(); 59 | } 60 | 61 | protected: 62 | typedef std::map ChannelMap; 63 | ChannelMap channels_; 64 | 65 | private: 66 | EventLoop* ownerLoop_; 67 | }; 68 | 69 | } 70 | } 71 | #endif // MUDUO_NET_POLLER_H 72 | -------------------------------------------------------------------------------- /mucgi/muduo_net/Socket.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | 9 | #include "muduo_net/Socket.h" 10 | 11 | #include "muduo_base/Logging.h" 12 | #include "muduo_net/InetAddress.h" 13 | #include "muduo_net/SocketsOps.h" 14 | 15 | #include 16 | #include 17 | #include // bzero 18 | #include // snprintf 19 | 20 | using namespace muduo; 21 | using namespace muduo::net; 22 | 23 | Socket::~Socket() 24 | { 25 | sockets::close(sockfd_); 26 | } 27 | 28 | bool Socket::getTcpInfo(struct tcp_info* tcpi) const 29 | { 30 | socklen_t len = sizeof(*tcpi); 31 | bzero(tcpi, len); 32 | return ::getsockopt(sockfd_, SOL_TCP, TCP_INFO, tcpi, &len) == 0; 33 | } 34 | 35 | bool Socket::getTcpInfoString(char* buf, int len) const 36 | { 37 | struct tcp_info tcpi; 38 | bool ok = getTcpInfo(&tcpi); 39 | if (ok) 40 | { 41 | snprintf(buf, len, "unrecovered=%u " 42 | "rto=%u ato=%u snd_mss=%u rcv_mss=%u " 43 | "lost=%u retrans=%u rtt=%u rttvar=%u " 44 | "sshthresh=%u cwnd=%u total_retrans=%u", 45 | tcpi.tcpi_retransmits, // Number of unrecovered [RTO] timeouts 46 | tcpi.tcpi_rto, // Retransmit timeout in usec 47 | tcpi.tcpi_ato, // Predicted tick of soft clock in usec 48 | tcpi.tcpi_snd_mss, 49 | tcpi.tcpi_rcv_mss, 50 | tcpi.tcpi_lost, // Lost packets 51 | tcpi.tcpi_retrans, // Retransmitted packets out 52 | tcpi.tcpi_rtt, // Smoothed round trip time in usec 53 | tcpi.tcpi_rttvar, // Medium deviation 54 | tcpi.tcpi_snd_ssthresh, 55 | tcpi.tcpi_snd_cwnd, 56 | tcpi.tcpi_total_retrans); // Total retransmits for entire connection 57 | } 58 | return ok; 59 | } 60 | 61 | void Socket::bindAddress(const InetAddress& addr) 62 | { 63 | sockets::bindOrDie(sockfd_, addr.getSockAddr()); 64 | } 65 | 66 | void Socket::listen() 67 | { 68 | sockets::listenOrDie(sockfd_); 69 | } 70 | 71 | int Socket::accept(InetAddress* peeraddr) 72 | { 73 | struct sockaddr_in6 addr; 74 | bzero(&addr, sizeof addr); 75 | int connfd = sockets::accept(sockfd_, &addr); 76 | if (connfd >= 0) 77 | { 78 | peeraddr->setSockAddrInet6(addr); 79 | } 80 | return connfd; 81 | } 82 | 83 | void Socket::shutdownWrite() 84 | { 85 | sockets::shutdownWrite(sockfd_); 86 | } 87 | 88 | void Socket::setTcpNoDelay(bool on) 89 | { 90 | int optval = on ? 1 : 0; 91 | ::setsockopt(sockfd_, IPPROTO_TCP, TCP_NODELAY, 92 | &optval, static_cast(sizeof optval)); 93 | // FIXME CHECK 94 | } 95 | 96 | void Socket::setReuseAddr(bool on) 97 | { 98 | int optval = on ? 1 : 0; 99 | ::setsockopt(sockfd_, SOL_SOCKET, SO_REUSEADDR, 100 | &optval, static_cast(sizeof optval)); 101 | // FIXME CHECK 102 | } 103 | 104 | void Socket::setReusePort(bool on) 105 | { 106 | #ifdef SO_REUSEPORT 107 | int optval = on ? 1 : 0; 108 | int ret = ::setsockopt(sockfd_, SOL_SOCKET, SO_REUSEPORT, 109 | &optval, static_cast(sizeof optval)); 110 | if (ret < 0 && on) 111 | { 112 | LOG_SYSERR << "SO_REUSEPORT failed."; 113 | } 114 | #else 115 | if (on) 116 | { 117 | LOG_ERROR << "SO_REUSEPORT is not supported."; 118 | } 119 | #endif 120 | } 121 | 122 | void Socket::setKeepAlive(bool on) 123 | { 124 | int optval = on ? 1 : 0; 125 | ::setsockopt(sockfd_, SOL_SOCKET, SO_KEEPALIVE, 126 | &optval, static_cast(sizeof optval)); 127 | // FIXME CHECK 128 | } 129 | 130 | -------------------------------------------------------------------------------- /mucgi/muduo_net/Socket.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is an internal header file, you should not include this. 10 | 11 | #ifndef MUDUO_NET_SOCKET_H 12 | #define MUDUO_NET_SOCKET_H 13 | 14 | #include 15 | 16 | // struct tcp_info is in 17 | struct tcp_info; 18 | 19 | namespace muduo 20 | { 21 | /// 22 | /// TCP networking. 23 | /// 24 | namespace net 25 | { 26 | 27 | class InetAddress; 28 | 29 | /// 30 | /// Wrapper of socket file descriptor. 31 | /// 32 | /// It closes the sockfd when desctructs. 33 | /// It's thread safe, all operations are delegated to OS. 34 | class Socket : boost::noncopyable 35 | { 36 | public: 37 | explicit Socket(int sockfd) 38 | : sockfd_(sockfd) 39 | { } 40 | 41 | // Socket(Socket&&) // move constructor in C++11 42 | ~Socket(); 43 | 44 | int fd() const { return sockfd_; } 45 | // return true if success. 46 | bool getTcpInfo(struct tcp_info*) const; 47 | bool getTcpInfoString(char* buf, int len) const; 48 | 49 | /// abort if address in use 50 | void bindAddress(const InetAddress& localaddr); 51 | /// abort if address in use 52 | void listen(); 53 | 54 | /// On success, returns a non-negative integer that is 55 | /// a descriptor for the accepted socket, which has been 56 | /// set to non-blocking and close-on-exec. *peeraddr is assigned. 57 | /// On error, -1 is returned, and *peeraddr is untouched. 58 | int accept(InetAddress* peeraddr); 59 | 60 | void shutdownWrite(); 61 | 62 | /// 63 | /// Enable/disable TCP_NODELAY (disable/enable Nagle's algorithm). 64 | /// 65 | void setTcpNoDelay(bool on); 66 | 67 | /// 68 | /// Enable/disable SO_REUSEADDR 69 | /// 70 | void setReuseAddr(bool on); 71 | 72 | /// 73 | /// Enable/disable SO_REUSEPORT 74 | /// 75 | void setReusePort(bool on); 76 | 77 | /// 78 | /// Enable/disable SO_KEEPALIVE 79 | /// 80 | void setKeepAlive(bool on); 81 | 82 | private: 83 | const int sockfd_; 84 | }; 85 | 86 | } 87 | } 88 | #endif // MUDUO_NET_SOCKET_H 89 | -------------------------------------------------------------------------------- /mucgi/muduo_net/SocketsOps.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is an internal header file, you should not include this. 10 | 11 | #ifndef MUDUO_NET_SOCKETSOPS_H 12 | #define MUDUO_NET_SOCKETSOPS_H 13 | 14 | #include 15 | 16 | namespace muduo 17 | { 18 | namespace net 19 | { 20 | namespace sockets 21 | { 22 | 23 | /// 24 | /// Creates a non-blocking socket file descriptor, 25 | /// abort if any error. 26 | int createNonblockingOrDie(sa_family_t family); 27 | 28 | int connect(int sockfd, const struct sockaddr* addr); 29 | void bindOrDie(int sockfd, const struct sockaddr* addr); 30 | void listenOrDie(int sockfd); 31 | int accept(int sockfd, struct sockaddr_in6* addr); 32 | ssize_t read(int sockfd, void *buf, size_t count); 33 | ssize_t readv(int sockfd, const struct iovec *iov, int iovcnt); 34 | ssize_t write(int sockfd, const void *buf, size_t count); 35 | void close(int sockfd); 36 | void shutdownWrite(int sockfd); 37 | 38 | void toIpPort(char* buf, size_t size, 39 | const struct sockaddr* addr); 40 | void toIp(char* buf, size_t size, 41 | const struct sockaddr* addr); 42 | 43 | void fromIpPort(const char* ip, uint16_t port, 44 | struct sockaddr_in* addr); 45 | void fromIpPort(const char* ip, uint16_t port, 46 | struct sockaddr_in6* addr); 47 | 48 | int getSocketError(int sockfd); 49 | 50 | const struct sockaddr* sockaddr_cast(const struct sockaddr_in* addr); 51 | const struct sockaddr* sockaddr_cast(const struct sockaddr_in6* addr); 52 | struct sockaddr* sockaddr_cast(struct sockaddr_in6* addr); 53 | const struct sockaddr_in* sockaddr_in_cast(const struct sockaddr* addr); 54 | const struct sockaddr_in6* sockaddr_in6_cast(const struct sockaddr* addr); 55 | 56 | struct sockaddr_in6 getLocalAddr(int sockfd); 57 | struct sockaddr_in6 getPeerAddr(int sockfd); 58 | bool isSelfConnect(int sockfd); 59 | 60 | } 61 | } 62 | } 63 | 64 | #endif // MUDUO_NET_SOCKETSOPS_H 65 | -------------------------------------------------------------------------------- /mucgi/muduo_net/TcpServer.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | 9 | #include "muduo_net/TcpServer.h" 10 | 11 | #include "muduo_base/Logging.h" 12 | #include "muduo_net/Acceptor.h" 13 | #include "muduo_net/EventLoop.h" 14 | #include "muduo_net/EventLoopThreadPool.h" 15 | #include "muduo_net/SocketsOps.h" 16 | 17 | #include 18 | 19 | #include // snprintf 20 | 21 | using namespace muduo; 22 | using namespace muduo::net; 23 | 24 | TcpServer::TcpServer(EventLoop* loop, 25 | const InetAddress& listenAddr, 26 | const string& nameArg, 27 | Option option) 28 | : loop_(CHECK_NOTNULL(loop)), 29 | ipPort_(listenAddr.toIpPort()), 30 | name_(nameArg), 31 | acceptor_(new Acceptor(loop, listenAddr, option == kReusePort)), 32 | threadPool_(new EventLoopThreadPool(loop, name_)), 33 | connectionCallback_(defaultConnectionCallback), 34 | messageCallback_(defaultMessageCallback), 35 | nextConnId_(1) 36 | { 37 | acceptor_->setNewConnectionCallback( 38 | boost::bind(&TcpServer::newConnection, this, _1, _2)); 39 | } 40 | 41 | TcpServer::~TcpServer() 42 | { 43 | loop_->assertInLoopThread(); 44 | LOG_TRACE << "TcpServer::~TcpServer [" << name_ << "] destructing"; 45 | 46 | for (ConnectionMap::iterator it(connections_.begin()); 47 | it != connections_.end(); ++it) 48 | { 49 | TcpConnectionPtr conn = it->second; 50 | it->second.reset(); 51 | conn->getLoop()->runInLoop( 52 | boost::bind(&TcpConnection::connectDestroyed, conn)); 53 | conn.reset(); 54 | } 55 | } 56 | 57 | void TcpServer::setThreadNum(int numThreads) 58 | { 59 | assert(0 <= numThreads); 60 | threadPool_->setThreadNum(numThreads); 61 | } 62 | 63 | void TcpServer::start() 64 | { 65 | if (started_.getAndSet(1) == 0) 66 | { 67 | threadPool_->start(threadInitCallback_); 68 | 69 | assert(!acceptor_->listenning()); 70 | loop_->runInLoop( 71 | boost::bind(&Acceptor::listen, get_pointer(acceptor_))); 72 | } 73 | } 74 | 75 | void TcpServer::newConnection(int sockfd, const InetAddress& peerAddr) 76 | { 77 | loop_->assertInLoopThread(); 78 | EventLoop* ioLoop = threadPool_->getNextLoop(); 79 | char buf[64]; 80 | memset( buf, 0, sizeof buf); 81 | snprintf(buf, sizeof buf, "-%s#%d", ipPort_.c_str(), nextConnId_); 82 | ++nextConnId_; 83 | string connName = name_ + buf; 84 | 85 | LOG_DEBUG << "TcpServer::newConnection [" << name_ 86 | << "] - new connection [" << connName 87 | << "] from " << peerAddr.toIpPort(); 88 | InetAddress localAddr(sockets::getLocalAddr(sockfd)); 89 | // FIXME poll with zero timeout to double confirm the new connection 90 | // FIXME use make_shared if necessary 91 | TcpConnectionPtr conn(new TcpConnection(ioLoop, 92 | connName, 93 | sockfd, 94 | localAddr, 95 | peerAddr)); 96 | connections_[connName] = conn; 97 | conn->setConnectionCallback(connectionCallback_); 98 | conn->setMessageCallback(messageCallback_); 99 | conn->setWriteCompleteCallback(writeCompleteCallback_); 100 | conn->setCloseCallback( 101 | boost::bind(&TcpServer::removeConnection, this, _1)); // FIXME: unsafe 102 | ioLoop->runInLoop(boost::bind(&TcpConnection::connectEstablished, conn)); 103 | } 104 | 105 | void TcpServer::removeConnection(const TcpConnectionPtr& conn) 106 | { 107 | // FIXME: unsafe 108 | loop_->runInLoop(boost::bind(&TcpServer::removeConnectionInLoop, this, conn)); 109 | } 110 | 111 | void TcpServer::removeConnectionInLoop(const TcpConnectionPtr& conn) 112 | { 113 | loop_->assertInLoopThread(); 114 | LOG_DEBUG << "TcpServer::removeConnectionInLoop [" << name_ 115 | << "] - connection " << conn->name(); 116 | size_t n = connections_.erase(conn->name()); 117 | (void)n; 118 | assert(n == 1); 119 | EventLoop* ioLoop = conn->getLoop(); 120 | ioLoop->queueInLoop( 121 | boost::bind(&TcpConnection::connectDestroyed, conn)); 122 | } 123 | 124 | -------------------------------------------------------------------------------- /mucgi/muduo_net/TcpServer.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is a public header file, it must only include public header files. 10 | 11 | #ifndef MUDUO_NET_TCPSERVER_H 12 | #define MUDUO_NET_TCPSERVER_H 13 | 14 | #include "muduo_base/Atomic.h" 15 | #include "muduo_base/Types.h" 16 | #include "muduo_net/TcpConnection.h" 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | namespace muduo 24 | { 25 | namespace net 26 | { 27 | 28 | class Acceptor; 29 | class EventLoop; 30 | class EventLoopThreadPool; 31 | 32 | /// 33 | /// TCP server, supports single-threaded and thread-pool models. 34 | /// 35 | /// This is an interface class, so don't expose too much details. 36 | class TcpServer : boost::noncopyable 37 | { 38 | public: 39 | typedef boost::function ThreadInitCallback; 40 | enum Option 41 | { 42 | kNoReusePort, 43 | kReusePort, 44 | }; 45 | 46 | //TcpServer(EventLoop* loop, const InetAddress& listenAddr); 47 | TcpServer(EventLoop* loop, 48 | const InetAddress& listenAddr, 49 | const string& nameArg, 50 | Option option = kNoReusePort); 51 | ~TcpServer(); // force out-line dtor, for scoped_ptr members. 52 | 53 | const string& ipPort() const { return ipPort_; } 54 | const string& name() const { return name_; } 55 | EventLoop* getLoop() const { return loop_; } 56 | 57 | /// Set the number of threads for handling input. 58 | /// 59 | /// Always accepts new connection in loop's thread. 60 | /// Must be called before @c start 61 | /// @param numThreads 62 | /// - 0 means all I/O in loop's thread, no thread will created. 63 | /// this is the default value. 64 | /// - 1 means all I/O in another thread. 65 | /// - N means a thread pool with N threads, new connections 66 | /// are assigned on a round-robin basis. 67 | void setThreadNum(int numThreads); 68 | void setThreadInitCallback(const ThreadInitCallback& cb) 69 | { threadInitCallback_ = cb; } 70 | /// valid after calling start() 71 | boost::shared_ptr threadPool() 72 | { return threadPool_; } 73 | 74 | /// Starts the server if it's not listenning. 75 | /// 76 | /// It's harmless to call it multiple times. 77 | /// Thread safe. 78 | void start(); 79 | 80 | /// Set connection callback. 81 | /// Not thread safe. 82 | void setConnectionCallback(const ConnectionCallback& cb) 83 | { connectionCallback_ = cb; } 84 | 85 | /// Set message callback. 86 | /// Not thread safe. 87 | void setMessageCallback(const MessageCallback& cb) 88 | { messageCallback_ = cb; } 89 | 90 | /// Set write complete callback. 91 | /// Not thread safe. 92 | void setWriteCompleteCallback(const WriteCompleteCallback& cb) 93 | { writeCompleteCallback_ = cb; } 94 | 95 | private: 96 | /// Not thread safe, but in loop 97 | void newConnection(int sockfd, const InetAddress& peerAddr); 98 | /// Thread safe. 99 | void removeConnection(const TcpConnectionPtr& conn); 100 | /// Not thread safe, but in loop 101 | void removeConnectionInLoop(const TcpConnectionPtr& conn); 102 | 103 | typedef std::map ConnectionMap; 104 | 105 | EventLoop* loop_; // the acceptor loop 106 | const string ipPort_; 107 | const string name_; 108 | boost::scoped_ptr acceptor_; // avoid revealing Acceptor 109 | boost::shared_ptr threadPool_; 110 | ConnectionCallback connectionCallback_; 111 | MessageCallback messageCallback_; 112 | WriteCompleteCallback writeCompleteCallback_; 113 | ThreadInitCallback threadInitCallback_; 114 | AtomicInt32 started_; 115 | // always in loop thread 116 | int nextConnId_; 117 | ConnectionMap connections_; 118 | }; 119 | 120 | } 121 | } 122 | 123 | #endif // MUDUO_NET_TCPSERVER_H 124 | -------------------------------------------------------------------------------- /mucgi/muduo_net/Timer.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | 9 | #include "muduo_net/Timer.h" 10 | 11 | using namespace muduo; 12 | using namespace muduo::net; 13 | 14 | AtomicInt64 Timer::s_numCreated_; 15 | 16 | void Timer::restart(Timestamp now) 17 | { 18 | if (repeat_) 19 | { 20 | expiration_ = addTime(now, interval_); 21 | } 22 | else 23 | { 24 | expiration_ = Timestamp::invalid(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /mucgi/muduo_net/Timer.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is an internal header file, you should not include this. 10 | 11 | #ifndef MUDUO_NET_TIMER_H 12 | #define MUDUO_NET_TIMER_H 13 | 14 | #include 15 | 16 | #include "muduo_base/Atomic.h" 17 | #include "muduo_base/Timestamp.h" 18 | #include "muduo_net/Callbacks.h" 19 | 20 | namespace muduo 21 | { 22 | namespace net 23 | { 24 | /// 25 | /// Internal class for timer event. 26 | /// 27 | class Timer : boost::noncopyable 28 | { 29 | public: 30 | Timer(const TimerCallback& cb, Timestamp when, double interval) 31 | : callback_(cb), 32 | expiration_(when), 33 | interval_(interval), 34 | repeat_(interval > 0.0), 35 | sequence_(s_numCreated_.incrementAndGet()) 36 | { } 37 | 38 | #ifdef __GXX_EXPERIMENTAL_CXX0X__ 39 | Timer(TimerCallback&& cb, Timestamp when, double interval) 40 | : callback_(std::move(cb)), 41 | expiration_(when), 42 | interval_(interval), 43 | repeat_(interval > 0.0), 44 | sequence_(s_numCreated_.incrementAndGet()) 45 | { } 46 | #endif 47 | 48 | void run() const 49 | { 50 | callback_(); 51 | } 52 | 53 | Timestamp expiration() const { return expiration_; } 54 | bool repeat() const { return repeat_; } 55 | int64_t sequence() const { return sequence_; } 56 | 57 | void restart(Timestamp now); 58 | 59 | static int64_t numCreated() { return s_numCreated_.get(); } 60 | 61 | private: 62 | const TimerCallback callback_; 63 | Timestamp expiration_; 64 | const double interval_; 65 | const bool repeat_; 66 | const int64_t sequence_; 67 | 68 | static AtomicInt64 s_numCreated_; 69 | }; 70 | } 71 | } 72 | #endif // MUDUO_NET_TIMER_H 73 | -------------------------------------------------------------------------------- /mucgi/muduo_net/TimerId.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is a public header file, it must only include public header files. 10 | 11 | #ifndef MUDUO_NET_TIMERID_H 12 | #define MUDUO_NET_TIMERID_H 13 | 14 | #include "muduo_base/copyable.h" 15 | 16 | namespace muduo 17 | { 18 | namespace net 19 | { 20 | 21 | class Timer; 22 | 23 | /// 24 | /// An opaque identifier, for canceling Timer. 25 | /// 26 | class TimerId : public muduo::copyable 27 | { 28 | public: 29 | TimerId() 30 | : timer_(NULL), 31 | sequence_(0) 32 | { 33 | } 34 | 35 | TimerId(Timer* timer, int64_t seq) 36 | : timer_(timer), 37 | sequence_(seq) 38 | { 39 | } 40 | 41 | // default copy-ctor, dtor and assignment are okay 42 | 43 | friend class TimerQueue; 44 | 45 | private: 46 | Timer* timer_; 47 | int64_t sequence_; 48 | }; 49 | 50 | } 51 | } 52 | 53 | #endif // MUDUO_NET_TIMERID_H 54 | -------------------------------------------------------------------------------- /mucgi/muduo_net/TimerQueue.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | // This is an internal header file, you should not include this. 10 | 11 | #ifndef MUDUO_NET_TIMERQUEUE_H 12 | #define MUDUO_NET_TIMERQUEUE_H 13 | 14 | #include 15 | #include 16 | 17 | #include 18 | 19 | #include "muduo_base/Mutex.h" 20 | #include "muduo_base/Timestamp.h" 21 | #include "muduo_net/Callbacks.h" 22 | #include "muduo_net/Channel.h" 23 | 24 | namespace muduo 25 | { 26 | namespace net 27 | { 28 | 29 | class EventLoop; 30 | class Timer; 31 | class TimerId; 32 | 33 | /// 34 | /// A best efforts timer queue. 35 | /// No guarantee that the callback will be on time. 36 | /// 37 | class TimerQueue : boost::noncopyable 38 | { 39 | public: 40 | TimerQueue(EventLoop* loop); 41 | ~TimerQueue(); 42 | 43 | /// 44 | /// Schedules the callback to be run at given time, 45 | /// repeats if @c interval > 0.0. 46 | /// 47 | /// Must be thread safe. Usually be called from other threads. 48 | TimerId addTimer(const TimerCallback& cb, 49 | Timestamp when, 50 | double interval); 51 | #ifdef __GXX_EXPERIMENTAL_CXX0X__ 52 | TimerId addTimer(TimerCallback&& cb, 53 | Timestamp when, 54 | double interval); 55 | #endif 56 | 57 | void cancel(TimerId timerId); 58 | 59 | private: 60 | 61 | // FIXME: use unique_ptr instead of raw pointers. 62 | typedef std::pair Entry; 63 | typedef std::set TimerList; 64 | typedef std::pair ActiveTimer; 65 | typedef std::set ActiveTimerSet; 66 | 67 | void addTimerInLoop(Timer* timer); 68 | void cancelInLoop(TimerId timerId); 69 | // called when timerfd alarms 70 | void handleRead(); 71 | // move out all expired timers 72 | std::vector getExpired(Timestamp now); 73 | void reset(const std::vector& expired, Timestamp now); 74 | 75 | bool insert(Timer* timer); 76 | 77 | EventLoop* loop_; 78 | const int timerfd_; 79 | Channel timerfdChannel_; 80 | // Timer list sorted by expiration 81 | TimerList timers_; 82 | 83 | // for cancel() 84 | ActiveTimerSet activeTimers_; 85 | bool callingExpiredTimers_; /* atomic */ 86 | ActiveTimerSet cancelingTimers_; 87 | }; 88 | 89 | } 90 | } 91 | #endif // MUDUO_NET_TIMERQUEUE_H 92 | -------------------------------------------------------------------------------- /mucgi/type.h: -------------------------------------------------------------------------------- 1 | #ifndef CGI_GLOBAL_TYPE_H_ 2 | #define CGI_GLOBAL_TYPE_H_ 3 | #include 4 | #include 5 | #include 6 | 7 | typedef std::map SSMap; 8 | typedef std::vector SVec; 9 | 10 | enum error_code_e 11 | { 12 | ERR_OK = 0, 13 | ERR_ICE_EXCEPTION, 14 | ERR_CALL_PROXY_FAILED, 15 | }; 16 | 17 | 18 | #endif 19 | 20 | --------------------------------------------------------------------------------