fastcgi++
protocol.hpp
Go to the documentation of this file.
00001 
00002 /***************************************************************************
00003 * Copyright (C) 2007 Eddie Carle [eddie@erctech.org]                       *
00004 *                                                                          *
00005 * This file is part of fastcgi++.                                          *
00006 *                                                                          *
00007 * fastcgi++ is free software: you can redistribute it and/or modify it     *
00008 * under the terms of the GNU Lesser General Public License as  published   *
00009 * by the Free Software Foundation, either version 3 of the License, or (at *
00010 * your option) any later version.                                          *
00011 *                                                                          *
00012 * fastcgi++ is distributed in the hope that it will be useful, but WITHOUT *
00013 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    *
00014 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public     *
00015 * License for more details.                                                *
00016 *                                                                          *
00017 * You should have received a copy of the GNU Lesser General Public License *
00018 * along with fastcgi++.  If not, see <http://www.gnu.org/licenses/>.       *
00019 ****************************************************************************/
00020 
00021 
00022 #ifndef PROTOCOL_HPP
00023 #define PROTOCOL_HPP
00024 
00025 #include <fastcgi++/config.h>
00026 #include <map>
00027 #include <string>
00028 #include <exception>
00029 
00030 #if defined (HAVE_ENDIAN_H)
00031 #include <endian.h>
00032 #elif defined (HAVE_MACHINE_ENDIAN_H)
00033 #include <machine/endian.h>
00034 #elif defined (HAVE_ARPA_ENDIAN_H)
00035 #include <arpa/nameser_compat.h>
00036 #else
00037 #error Could not locate a file that defines endianess
00038 #endif
00039 
00040 #include <stdint.h>
00041 
00042 #include <boost/shared_array.hpp>
00043 
00044 #include <fastcgi++/message.hpp>
00045 
00047 namespace Fastcgipp
00048 {
00050    extern const char version[];
00051    namespace Protocol
00052    {
00054       typedef uint16_t RequestId;
00055       
00057 
00064       struct FullId
00065       {
00067 
00074          FullId(RequestId fcgiId_, int fd_): fcgiId(fcgiId_), fd(fd_) { } 
00075          FullId() { }
00077          RequestId fcgiId;
00079          uint16_t fd;
00080       };
00081       
00083       enum RecordType { BEGIN_REQUEST=1, ABORT_REQUEST=2, END_REQUEST=3, PARAMS=4, IN=5, OUT=6, ERR=7, DATA=8, GET_VALUES=9, GET_VALUES_RESULT=10, UNKNOWN_TYPE=11 };
00084       
00086       extern const char* recordTypeLabels[];
00087    }
00088 }
00089       
00090 
00091 #include <fastcgi++/exceptions.hpp>
00092 
00094 namespace Fastcgipp
00095 {
00097 
00103    namespace Protocol
00104    {
00106       const int version=1;
00107 
00109       const int chunkSize=8;
00110 
00112       enum Role { RESPONDER=1, AUTHORIZER=2, FILTER=3 };
00113 
00115       enum ProtocolStatus { REQUEST_COMPLETE=0, CANT_MPX_CONN=1, OVERLOADED=2, UNKNOWN_ROLE=3 };
00116 
00118 
00121       inline bool operator>(const FullId& x, const FullId& y) { return *(uint32_t*)&x.fcgiId > *(uint32_t*)&y.fcgiId; }
00122 
00124 
00127       inline bool operator<(const FullId& x, const FullId& y) { return *(uint32_t*)&x.fcgiId < *(uint32_t*)&y.fcgiId; }
00128 
00130 
00133       inline bool operator==(const FullId& x, const FullId& y) { return *(uint32_t*)&x.fcgiId == *(uint32_t*)&y.fcgiId; }
00134 
00136 
00144 #if __BYTE_ORDER == __LITTLE_ENDIAN
00145       template<class T> T readBigEndian(T value)
00146       {
00147          T result;
00148          char* pValue=(char*)&value-1;
00149          char* pValueEnd=pValue+sizeof(T);
00150          char* pResult=(char*)&result+sizeof(T);
00151          while(pValue!=pValueEnd)
00152             *--pResult=*++pValue;
00153          return result;
00154       }
00155 #elif __BYTE_ORDER == __BIG_ENDIAN
00156       template<class T> T readBigEndian(T value)
00157       {
00158          return value;
00159       }
00160 #endif
00161 
00163 
00168       class Header
00169       {
00170       public:
00172 
00175          void setVersion(uint8_t version_) { version=version_; }
00176 
00178 
00181          int getVersion() const { return version; }
00182 
00184 
00187          void setType(RecordType type_) { type=static_cast<uint8_t>(type_); }
00188 
00190 
00193          RecordType getType() const { return static_cast<RecordType>(type); }
00194 
00196 
00199          void setRequestId(RequestId requestId_) { *(uint16_t*)&requestIdB1=readBigEndian(requestId_); }
00200 
00202 
00205          RequestId getRequestId() const { return readBigEndian(*(uint16_t*)&requestIdB1); }
00206 
00208 
00211          void setContentLength(uint16_t contentLength_) { *(uint16_t*)&contentLengthB1=readBigEndian(contentLength_); }
00212 
00214 
00217          int getContentLength() const { return readBigEndian(*(uint16_t*)&contentLengthB1); }
00218 
00220 
00223          void setPaddingLength(uint8_t paddingLength_) { paddingLength=paddingLength_; }
00224 
00226 
00229          int getPaddingLength() const { return paddingLength; }
00230       private:
00232          uint8_t version;
00234          uint8_t type;
00236          uint8_t requestIdB1;
00238          uint8_t requestIdB0;
00240          uint8_t contentLengthB1;
00242          uint8_t contentLengthB0;
00244          uint8_t paddingLength;
00246          uint8_t reserved;
00247       };
00248 
00249       
00251 
00256       class BeginRequest
00257       {
00258       public:
00260 
00263          Role getRole() const { return static_cast<Role>(readBigEndian(*(uint16_t*)&roleB1)); }
00264 
00266 
00273          bool getKeepConn() const { return flags & keepConnBit; }
00274       private:
00276          static const int keepConnBit = 1;
00277 
00279          uint8_t roleB1;
00281          uint8_t roleB0;
00283          uint8_t flags;
00285          uint8_t reserved[5];
00286       };
00287 
00289 
00294       class UnknownType
00295       {
00296       public:
00298 
00301          void setType(RecordType type_) { type=static_cast<uint8_t>(type_); }
00302       private:
00304          uint8_t type;
00306          uint8_t reserved[7];
00307       };
00308 
00310 
00316       class EndRequest
00317       {
00318       public:
00320 
00326          void setAppStatus(int status) { *(int*)&appStatusB3=readBigEndian(status); }
00327 
00329 
00334          void setProtocolStatus(ProtocolStatus status) { protocolStatus=static_cast<uint8_t>(status); }
00335       private:
00337          uint8_t appStatusB3;
00339          uint8_t appStatusB2;
00341          uint8_t appStatusB1;
00343          uint8_t appStatusB0;
00345          uint8_t protocolStatus;
00347          uint8_t reserved[3];
00348       };
00349 
00351 
00362       void processParamHeader(const char* data, size_t dataSize, const char*& name, size_t& nameSize, const char*& value, size_t& valueSize);
00363 
00364       
00366 
00379       template<int NAMELENGTH, int VALUELENGTH, int PADDINGLENGTH> struct ManagementReply
00380       {
00381       private:
00383          Header header;
00385          uint8_t nameLength;
00387          uint8_t valueLength;
00389          uint8_t name[NAMELENGTH];
00391          uint8_t value[VALUELENGTH];
00393          uint8_t padding[PADDINGLENGTH];
00394       public:
00396 
00406          ManagementReply(const char* name_, const char* value_): nameLength(NAMELENGTH), valueLength(VALUELENGTH)
00407          {
00408             for(int i=0; i<NAMELENGTH; i++) name[i]=*(name_+i);
00409             for(int i=0; i<VALUELENGTH; i++) value[i]=*(value_+i);
00410             header.setVersion(version);
00411             header.setType(GET_VALUES_RESULT);
00412             header.setRequestId(0);
00413             header.setContentLength(NAMELENGTH+VALUELENGTH);
00414             header.setPaddingLength(PADDINGLENGTH);
00415          }
00416       };
00417 
00419       extern ManagementReply<14, 2, 8> maxConnsReply;
00421       extern ManagementReply<13, 2, 1> maxReqsReply;
00423       extern ManagementReply<15, 1, 8> mpxsConnsReply;
00424    }
00425 }
00426 
00427 #endif