00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #ifndef _PASSENGER_SESSION_H_
00026 #define _PASSENGER_SESSION_H_
00027
00028 #include <sys/types.h>
00029 #include <sys/socket.h>
00030 #include <sys/un.h>
00031 #include <unistd.h>
00032 #include <netdb.h>
00033 #include <cerrno>
00034 #include <cstring>
00035
00036 #include <string>
00037 #include <vector>
00038
00039 #include <boost/shared_ptr.hpp>
00040 #include <boost/function.hpp>
00041 #include <oxt/backtrace.hpp>
00042 #include <oxt/system_calls.hpp>
00043
00044 #include "MessageChannel.h"
00045 #include "StaticString.h"
00046 #include "Exceptions.h"
00047 #include "Utils/StrIntUtils.h"
00048 #include "Utils/IOUtils.h"
00049
00050 namespace Passenger {
00051
00052 using namespace boost;
00053 using namespace oxt;
00054 using namespace std;
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081 class Session {
00082 protected:
00083 string detachKey;
00084 string connectPassword;
00085 string gupid;
00086
00087 public:
00088
00089
00090
00091 virtual ~Session() {}
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101 virtual void initiate() = 0;
00102
00103
00104
00105
00106
00107 virtual bool initiated() const = 0;
00108
00109
00110
00111
00112
00113
00114
00115 virtual string getSocketType() const = 0;
00116
00117
00118
00119
00120
00121
00122
00123
00124 virtual string getSocketName() const = 0;
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154 virtual void sendHeaders(const char *headers, unsigned int size) {
00155 TRACE_POINT();
00156 int stream = getStream();
00157 if (stream == -1) {
00158 throw IOException("Cannot write headers to the request handler "
00159 "because the I/O stream has already been closed or discarded.");
00160 }
00161 try {
00162 MessageChannel(stream).writeScalar(headers, size);
00163 } catch (SystemException &e) {
00164 e.setBriefMessage("An error occured while writing headers "
00165 "to the request handler");
00166 throw;
00167 }
00168 }
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178 virtual void sendHeaders(const StaticString &headers) {
00179 sendHeaders(headers.c_str(), headers.size());
00180 }
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197 virtual void sendBodyBlock(const char *block, unsigned int size) {
00198 TRACE_POINT();
00199 int stream = getStream();
00200 if (stream == -1) {
00201 throw IOException("Cannot write request body block to the "
00202 "request handler because the I/O channel has "
00203 "already been closed or discarded.");
00204 }
00205 try {
00206 writeExact(stream, block, size);
00207 } catch (SystemException &e) {
00208 e.setBriefMessage("An error occured while sending the "
00209 "request body to the request handler");
00210 throw;
00211 }
00212 }
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223 virtual int getStream() const = 0;
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236 virtual void setReaderTimeout(unsigned int msec) = 0;
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249 virtual void setWriterTimeout(unsigned int msec) = 0;
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260 virtual void shutdownReader() = 0;
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271 virtual void shutdownWriter() = 0;
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281 virtual void closeStream() = 0;
00282
00283
00284
00285
00286
00287
00288
00289
00290 virtual void discardStream() = 0;
00291
00292
00293
00294
00295
00296 virtual pid_t getPid() const = 0;
00297
00298 const string getDetachKey() const {
00299 return detachKey;
00300 }
00301
00302
00303
00304
00305
00306 const string getConnectPassword() const {
00307 return connectPassword;
00308 }
00309
00310 const string getGupid() const {
00311 return gupid;
00312 }
00313 };
00314
00315 typedef shared_ptr<Session> SessionPtr;
00316
00317
00318
00319
00320
00321 class StandardSession: public Session {
00322 public:
00323 typedef function<void (const StandardSession *)> CloseCallback;
00324
00325 protected:
00326 pid_t pid;
00327 CloseCallback closeCallback;
00328 string socketType;
00329 string socketName;
00330
00331
00332 int fd;
00333 bool isInitiated;
00334
00335 public:
00336 StandardSession(pid_t pid,
00337 const CloseCallback &closeCallback,
00338 const string &socketType,
00339 const string &socketName,
00340 const string &detachKey,
00341 const string &connectPassword,
00342 const string &gupid)
00343 {
00344 TRACE_POINT();
00345 if (socketType != "unix" && socketType != "tcp") {
00346 throw IOException("Unsupported socket type '" + socketType + "'");
00347 }
00348 this->pid = pid;
00349 this->closeCallback = closeCallback;
00350 this->socketType = socketType;
00351 this->socketName = socketName;
00352 this->detachKey = detachKey;
00353 this->connectPassword = connectPassword;
00354 this->gupid = gupid;
00355 fd = -1;
00356 isInitiated = false;
00357 }
00358
00359 virtual ~StandardSession() {
00360 TRACE_POINT();
00361 closeStream();
00362 if (closeCallback != NULL) {
00363 closeCallback(this);
00364 }
00365 }
00366
00367 virtual void initiate() {
00368 TRACE_POINT();
00369 if (socketType == "unix") {
00370 fd = connectToUnixServer(socketName.c_str());
00371 } else {
00372 vector<string> args;
00373
00374 split(socketName, ':', args);
00375 if (args.size() != 2 || atoi(args[1]) == 0) {
00376 UPDATE_TRACE_POINT();
00377 throw IOException("Invalid TCP/IP address '" + socketName + "'");
00378 }
00379 fd = connectToTcpServer(args[0].c_str(), atoi(args[1]));
00380 }
00381 isInitiated = true;
00382 }
00383
00384 virtual bool initiated() const {
00385 return isInitiated;
00386 }
00387
00388 virtual string getSocketType() const {
00389 return socketType;
00390 }
00391
00392 virtual string getSocketName() const {
00393 return socketName;
00394 }
00395
00396 virtual int getStream() const {
00397 return fd;
00398 }
00399
00400 virtual void setReaderTimeout(unsigned int msec) {
00401 MessageChannel(fd).setReadTimeout(msec);
00402 }
00403
00404 virtual void setWriterTimeout(unsigned int msec) {
00405 MessageChannel(fd).setWriteTimeout(msec);
00406 }
00407
00408 virtual void shutdownReader() {
00409 TRACE_POINT();
00410 if (fd != -1) {
00411 int ret = syscalls::shutdown(fd, SHUT_RD);
00412 if (ret == -1) {
00413 int e = errno;
00414
00415 if (e != ENOTCONN) {
00416 throw SystemException("Cannot shutdown the reader stream",
00417 e);
00418 }
00419 }
00420 }
00421 }
00422
00423 virtual void shutdownWriter() {
00424 TRACE_POINT();
00425 if (fd != -1) {
00426 int ret = syscalls::shutdown(fd, SHUT_WR);
00427 if (ret == -1) {
00428 int e = errno;
00429
00430 if (e != ENOTCONN) {
00431 throw SystemException("Cannot shutdown the writer stream",
00432 e);
00433 }
00434 }
00435 }
00436 }
00437
00438 virtual void closeStream() {
00439 TRACE_POINT();
00440 if (fd != -1) {
00441 int ret = syscalls::close(fd);
00442 fd = -1;
00443 if (ret == -1) {
00444 int e = errno;
00445 if (errno == EIO) {
00446 throw SystemException(
00447 "A write operation on the session stream failed",
00448 e);
00449 } else {
00450 throw SystemException(
00451 "Cannot close the session stream",
00452 e);
00453 }
00454 }
00455 }
00456 }
00457
00458 virtual void discardStream() {
00459 fd = -1;
00460 }
00461
00462 virtual pid_t getPid() const {
00463 return pid;
00464 }
00465 };
00466
00467
00468 }
00469
00470 #endif