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, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 #include "server_connection.h"
20 
21 #include "ats_fcgi_client.h"
22 #include "ats_fastcgi.h"
23 using namespace ats_plugin;
InterceptIOChannel()24 InterceptIOChannel::InterceptIOChannel() : vio(nullptr), iobuf(nullptr), reader(nullptr), total_bytes_written(0), readEnable(false)
25 {
26 }
~InterceptIOChannel()27 InterceptIOChannel::~InterceptIOChannel()
28 {
29   if (this->reader) {
30     TSIOBufferReaderFree(this->reader);
31   }
32 
33   if (this->iobuf) {
34     TSIOBufferDestroy(this->iobuf);
35   }
36   vio                 = nullptr;
37   total_bytes_written = 0;
38 }
39 
40 void
read(TSVConn vc,TSCont contp)41 InterceptIOChannel::read(TSVConn vc, TSCont contp)
42 {
43   if (TSVConnClosedGet(vc)) {
44     TSError("[InterceptIOChannel:%s] Connection Closed...", __FUNCTION__);
45     return;
46   }
47   if (!this->iobuf) {
48     this->iobuf  = TSIOBufferCreate();
49     this->reader = TSIOBufferReaderAlloc(this->iobuf);
50     this->vio    = TSVConnRead(vc, contp, this->iobuf, INT64_MAX);
51     if (this->vio == nullptr) {
52       TSError("[InterceptIOChannel:%s] ERROR While reading from server", __FUNCTION__);
53       return;
54     }
55     TSDebug(PLUGIN_NAME, "[InterceptIOChannel:%s] ReadIO.vio :%p ", __FUNCTION__, this->vio);
56   }
57 }
58 
59 void
write(TSVConn vc,TSCont contp)60 InterceptIOChannel::write(TSVConn vc, TSCont contp)
61 {
62   TSReleaseAssert(this->vio == nullptr);
63   TSReleaseAssert((this->iobuf = TSIOBufferCreate()));
64   TSReleaseAssert((this->reader = TSIOBufferReaderAlloc(this->iobuf)));
65   if (TSVConnClosedGet(contp)) {
66     TSError("[%s] Connection Closed...", __FUNCTION__);
67     return;
68   }
69   this->vio = TSVConnWrite(vc, contp, this->reader, INT64_MAX);
70 }
71 
72 void
phpWrite(TSVConn vc,TSCont contp,unsigned char * buf,int data_size,bool endflag)73 InterceptIOChannel::phpWrite(TSVConn vc, TSCont contp, unsigned char *buf, int data_size, bool endflag)
74 {
75   if (TSVConnClosedGet(vc)) {
76     TSError("[InterceptIOChannel:%s] Connection Closed...", __FUNCTION__);
77     return;
78   }
79 
80   if (!this->iobuf) {
81     this->iobuf  = TSIOBufferCreate();
82     this->reader = TSIOBufferReaderAlloc(this->iobuf);
83     this->vio    = TSVConnWrite(vc, contp, this->reader, INT64_MAX);
84     if (this->vio == nullptr) {
85       TSError("[InterceptIOChannel:%s] Error TSVIO returns null. ", __FUNCTION__);
86       return;
87     }
88   }
89 
90   int num_bytes_written = TSIOBufferWrite(this->iobuf, (const void *)buf, data_size);
91   if (num_bytes_written != data_size) {
92     TSError("[InterceptIOChannel:%s] Error while writing to buffer! Attempted %d bytes but only "
93             "wrote %d bytes",
94             PLUGIN_NAME, data_size, num_bytes_written);
95     return;
96   }
97 
98   total_bytes_written += data_size;
99   if (!endflag) {
100     TSMutexLock(TSVIOMutexGet(vio));
101     TSVIOReenable(this->vio);
102     TSMutexUnlock(TSVIOMutexGet(vio));
103     return;
104   }
105 
106   this->readEnable = true;
107   TSDebug(PLUGIN_NAME, "[%s] Done: %ld \tnBytes: %ld", __FUNCTION__, TSVIONDoneGet(this->vio), TSVIONBytesGet(this->vio));
108 }
109 
ServerConnection(Server * server,TSEventFunc funcp)110 ServerConnection::ServerConnection(Server *server, TSEventFunc funcp)
111   : vc_(nullptr),
112     _fcgiRequest(nullptr),
113     _state(INITIATED),
114     _server(server),
115     _funcp(funcp),
116     _contp(nullptr),
117     _sConnInfo(nullptr),
118     _requestId(0),
119     _max_requests(0),
120     _req_count(0)
121 {
122   ats_plugin::FcgiPluginConfig *gConfig = InterceptGlobal::plugin_data->getGlobalConfigObj();
123   _max_requests                         = gConfig->getMaxReqLength();
124 }
125 
~ServerConnection()126 ServerConnection::~ServerConnection()
127 {
128   TSDebug(PLUGIN_NAME, "Destroying server Connection Obj.ServerConn: %p ,request_id: %d,max_requests: %d, req_count: %d ", this,
129           _requestId, _max_requests, _req_count);
130 
131   if (vc_) {
132     TSVConnClose(vc_);
133     vc_ = nullptr;
134   }
135   // XXX(oschaaf): check commmented line below.
136   // readio.vio = writeio.vio = nullptr;
137   _requestId    = 0;
138   _max_requests = 0;
139   _req_count    = 0;
140   TSContDestroy(_contp);
141   _contp = nullptr;
142   if (_fcgiRequest != nullptr)
143     delete _fcgiRequest;
144   delete _sConnInfo;
145 }
146 
147 void
createFCGIClient(ServerIntercept * intercept)148 ServerConnection::createFCGIClient(ServerIntercept *intercept)
149 {
150   if (_state == READY || _state == COMPLETE) {
151     Transaction &transaction = utils::internal::getTransaction(intercept->_txn);
152     transaction.addPlugin(intercept);
153     transaction.resume();
154     _fcgiRequest = new FCGIClientRequest(_requestId, intercept->_txn);
155     _state       = INUSE;
156     _req_count++;
157   }
158 }
159 
160 void
releaseFCGIClient()161 ServerConnection::releaseFCGIClient()
162 {
163   if (_state == COMPLETE) {
164     TSDebug(PLUGIN_NAME,
165             "[ServerConnection:%s] Release FCGI resource of ServerConn: %p ,request_id: %d,max_requests: %d, req_count: %d ",
166             __FUNCTION__, this, _requestId, _max_requests, _req_count);
167     delete _fcgiRequest;
168     _fcgiRequest = nullptr;
169     _state       = READY;
170   }
171 }
172 
173 void
createConnection()174 ServerConnection::createConnection()
175 {
176   struct sockaddr_in ip_addr;
177   unsigned short int a, b, c, d, p;
178   char *arr  = InterceptGlobal::plugin_data->getGlobalConfigObj()->getServerIp();
179   char *port = InterceptGlobal::plugin_data->getGlobalConfigObj()->getServerPort();
180   sscanf(arr, "%hu.%hu.%hu.%hu", &a, &b, &c, &d);
181   sscanf(port, "%hu", &p);
182   int new_ip = (a << 24) | (b << 16) | (c << 8) | (d);
183   memset(&ip_addr, 0, sizeof(ip_addr));
184   ip_addr.sin_family      = AF_INET;
185   ip_addr.sin_addr.s_addr = htonl(new_ip); /* Should be in network byte order */
186   ip_addr.sin_port        = htons(p);      // server_port;
187 
188   // contp is a global netconnect handler  which will be used to connect with
189   // php server
190   _contp     = TSContCreate(_funcp, TSMutexCreate());
191   _sConnInfo = new ServerConnectionInfo(_server, this);
192   TSContDataSet(_contp, _sConnInfo);
193   // TODO: Need to handle return value of NetConnect
194   TSNetConnect(_contp, (struct sockaddr const *)&ip_addr);
195 }
196