#include #include #include #include #include #include "LogFile.h" #include "ThreadMonitor.h" #include "SocketInfo.h" static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; std::string SocketInfo::getValidString() const { switch (_valid) { case valid: return "valid"; case invalidRetry: return "invalidRetry"; case invalidFail: return "invalidFail"; case invalidTooMany: return "invalidTooMany"; default: return "Valid(" + ntoa(_valid) + ")"; // Unknown, shouldn't happen. } } TclList SocketInfo::debugDump() const { TclList a; TclList b(1, true, "hi"); return TclList(TclList("_socketHandle", _socketHandle), TclList("_EOF", atEOF()), TclList("_valid", getValidString()), TclList("isGoingDown()", isGoingDown()), TclList("_serialNumber", _serialNumber), TclList("remoteAddr()", remoteAddr()), TclList("objectIsValid()", objectIsValid())); } inline int64_t SocketInfo::expectedValidator() const { return ((int64_t)this)^_serialNumber; } bool SocketInfo::objectIsValid() const { // We've had trouble with people using SocketInfo objects after they were // deleted. We try not to share a lot of data between threads, but we have // to share socket objects to keep track of requests. If two clients make // two different requests, we need to know which client gets each response. // // Every valid SocketInfo object should have a unique serial number. 0 is // reserved for no socket / a NULL pointer to a SocketInfo object. // _serialNumber is set to a unique number at the top of the constructor, // and set to 0 at the bottom of the destructor. So, _serialNumber gives // a unique id to each object when it's alive, but we also use it as a flag // to see if we are using a recently deleted object. // // Just looking at _serialNumber is not sufficient. If memory gets reused // it's somewhat random whether or not _serialNumber is 0. If we assume // _serialNumber could be overwritten with any value, and any value is just // as likely as any other, the chance that this will remain 0 after the // memory is reused is pretty low. So just using _serialNumber would give // us a lot of false negatives. // // The _validator field gives us another value to look for. It should be // set to a very specific value which depends on the _serialNumber. The // chance that this will be correct when looking at random memory is 1 in // 2^64. So we went from a 1 in 2^64 chance of noticing the problem to a // 1 in 2^64 chance of missing the problem. return _serialNumber && (_validator == expectedValidator()); } SocketInfo::SerialNumber SocketInfo::_lastSerialNumber = 0; SocketInfo::SerialNumber SocketInfo::getNextSerialNumber() { return __sync_add_and_fetch(&_lastSerialNumber, 1); } SocketInfo::SocketInfo(int parentSocket) : _EOF(false), _goingDown(false), _valid(valid), _serialNumber(getNextSerialNumber()), _validator(expectedValidator()) { socklen_t incoming_addr_len = sizeof(incoming_addr); _socketHandle = accept(parentSocket, (sockaddr*)&incoming_addr, &incoming_addr_len); if (_socketHandle < 0) { _EOF = true; switch (errno) { case EBADF: case ENOTSOCK: case EOPNOTSUPP: case EINVAL: case EFAULT: { _valid = invalidFail; break; } case EMFILE: case ENFILE: case ENOBUFS: case ENOMEM : { _valid = invalidTooMany; break; } default: { // There is no complete list. When we don't know for certain, // we assume that retries make sense. In some cases that is // really required. Many of these errors are unavoidable. _valid = invalidRetry; break; } } char errorMessageBuffer[256]; int saveErrorno = errno; char *errorMessage = strerror_r(errno, errorMessageBuffer, 255); TclList logMsg; logMsg<<"SocketInfo.C" <<"Error" <<"accept()" <ai_addr, results->ai_addrlen); freeaddrinfo(results); if (connectFailed) { std::string errorMsg(errorString()); TclList logMsg; logMsg<<"Error connecting to client" < maxCount) { count = maxCount; } else { count = bufferSize; } return write(buffer.data(), count); } ssize_t SocketInfo::write(std::string const &buffer) const { return write(buffer.data(), buffer.size()); } ssize_t SocketInfo::write(const char *buffer, int maxCount) const { ssize_t result = ::write(_socketHandle, buffer, maxCount); if ((result == -1) && ((errno == EAGAIN) || (errno == EINTR))) { // Nothing was accomplished but we should retry soon result = 0; std::string errorMessage = errorString(); TclList logMsg; logMsg<<"SocketInfo.C" <<"Warning" <<"write()" <>24) + '.' + itoa((ip>>16)&255) + '.' + itoa((ip>>8)&255) + '.' + itoa(ip&255); } std::string result = _remoteAddr; pthread_mutex_unlock(&mutex); return result; } void SocketInfo::setRemoteAddr(std::string value) { pthread_mutex_lock(&mutex); _remoteAddr = value; pthread_mutex_unlock(&mutex); } class SocketInfoInitializer { public: SocketInfoInitializer() { signal(SIGPIPE, SIG_IGN); } }; static SocketInfoInitializer doIt;