1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <https/BaseConnection.h>
18 
19 #include <https/SafeCallbackable.h>
20 #include <https/PlainSocket.h>
21 
BaseConnection(std::shared_ptr<RunLoop> runLoop,int sock)22 BaseConnection::BaseConnection(std::shared_ptr<RunLoop> runLoop, int sock)
23     : mRunLoop(runLoop),
24       mSocket(std::make_unique<PlainSocket>(mRunLoop, sock)),
25       mInBufferLen(0),
26       mSendPending(false) {
27 }
28 
run()29 void BaseConnection::run() {
30     receiveClientRequest();
31 }
32 
receiveClientRequest()33 void BaseConnection::receiveClientRequest() {
34     mSocket->postRecv(makeSafeCallback(this, &BaseConnection::onClientRequest));
35 }
36 
onClientRequest()37 void BaseConnection::onClientRequest() {
38     static constexpr size_t kMaxChunkSize = 8192;
39 
40     mInBuffer.resize(mInBufferLen + kMaxChunkSize);
41 
42     ssize_t n;
43     do {
44         n = mSocket->recv(&mInBuffer[mInBufferLen], kMaxChunkSize);
45     } while (n < 0 && errno == EINTR);
46 
47     if (n <= 0) {
48         onDisconnect((n < 0) ? -errno : 0);
49         return;
50     }
51 
52     mInBufferLen += static_cast<size_t>(n);
53 
54     while (mInBufferLen > 0) {
55         n = processClientRequest(mInBuffer.data(), mInBufferLen);
56 
57         if (n <= 0) {
58             break;
59         }
60 
61         mInBuffer.erase(mInBuffer.begin(), mInBuffer.begin() + n);
62         mInBufferLen -= n;
63     }
64 
65     if (n <= 0 && n != -EAGAIN && n != EWOULDBLOCK) {
66         onDisconnect(n);
67         return;
68     }
69 
70     receiveClientRequest();
71 }
72 
send(const void * _data,size_t size)73 void BaseConnection::send(const void *_data, size_t size) {
74     const uint8_t *data = static_cast<const uint8_t *>(_data);
75     std::copy(data, data + size, std::back_inserter(mOutBuffer));
76 
77     if (!mSendPending) {
78         mSendPending = true;
79         mSocket->postSend(
80                 makeSafeCallback(this, &BaseConnection::sendOutputData));
81     }
82 }
83 
sendOutputData()84 void BaseConnection::sendOutputData() {
85     mSendPending = false;
86 
87     const size_t size = mOutBuffer.size();
88     size_t offset = 0;
89 
90     while (offset < size) {
91         ssize_t n = mSocket->send(mOutBuffer.data() + offset, size - offset);
92 
93         if (n < 0) {
94             if (errno == EINTR) {
95                 continue;
96             }
97 
98             assert(!"Should not be here");
99         } else if (n == 0) {
100             // The remote seems gone, clear the output buffer and disconnect.
101             offset = size;
102             break;
103         }
104 
105         offset += static_cast<size_t>(n);
106     }
107 
108     mOutBuffer.erase(mOutBuffer.begin(), mOutBuffer.begin() + offset);
109 
110     if (!mOutBuffer.empty()) {
111         mSendPending = true;
112 
113         mSocket->postSend(
114                 makeSafeCallback(this, &BaseConnection::sendOutputData));
115         return;
116     }
117 }
118 
fd() const119 int BaseConnection::fd() const {
120     return mSocket->fd();
121 }
122 
123