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