fastcgi++
protocol.hpp
Go to the documentation of this file.
1 
2 /***************************************************************************
3 * Copyright (C) 2007 Eddie Carle [eddie@erctech.org] *
4 * *
5 * This file is part of fastcgi++. *
6 * *
7 * fastcgi++ is free software: you can redistribute it and/or modify it *
8 * under the terms of the GNU Lesser General Public License as published *
9 * by the Free Software Foundation, either version 3 of the License, or (at *
10 * your option) any later version. *
11 * *
12 * fastcgi++ is distributed in the hope that it will be useful, but WITHOUT *
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public *
15 * License for more details. *
16 * *
17 * You should have received a copy of the GNU Lesser General Public License *
18 * along with fastcgi++. If not, see <http://www.gnu.org/licenses/>. *
19 ****************************************************************************/
20 
21 
22 #ifndef PROTOCOL_HPP
23 #define PROTOCOL_HPP
24 
25 #include <fastcgi++/config.h>
26 #include <map>
27 #include <string>
28 #include <exception>
29 
30 #if defined (HAVE_ENDIAN_H)
31 #include <endian.h>
32 #elif defined (HAVE_MACHINE_ENDIAN_H)
33 #include <machine/endian.h>
34 #elif defined (HAVE_ARPA_ENDIAN_H)
35 #include <arpa/nameser_compat.h>
36 #else
37 #error Could not locate a file that defines endianess
38 #endif
39 
40 #include <stdint.h>
41 
42 #include <boost/shared_array.hpp>
43 
44 #include <fastcgi++/message.hpp>
45 
47 namespace Fastcgipp
48 {
50  extern const char version[];
51  namespace Protocol
52  {
54  typedef uint16_t RequestId;
55 
57 
64  struct FullId
65  {
67 
74  FullId(RequestId fcgiId_, int fd_): fcgiId(fcgiId_), fd(fd_) { }
75  FullId() { }
79  uint16_t fd;
80  };
81 
84 
86  extern const char* recordTypeLabels[];
87  }
88 }
89 
90 
91 #include <fastcgi++/exceptions.hpp>
92 
94 namespace Fastcgipp
95 {
97 
103  namespace Protocol
104  {
106  const int version=1;
107 
109  const int chunkSize=8;
110 
112  enum Role { RESPONDER=1, AUTHORIZER=2, FILTER=3 };
113 
116 
118 
121  inline bool operator>(const FullId& x, const FullId& y) { return *(uint32_t*)&x.fcgiId > *(uint32_t*)&y.fcgiId; }
122 
124 
127  inline bool operator<(const FullId& x, const FullId& y) { return *(uint32_t*)&x.fcgiId < *(uint32_t*)&y.fcgiId; }
128 
130 
133  inline bool operator==(const FullId& x, const FullId& y) { return *(uint32_t*)&x.fcgiId == *(uint32_t*)&y.fcgiId; }
134 
136 
144 #if __BYTE_ORDER == __LITTLE_ENDIAN
145  template<class T> T readBigEndian(T value)
146  {
147  T result;
148  char* pValue=(char*)&value-1;
149  char* pValueEnd=pValue+sizeof(T);
150  char* pResult=(char*)&result+sizeof(T);
151  while(pValue!=pValueEnd)
152  *--pResult=*++pValue;
153  return result;
154  }
155 #elif __BYTE_ORDER == __BIG_ENDIAN
156  template<class T> T readBigEndian(T value)
157  {
158  return value;
159  }
160 #endif
161 
163 
168  class Header
169  {
170  public:
172 
175  void setVersion(uint8_t version_) { version=version_; }
176 
178 
181  int getVersion() const { return version; }
182 
184 
187  void setType(RecordType type_) { type=static_cast<uint8_t>(type_); }
188 
190 
193  RecordType getType() const { return static_cast<RecordType>(type); }
194 
196 
199  void setRequestId(RequestId requestId_) { *(uint16_t*)&requestIdB1=readBigEndian(requestId_); }
200 
202 
205  RequestId getRequestId() const { return readBigEndian(*(uint16_t*)&requestIdB1); }
206 
208 
211  void setContentLength(uint16_t contentLength_) { *(uint16_t*)&contentLengthB1=readBigEndian(contentLength_); }
212 
214 
217  int getContentLength() const { return readBigEndian(*(uint16_t*)&contentLengthB1); }
218 
220 
223  void setPaddingLength(uint8_t paddingLength_) { paddingLength=paddingLength_; }
224 
226 
229  int getPaddingLength() const { return paddingLength; }
230  private:
232  uint8_t version;
234  uint8_t type;
236  uint8_t requestIdB1;
238  uint8_t requestIdB0;
244  uint8_t paddingLength;
246  uint8_t reserved;
247  };
248 
249 
251 
257  {
258  public:
260 
263  Role getRole() const { return static_cast<Role>(readBigEndian(*(uint16_t*)&roleB1)); }
264 
266 
273  bool getKeepConn() const { return flags & keepConnBit; }
274  private:
276  static const int keepConnBit = 1;
277 
279  uint8_t roleB1;
281  uint8_t roleB0;
283  uint8_t flags;
285  uint8_t reserved[5];
286  };
287 
289 
295  {
296  public:
298 
301  void setType(RecordType type_) { type=static_cast<uint8_t>(type_); }
302  private:
304  uint8_t type;
306  uint8_t reserved[7];
307  };
308 
310 
317  {
318  public:
320 
326  void setAppStatus(int status) { *(int*)&appStatusB3=readBigEndian(status); }
327 
329 
334  void setProtocolStatus(ProtocolStatus status) { protocolStatus=static_cast<uint8_t>(status); }
335  private:
337  uint8_t appStatusB3;
339  uint8_t appStatusB2;
341  uint8_t appStatusB1;
343  uint8_t appStatusB0;
345  uint8_t protocolStatus;
347  uint8_t reserved[3];
348  };
349 
351 
362  void processParamHeader(const char* data, size_t dataSize, const char*& name, size_t& nameSize, const char*& value, size_t& valueSize);
363 
364 
366 
379  template<int NAMELENGTH, int VALUELENGTH, int PADDINGLENGTH> struct ManagementReply
380  {
381  private:
385  uint8_t nameLength;
387  uint8_t valueLength;
389  uint8_t name[NAMELENGTH];
391  uint8_t value[VALUELENGTH];
393  uint8_t padding[PADDINGLENGTH];
394  public:
396 
406  ManagementReply(const char* name_, const char* value_): nameLength(NAMELENGTH), valueLength(VALUELENGTH)
407  {
408  for(int i=0; i<NAMELENGTH; i++) name[i]=*(name_+i);
409  for(int i=0; i<VALUELENGTH; i++) value[i]=*(value_+i);
412  header.setRequestId(0);
413  header.setContentLength(NAMELENGTH+VALUELENGTH);
414  header.setPaddingLength(PADDINGLENGTH);
415  }
416  };
417 
419  extern ManagementReply<14, 2, 8> maxConnsReply;
421  extern ManagementReply<13, 2, 1> maxReqsReply;
423  extern ManagementReply<15, 1, 8> mpxsConnsReply;
424  }
425 }
426 
427 #endif