00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifndef _PASSENGER_MESSAGE_CHANNEL_H_
00021 #define _PASSENGER_MESSAGE_CHANNEL_H_
00022
00023 #include <algorithm>
00024 #include <string>
00025 #include <list>
00026 #include <vector>
00027
00028 #include <sys/types.h>
00029 #include <sys/socket.h>
00030 #include <arpa/inet.h>
00031 #include <errno.h>
00032 #include <unistd.h>
00033 #include <cstdarg>
00034
00035 #include "System.h"
00036 #include "Exceptions.h"
00037 #include "Utils.h"
00038
00039 namespace Passenger {
00040
00041 using namespace std;
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
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
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098 class MessageChannel {
00099 private:
00100 const static char DELIMITER = '\0';
00101 int fd;
00102
00103 public:
00104
00105
00106
00107
00108
00109
00110 MessageChannel() {
00111 this->fd = -1;
00112 }
00113
00114
00115
00116
00117 MessageChannel(int fd) {
00118 this->fd = fd;
00119 }
00120
00121
00122
00123
00124
00125
00126
00127
00128 void close() {
00129 if (fd != -1) {
00130 int ret = InterruptableCalls::close(fd);
00131 if (ret == -1) {
00132 throw SystemException("Cannot close file descriptor", errno);
00133 }
00134 fd = -1;
00135 }
00136 }
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148 void write(const list<string> &args) {
00149 list<string>::const_iterator it;
00150 string data;
00151 uint16_t dataSize = 0;
00152
00153 for (it = args.begin(); it != args.end(); it++) {
00154 dataSize += it->size() + 1;
00155 }
00156 data.reserve(dataSize + sizeof(dataSize));
00157 dataSize = htons(dataSize);
00158 data.append((const char *) &dataSize, sizeof(dataSize));
00159 for (it = args.begin(); it != args.end(); it++) {
00160 data.append(*it);
00161 data.append(1, DELIMITER);
00162 }
00163
00164 writeRaw(data);
00165 }
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179 void write(const char *name, ...) {
00180 list<string> args;
00181 args.push_back(name);
00182
00183 va_list ap;
00184 va_start(ap, name);
00185 while (true) {
00186 const char *arg = va_arg(ap, const char *);
00187 if (arg == NULL) {
00188 break;
00189 } else {
00190 args.push_back(arg);
00191 }
00192 }
00193 va_end(ap);
00194 write(args);
00195 }
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205 void writeScalar(const string &str) {
00206 writeScalar(str.c_str(), str.size());
00207 }
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219 void writeScalar(const char *data, unsigned int size) {
00220 uint32_t l = htonl(size);
00221 writeRaw((const char *) &l, sizeof(uint32_t));
00222 writeRaw(data, size);
00223 }
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236 void writeRaw(const char *data, unsigned int size) {
00237 ssize_t ret;
00238 unsigned int written = 0;
00239 do {
00240 ret = InterruptableCalls::write(fd, data + written, size - written);
00241 if (ret == -1) {
00242 throw SystemException("write() failed", errno);
00243 } else {
00244 written += ret;
00245 }
00246 } while (written < size);
00247 }
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258 void writeRaw(const string &data) {
00259 writeRaw(data.c_str(), data.size());
00260 }
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272 void writeFileDescriptor(int fileDescriptor) {
00273 struct msghdr msg;
00274 struct iovec vec;
00275 char dummy[1];
00276 #ifdef __APPLE__
00277 struct {
00278 struct cmsghdr header;
00279 int fd;
00280 } control_data;
00281 #else
00282 char control_data[CMSG_SPACE(sizeof(int))];
00283 #endif
00284 struct cmsghdr *control_header;
00285 int ret;
00286
00287 msg.msg_name = NULL;
00288 msg.msg_namelen = 0;
00289
00290
00291 dummy[0] = '\0';
00292 vec.iov_base = dummy;
00293 vec.iov_len = sizeof(dummy);
00294 msg.msg_iov = &vec;
00295 msg.msg_iovlen = 1;
00296
00297 msg.msg_control = (caddr_t) &control_data;
00298 msg.msg_controllen = sizeof(control_data);
00299 msg.msg_flags = 0;
00300
00301 control_header = CMSG_FIRSTHDR(&msg);
00302 control_header->cmsg_level = SOL_SOCKET;
00303 control_header->cmsg_type = SCM_RIGHTS;
00304 #ifdef __APPLE__
00305 control_header->cmsg_len = sizeof(control_data);
00306 control_data.fd = fileDescriptor;
00307 #else
00308 control_header->cmsg_len = CMSG_LEN(sizeof(int));
00309 memcpy(CMSG_DATA(control_header), &fileDescriptor, sizeof(int));
00310 #endif
00311
00312 ret = InterruptableCalls::sendmsg(fd, &msg, 0);
00313 if (ret == -1) {
00314 throw SystemException("Cannot send file descriptor with sendmsg()", errno);
00315 }
00316 }
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328 bool read(vector<string> &args) {
00329 uint16_t size;
00330 int ret;
00331 unsigned int alreadyRead = 0;
00332
00333 do {
00334 ret = InterruptableCalls::read(fd, (char *) &size + alreadyRead, sizeof(size) - alreadyRead);
00335 if (ret == -1) {
00336 throw SystemException("read() failed", errno);
00337 } else if (ret == 0) {
00338 return false;
00339 }
00340 alreadyRead += ret;
00341 } while (alreadyRead < sizeof(size));
00342 size = ntohs(size);
00343
00344 string buffer;
00345 args.clear();
00346 buffer.reserve(size);
00347 while (buffer.size() < size) {
00348 char tmp[1024 * 8];
00349 ret = InterruptableCalls::read(fd, tmp, min(size - buffer.size(), sizeof(tmp)));
00350 if (ret == -1) {
00351 throw SystemException("read() failed", errno);
00352 } else if (ret == 0) {
00353 return false;
00354 }
00355 buffer.append(tmp, ret);
00356 }
00357
00358 if (!buffer.empty()) {
00359 string::size_type start = 0, pos;
00360 const string &const_buffer(buffer);
00361 while ((pos = const_buffer.find('\0', start)) != string::npos) {
00362 args.push_back(const_buffer.substr(start, pos - start));
00363 start = pos + 1;
00364 }
00365 }
00366 return true;
00367 }
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378 bool readScalar(string &output) {
00379 uint32_t size;
00380 unsigned int remaining;
00381
00382 if (!readRaw(&size, sizeof(uint32_t))) {
00383 return false;
00384 }
00385 size = ntohl(size);
00386
00387 output.clear();
00388 output.reserve(size);
00389 remaining = size;
00390 while (remaining > 0) {
00391 char buf[1024 * 32];
00392 unsigned int blockSize = min((unsigned int) sizeof(buf), remaining);
00393
00394 if (!readRaw(buf, blockSize)) {
00395 return false;
00396 }
00397 output.append(buf, blockSize);
00398 remaining -= blockSize;
00399 }
00400 return true;
00401 }
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419 bool readRaw(void *buf, unsigned int size) {
00420 ssize_t ret;
00421 unsigned int alreadyRead = 0;
00422
00423 while (alreadyRead < size) {
00424 ret = InterruptableCalls::read(fd, (char *) buf + alreadyRead, size - alreadyRead);
00425 if (ret == -1) {
00426 throw SystemException("read() failed", errno);
00427 } else if (ret == 0) {
00428 return false;
00429 } else {
00430 alreadyRead += ret;
00431 }
00432 }
00433 return true;
00434 }
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448 int readFileDescriptor() {
00449 struct msghdr msg;
00450 struct iovec vec;
00451 char dummy[1];
00452 #ifdef __APPLE__
00453
00454
00455 struct {
00456 struct cmsghdr header;
00457 int fd;
00458 } control_data;
00459 #define EXPECTED_CMSG_LEN sizeof(control_data)
00460 #else
00461 char control_data[CMSG_SPACE(sizeof(int))];
00462 #define EXPECTED_CMSG_LEN CMSG_LEN(sizeof(int))
00463 #endif
00464 struct cmsghdr *control_header;
00465 int ret;
00466
00467 msg.msg_name = NULL;
00468 msg.msg_namelen = 0;
00469
00470 dummy[0] = '\0';
00471 vec.iov_base = dummy;
00472 vec.iov_len = sizeof(dummy);
00473 msg.msg_iov = &vec;
00474 msg.msg_iovlen = 1;
00475
00476 msg.msg_control = (caddr_t) &control_data;
00477 msg.msg_controllen = sizeof(control_data);
00478 msg.msg_flags = 0;
00479
00480 ret = InterruptableCalls::recvmsg(fd, &msg, 0);
00481 if (ret == -1) {
00482 throw SystemException("Cannot read file descriptor with recvmsg()", errno);
00483 }
00484
00485 control_header = CMSG_FIRSTHDR(&msg);
00486 if (control_header->cmsg_len != EXPECTED_CMSG_LEN
00487 || control_header->cmsg_level != SOL_SOCKET
00488 || control_header->cmsg_type != SCM_RIGHTS) {
00489 throw IOException("No valid file descriptor received.");
00490 }
00491 #ifdef __APPLE__
00492 return control_data.fd;
00493 #else
00494 return *((int *) CMSG_DATA(control_header));
00495 #endif
00496 }
00497 };
00498
00499 }
00500
00501 #endif