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
20 #include <thrift/server/TClientInfo.h>
21
22 namespace apache { namespace thrift { namespace server {
23
24 using namespace apache::thrift;
25 using namespace apache::thrift::transport;
26
TClientInfoConnection()27 TClientInfoConnection::TClientInfoConnection() {
28 call_[kNameLen - 1] = '\0'; // insure NUL terminator is there
29 eraseAddr();
30 eraseCall();
31 }
32
recordAddr(const sockaddr * addr)33 void TClientInfoConnection::recordAddr(const sockaddr* addr) {
34 eraseAddr();
35 initTime();
36 ncalls_ = 0;
37 if (addr != nullptr) {
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
eraseAddr()47 void TClientInfoConnection::eraseAddr() {
48 addr_.ipv4.sin_family = AF_UNSPEC;
49 }
50
getAddr(char * buf,int len) const51 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 nullptr;
59 }
60 }
61
recordCall(const char * name)62 void TClientInfoConnection::recordCall(const char* name) {
63 strncpy(call_, name, kNameLen - 1); // NUL terminator set in constructor
64 ncalls_++;
65 }
66
eraseCall()67 void TClientInfoConnection::eraseCall() {
68 call_[0] = '\0';
69 }
70
getCall() const71 const char* TClientInfoConnection::getCall() const {
72 if (call_[0] == '\0') {
73 return nullptr;
74 }
75 return call_;
76 }
77
getTime(timespec * time) const78 void TClientInfoConnection::getTime(timespec* time) const {
79 *time = time_;
80 }
81
getNCalls() const82 uint64_t TClientInfoConnection::getNCalls() const {
83 return ncalls_;
84 }
85
initTime()86 void TClientInfoConnection::initTime() {
87 clock_gettime(CLOCK_REALTIME, &time_);
88 }
89
90
getConnection(int fd,bool grow)91 TClientInfoConnection* TClientInfo::getConnection(int fd, bool grow) {
92 if (fd < 0 || (!grow && fd >= info_.size())) {
93 return nullptr;
94 }
95 return &info_[fd];
96 }
97
size() const98 size_t TClientInfo::size() const {
99 return info_.size();
100 }
101
createContext(boost::shared_ptr<TProtocol> input,boost::shared_ptr<TProtocol> output)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
deleteContext(void * connectionContext,boost::shared_ptr<TProtocol> input,boost::shared_ptr<TProtocol> output)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
processContext(void * connectionContext,shared_ptr<TTransport> transport)119 void TClientInfoServerHandler::processContext(void* connectionContext,
120 shared_ptr<TTransport> transport) {
121 Connect* call = static_cast<Connect*>(connectionContext);
122 if (call->callInfo_ == nullptr) {
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_ != nullptr);
131 socklen_t len;
132 call->callInfo_->recordAddr(tsocket->getCachedAddress(&len));
133 }
134 }
135 }
136
getStatsStrings(vector<string> & result)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 == nullptr) {
146 continue;
147 }
148
149 char addrBuf[INET6_ADDRSTRLEN];
150 const char* addrStr = info->getAddr(addrBuf, sizeof addrBuf);
151 if (addrStr == nullptr) {
152 // cerr << "no addr!" << endl;
153 continue;
154 }
155
156 timespec start;
157 info->getTime(&start);
158 double secs = (double)(now.tv_sec - start.tv_sec) + (now.tv_nsec - start.tv_nsec)*0.000000001;
159
160 char buf[256];
161 snprintf(buf, sizeof buf, "%d %s %s %.3f %llu", i, addrStr, callStr, secs,
162 (uint64_t)info->getNCalls());
163
164 result.push_back(buf);
165 }
166 }
167
getContext(const char * fn_name,void * serverContext)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 != nullptr) {
172 callInfo->recordCall(fn_name);
173 }
174 }
175 return nullptr;
176 }
177
178 } } } // namespace apache::thrift::server
179