David Reiss | 2324871 | 2010-10-06 17:10:08 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Licensed to the Apache Software Foundation (ASF) under one |
| 3 | * or more contributor license agreements. See the NOTICE file |
| 4 | * distributed with this work for additional information |
| 5 | * regarding copyright ownership. The ASF licenses this file |
| 6 | * to you under the Apache License, Version 2.0 (the |
| 7 | * "License"); you may not use this file except in compliance |
| 8 | * with the License. You may obtain a copy of the License at |
| 9 | * |
| 10 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 11 | * |
| 12 | * Unless required by applicable law or agreed to in writing, |
| 13 | * software distributed under the License is distributed on an |
| 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| 15 | * KIND, either express or implied. See the License for the |
| 16 | * specific language governing permissions and limitations |
| 17 | * under the License. |
| 18 | */ |
| 19 | |
Roger Meier | 49ff8b1 | 2012-04-13 09:12:31 +0000 | [diff] [blame] | 20 | #include <thrift/server/TClientInfo.h> |
David Reiss | 2324871 | 2010-10-06 17:10:08 +0000 | [diff] [blame] | 21 | |
| 22 | namespace apache { namespace thrift { namespace server { |
| 23 | |
| 24 | using namespace apache::thrift; |
| 25 | using namespace apache::thrift::transport; |
| 26 | |
| 27 | TClientInfoConnection::TClientInfoConnection() { |
| 28 | call_[kNameLen - 1] = '\0'; // insure NUL terminator is there |
| 29 | eraseAddr(); |
| 30 | eraseCall(); |
| 31 | } |
| 32 | |
| 33 | void TClientInfoConnection::recordAddr(const sockaddr* addr) { |
| 34 | eraseAddr(); |
| 35 | initTime(); |
| 36 | ncalls_ = 0; |
| 37 | if (addr != NULL) { |
| 38 | if (addr->sa_family == AF_INET) { |
| 39 | memcpy((void*)&addr_.ipv4, (const void *)addr, sizeof(sockaddr_in)); |
| 40 | } |
| 41 | else if (addr->sa_family == AF_INET6) { |
| 42 | memcpy((void*)&addr_.ipv6, (const void *)addr, sizeof(sockaddr_in6)); |
| 43 | } |
| 44 | } |
| 45 | } |
| 46 | |
| 47 | void TClientInfoConnection::eraseAddr() { |
| 48 | addr_.ipv4.sin_family = AF_UNSPEC; |
| 49 | } |
| 50 | |
| 51 | const char* TClientInfoConnection::getAddr(char* buf, int len) const { |
| 52 | switch (addr_.ipv4.sin_family) { |
| 53 | case AF_INET: |
| 54 | return inet_ntop(AF_INET, &addr_.ipv4.sin_addr, buf, len); |
| 55 | case AF_INET6: |
| 56 | return inet_ntop(AF_INET6, &addr_.ipv6.sin6_addr, buf, len); |
| 57 | default: |
| 58 | return NULL; |
| 59 | } |
| 60 | } |
| 61 | |
| 62 | void TClientInfoConnection::recordCall(const char* name) { |
| 63 | strncpy(call_, name, kNameLen - 1); // NUL terminator set in constructor |
| 64 | ncalls_++; |
| 65 | } |
| 66 | |
| 67 | void TClientInfoConnection::eraseCall() { |
| 68 | call_[0] = '\0'; |
| 69 | } |
| 70 | |
| 71 | const char* TClientInfoConnection::getCall() const { |
| 72 | if (call_[0] == '\0') { |
| 73 | return NULL; |
| 74 | } |
| 75 | return call_; |
| 76 | } |
| 77 | |
| 78 | void TClientInfoConnection::getTime(timespec* time) const { |
| 79 | *time = time_; |
| 80 | } |
| 81 | |
| 82 | uint64_t TClientInfoConnection::getNCalls() const { |
| 83 | return ncalls_; |
| 84 | } |
| 85 | |
| 86 | void TClientInfoConnection::initTime() { |
| 87 | clock_gettime(CLOCK_REALTIME, &time_); |
| 88 | } |
| 89 | |
| 90 | |
| 91 | TClientInfoConnection* TClientInfo::getConnection(int fd, bool grow) { |
| 92 | if (fd < 0 || (!grow && fd >= info_.size())) { |
| 93 | return NULL; |
| 94 | } |
| 95 | return &info_[fd]; |
| 96 | } |
| 97 | |
| 98 | size_t TClientInfo::size() const { |
| 99 | return info_.size(); |
| 100 | } |
| 101 | |
| 102 | void* TClientInfoServerHandler::createContext(boost::shared_ptr<TProtocol> input, |
| 103 | boost::shared_ptr<TProtocol> output) { |
| 104 | (void)input; |
| 105 | (void)output; |
| 106 | return (void*) new Connect(&clientInfo_); |
| 107 | } |
| 108 | |
| 109 | void TClientInfoServerHandler::deleteContext(void* connectionContext, |
| 110 | boost::shared_ptr<TProtocol> input, |
| 111 | boost::shared_ptr<TProtocol> output) { |
| 112 | Connect* call = static_cast<Connect*>(connectionContext); |
| 113 | if (call->callInfo_) { |
| 114 | call->callInfo_->eraseCall(); |
| 115 | } |
| 116 | delete call; |
| 117 | } |
| 118 | |
| 119 | void TClientInfoServerHandler::processContext(void* connectionContext, |
| 120 | shared_ptr<TTransport> transport) { |
| 121 | Connect* call = static_cast<Connect*>(connectionContext); |
| 122 | if (call->callInfo_ == NULL) { |
| 123 | if (typeid(*(transport.get())) == typeid(TSocket)) { |
| 124 | TSocket* tsocket = static_cast<TSocket*>(transport.get()); |
| 125 | int fd = tsocket->getSocketFD(); |
| 126 | if (fd < 0) { |
| 127 | return; |
| 128 | } |
| 129 | call->callInfo_ = call->clientInfo_->getConnection(fd, true); |
| 130 | assert(call->callInfo_ != NULL); |
| 131 | socklen_t len; |
| 132 | call->callInfo_->recordAddr(tsocket->getCachedAddress(&len)); |
| 133 | } |
| 134 | } |
| 135 | } |
| 136 | |
| 137 | void TClientInfoServerHandler::getStatsStrings(vector<string>& result) { |
| 138 | result.clear(); |
| 139 | timespec now; |
| 140 | clock_gettime(CLOCK_REALTIME, &now); |
| 141 | |
| 142 | for (int i = 0; i < clientInfo_.size(); ++i) { |
| 143 | TClientInfoConnection* info = clientInfo_.getConnection(i, false); |
| 144 | const char* callStr = info->getCall(); |
| 145 | if (callStr == NULL) { |
| 146 | continue; |
| 147 | } |
| 148 | |
| 149 | char addrBuf[INET6_ADDRSTRLEN]; |
| 150 | const char* addrStr = info->getAddr(addrBuf, sizeof addrBuf); |
| 151 | if (addrStr == NULL) { |
| 152 | // cerr << "no addr!" << endl; |
| 153 | continue; |
| 154 | } |
| 155 | |
| 156 | timespec start; |
David Reiss | 2324871 | 2010-10-06 17:10:08 +0000 | [diff] [blame] | 157 | info->getTime(&start); |
Roger Meier | 71f2d8a | 2015-04-26 17:00:04 +0200 | [diff] [blame] | 158 | double secs = (double)(now.tv_sec - start.tv_sec) + (now.tv_nsec - start.tv_nsec)*0.000000001; |
David Reiss | 2324871 | 2010-10-06 17:10:08 +0000 | [diff] [blame] | 159 | |
| 160 | char buf[256]; |
| 161 | snprintf(buf, sizeof buf, "%d %s %s %.3f %llu", i, addrStr, callStr, secs, |
Roger Meier | 5f9614c | 2010-11-21 16:59:05 +0000 | [diff] [blame] | 162 | (uint64_t)info->getNCalls()); |
David Reiss | 2324871 | 2010-10-06 17:10:08 +0000 | [diff] [blame] | 163 | |
| 164 | result.push_back(buf); |
| 165 | } |
| 166 | } |
| 167 | |
| 168 | void* TClientInfoCallHandler::getContext(const char* fn_name, void* serverContext) { |
| 169 | if (serverContext) { |
| 170 | TClientInfoConnection* callInfo = static_cast<TClientInfoServerHandler::Connect*>(serverContext)->callInfo_; |
| 171 | if (callInfo != NULL) { |
| 172 | callInfo->recordCall(fn_name); |
| 173 | } |
| 174 | } |
| 175 | return NULL; |
| 176 | } |
| 177 | |
| 178 | } } } // namespace apache::thrift::server |