| /* | 
 |  * Licensed to the Apache Software Foundation (ASF) under one | 
 |  * or more contributor license agreements. See the NOTICE file | 
 |  * distributed with this work for additional information | 
 |  * regarding copyright ownership. The ASF licenses this file | 
 |  * to you under the Apache License, Version 2.0 (the | 
 |  * "License"); you may not use this file except in compliance | 
 |  * with the License. You may obtain a copy of the License at | 
 |  * | 
 |  *   http://www.apache.org/licenses/LICENSE-2.0 | 
 |  * | 
 |  * Unless required by applicable law or agreed to in writing, | 
 |  * software distributed under the License is distributed on an | 
 |  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | 
 |  * KIND, either express or implied. See the License for the | 
 |  * specific language governing permissions and limitations | 
 |  * under the License. | 
 |  */ | 
 |  | 
 | #include <server/TClientInfo.h> | 
 |  | 
 | namespace apache { namespace thrift { namespace server { | 
 |  | 
 | using namespace apache::thrift; | 
 | using namespace apache::thrift::transport; | 
 |  | 
 | TClientInfoConnection::TClientInfoConnection() { | 
 |   call_[kNameLen - 1] = '\0';    // insure NUL terminator is there | 
 |   eraseAddr(); | 
 |   eraseCall(); | 
 | } | 
 |  | 
 | void TClientInfoConnection::recordAddr(const sockaddr* addr) { | 
 |   eraseAddr(); | 
 |   initTime(); | 
 |   ncalls_ = 0; | 
 |   if (addr != NULL) { | 
 |     if (addr->sa_family == AF_INET) { | 
 |       memcpy((void*)&addr_.ipv4, (const void *)addr, sizeof(sockaddr_in)); | 
 |     } | 
 |     else if (addr->sa_family == AF_INET6) { | 
 |       memcpy((void*)&addr_.ipv6, (const void *)addr, sizeof(sockaddr_in6)); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | void TClientInfoConnection::eraseAddr() { | 
 |   addr_.ipv4.sin_family = AF_UNSPEC; | 
 | } | 
 |  | 
 | const char* TClientInfoConnection::getAddr(char* buf, int len) const { | 
 |   switch (addr_.ipv4.sin_family) { | 
 |   case AF_INET: | 
 |     return inet_ntop(AF_INET, &addr_.ipv4.sin_addr, buf, len); | 
 |   case AF_INET6: | 
 |     return inet_ntop(AF_INET6, &addr_.ipv6.sin6_addr, buf, len); | 
 |   default: | 
 |     return NULL; | 
 |   } | 
 | } | 
 |  | 
 | void TClientInfoConnection::recordCall(const char* name) { | 
 |   strncpy(call_, name, kNameLen - 1);   // NUL terminator set in constructor | 
 |   ncalls_++; | 
 | } | 
 |  | 
 | void TClientInfoConnection::eraseCall() { | 
 |   call_[0] = '\0'; | 
 | } | 
 |  | 
 | const char* TClientInfoConnection::getCall() const { | 
 |   if (call_[0] == '\0') { | 
 |       return NULL; | 
 |   } | 
 |   return call_; | 
 | } | 
 |  | 
 | void TClientInfoConnection::getTime(timespec* time) const { | 
 |   *time = time_; | 
 | } | 
 |  | 
 | uint64_t TClientInfoConnection::getNCalls() const { | 
 |   return ncalls_; | 
 | } | 
 |  | 
 | void TClientInfoConnection::initTime() { | 
 |   clock_gettime(CLOCK_REALTIME, &time_); | 
 | } | 
 |  | 
 |  | 
 | TClientInfoConnection* TClientInfo::getConnection(int fd, bool grow) { | 
 |   if (fd < 0 || (!grow && fd >= info_.size())) { | 
 |     return NULL; | 
 |   } | 
 |   return &info_[fd]; | 
 | } | 
 |  | 
 | size_t TClientInfo::size() const { | 
 |     return info_.size(); | 
 | } | 
 |  | 
 | void* TClientInfoServerHandler::createContext(boost::shared_ptr<TProtocol> input, | 
 |                                               boost::shared_ptr<TProtocol> output) { | 
 |   (void)input; | 
 |   (void)output; | 
 |   return (void*) new Connect(&clientInfo_); | 
 | } | 
 |  | 
 | void TClientInfoServerHandler::deleteContext(void* connectionContext, | 
 |                                              boost::shared_ptr<TProtocol> input, | 
 |                                              boost::shared_ptr<TProtocol> output) { | 
 |   Connect* call = static_cast<Connect*>(connectionContext); | 
 |   if (call->callInfo_) { | 
 |     call->callInfo_->eraseCall(); | 
 |   } | 
 |   delete call; | 
 | } | 
 |  | 
 | void TClientInfoServerHandler::processContext(void* connectionContext, | 
 |                                               shared_ptr<TTransport> transport) { | 
 |   Connect* call = static_cast<Connect*>(connectionContext); | 
 |   if (call->callInfo_ == NULL) { | 
 |     if (typeid(*(transport.get())) == typeid(TSocket)) { | 
 |       TSocket* tsocket = static_cast<TSocket*>(transport.get()); | 
 |       int fd = tsocket->getSocketFD(); | 
 |       if (fd < 0) { | 
 |         return; | 
 |       } | 
 |       call->callInfo_ = call->clientInfo_->getConnection(fd, true); | 
 |       assert(call->callInfo_ != NULL); | 
 |       socklen_t len; | 
 |         call->callInfo_->recordAddr(tsocket->getCachedAddress(&len)); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | void TClientInfoServerHandler::getStatsStrings(vector<string>& result) { | 
 |   result.clear(); | 
 |   timespec now; | 
 |   clock_gettime(CLOCK_REALTIME, &now); | 
 |  | 
 |   for (int i = 0; i < clientInfo_.size(); ++i) { | 
 |     TClientInfoConnection* info = clientInfo_.getConnection(i, false); | 
 |     const char* callStr = info->getCall(); | 
 |     if (callStr == NULL) { | 
 |       continue; | 
 |     } | 
 |  | 
 |     char addrBuf[INET6_ADDRSTRLEN]; | 
 |     const char* addrStr = info->getAddr(addrBuf, sizeof addrBuf); | 
 |     if (addrStr == NULL) { | 
 |       // cerr << "no addr!" << endl; | 
 |       continue; | 
 |     } | 
 |  | 
 |     timespec start; | 
 |     double secs = 0.0; | 
 |     info->getTime(&start); | 
 |     secs = (double)(now.tv_sec - start.tv_sec) + (now.tv_nsec - start.tv_nsec)*0.000000001; | 
 |  | 
 |     char buf[256]; | 
 |     snprintf(buf, sizeof buf, "%d %s %s %.3f %llu", i, addrStr, callStr, secs, | 
 |              (unsigned long long)info->getNCalls()); | 
 |                 | 
 |     result.push_back(buf); | 
 |   } | 
 | } | 
 |  | 
 | void* TClientInfoCallHandler::getContext(const char* fn_name, void* serverContext) { | 
 |   if (serverContext) { | 
 |     TClientInfoConnection* callInfo =  static_cast<TClientInfoServerHandler::Connect*>(serverContext)->callInfo_; | 
 |     if (callInfo != NULL) { | 
 |       callInfo->recordCall(fn_name); | 
 |     } | 
 |   } | 
 |   return NULL; | 
 | } | 
 |  | 
 | } } } // namespace apache::thrift::server |