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
00048 namespace Passenger {
00049
00050 using namespace boost;
00051 using namespace oxt;
00052 using namespace std;
00053
00054
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 class Session {
00080 protected:
00081 string detachKey;
00082 string connectPassword;
00083
00084 public:
00085
00086
00087
00088 virtual ~Session() {}
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098 virtual void initiate() = 0;
00099
00100
00101
00102
00103
00104 virtual bool initiated() const = 0;
00105
00106
00107
00108
00109
00110
00111
00112 virtual string getSocketType() const = 0;
00113
00114
00115
00116
00117
00118
00119
00120
00121 virtual string getSocketName() const = 0;
00122
00123
00124
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 virtual void sendHeaders(const char *headers, unsigned int size) {
00152 TRACE_POINT();
00153 int stream = getStream();
00154 if (stream == -1) {
00155 throw IOException("Cannot write headers to the request handler "
00156 "because the I/O stream has already been closed or discarded.");
00157 }
00158 try {
00159 MessageChannel(stream).writeScalar(headers, size);
00160 } catch (SystemException &e) {
00161 e.setBriefMessage("An error occured while writing headers "
00162 "to the request handler");
00163 throw;
00164 }
00165 }
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175 virtual void sendHeaders(const StaticString &headers) {
00176 sendHeaders(headers.c_str(), headers.size());
00177 }
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194 virtual void sendBodyBlock(const char *block, unsigned int size) {
00195 TRACE_POINT();
00196 int stream = getStream();
00197 if (stream == -1) {
00198 throw IOException("Cannot write request body block to the "
00199 "request handler because the I/O channel has "
00200 "already been closed or discarded.");
00201 }
00202 try {
00203 MessageChannel(stream).writeRaw(block, size);
00204 } catch (SystemException &e) {
00205 e.setBriefMessage("An error occured while sending the "
00206 "request body to the request handler");
00207 throw;
00208 }
00209 }
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220 virtual int getStream() const = 0;
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233 virtual void setReaderTimeout(unsigned int msec) = 0;
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246 virtual void setWriterTimeout(unsigned int msec) = 0;
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257 virtual void shutdownReader() = 0;
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268 virtual void shutdownWriter() = 0;
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278 virtual void closeStream() = 0;
00279
00280
00281
00282
00283
00284
00285
00286
00287 virtual void discardStream() = 0;
00288
00289
00290
00291
00292
00293 virtual pid_t getPid() const = 0;
00294
00295 const string getDetachKey() const {
00296 return detachKey;
00297 }
00298
00299
00300
00301
00302
00303 const string getConnectPassword() const {
00304 return connectPassword;
00305 }
00306 };
00307
00308 typedef shared_ptr<Session> SessionPtr;
00309
00310
00311
00312
00313
00314 class StandardSession: public Session {
00315 protected:
00316 pid_t pid;
00317 function<void()> closeCallback;
00318 string socketType;
00319 string socketName;
00320
00321
00322 int fd;
00323 bool isInitiated;
00324
00325 public:
00326 StandardSession(pid_t pid,
00327 const function<void()> &closeCallback,
00328 const string &socketType,
00329 const string &socketName,
00330 const string &detachKey,
00331 const string &connectPassword)
00332 {
00333 TRACE_POINT();
00334 if (socketType != "unix" && socketType != "tcp") {
00335 throw IOException("Unsupported socket type '" + socketType + "'");
00336 }
00337 this->pid = pid;
00338 this->closeCallback = closeCallback;
00339 this->socketType = socketType;
00340 this->socketName = socketName;
00341 this->detachKey = detachKey;
00342 this->connectPassword = connectPassword;
00343 fd = -1;
00344 isInitiated = false;
00345 }
00346
00347 virtual ~StandardSession() {
00348 TRACE_POINT();
00349 closeStream();
00350 if (closeCallback != NULL) {
00351 closeCallback();
00352 }
00353 }
00354
00355 virtual void initiate() {
00356 TRACE_POINT();
00357 if (socketType == "unix") {
00358 fd = connectToUnixServer(socketName.c_str());
00359 } else {
00360 vector<string> args;
00361
00362 split(socketName, ':', args);
00363 if (args.size() != 2 || atoi(args[1]) == 0) {
00364 UPDATE_TRACE_POINT();
00365 throw IOException("Invalid TCP/IP address '" + socketName + "'");
00366 }
00367 fd = connectToTcpServer(args[0].c_str(), atoi(args[1]));
00368 }
00369 isInitiated = true;
00370 }
00371
00372 virtual bool initiated() const {
00373 return isInitiated;
00374 }
00375
00376 virtual string getSocketType() const {
00377 return socketType;
00378 }
00379
00380 virtual string getSocketName() const {
00381 return socketName;
00382 }
00383
00384 virtual int getStream() const {
00385 return fd;
00386 }
00387
00388 virtual void setReaderTimeout(unsigned int msec) {
00389 MessageChannel(fd).setReadTimeout(msec);
00390 }
00391
00392 virtual void setWriterTimeout(unsigned int msec) {
00393 MessageChannel(fd).setWriteTimeout(msec);
00394 }
00395
00396 virtual void shutdownReader() {
00397 TRACE_POINT();
00398 if (fd != -1) {
00399 int ret = syscalls::shutdown(fd, SHUT_RD);
00400 if (ret == -1) {
00401 int e = errno;
00402
00403 if (e != ENOTCONN) {
00404 throw SystemException("Cannot shutdown the reader stream",
00405 e);
00406 }
00407 }
00408 }
00409 }
00410
00411 virtual void shutdownWriter() {
00412 TRACE_POINT();
00413 if (fd != -1) {
00414 int ret = syscalls::shutdown(fd, SHUT_WR);
00415 if (ret == -1) {
00416 int e = errno;
00417
00418 if (e != ENOTCONN) {
00419 throw SystemException("Cannot shutdown the writer stream",
00420 e);
00421 }
00422 }
00423 }
00424 }
00425
00426 virtual void closeStream() {
00427 TRACE_POINT();
00428 if (fd != -1) {
00429 int ret = syscalls::close(fd);
00430 fd = -1;
00431 if (ret == -1) {
00432 if (errno == EIO) {
00433 throw SystemException("A write operation on the session stream failed",
00434 errno);
00435 } else {
00436 throw SystemException("Cannot close the session stream",
00437 errno);
00438 }
00439 }
00440 }
00441 }
00442
00443 virtual void discardStream() {
00444 fd = -1;
00445 }
00446
00447 virtual pid_t getPid() const {
00448 return pid;
00449 }
00450 };
00451
00452
00453 }
00454
00455 #endif