Loading...
Searching...
No Matches
tcp_socket.cpp
Go to the documentation of this file.
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
21
22#include <arpa/inet.h>
23#include <errno.h>
24#include <glog/logging.h>
25#include <string.h>
26#include <sys/ioctl.h>
27#include <unistd.h>
28
29#include <thread>
30
31namespace resdb {
32
33namespace {
34
35int RecvInternal(int fd, void* buf, size_t len) {
36 size_t pos = 0;
37 while (len > 0) {
38 int ret = recv(fd, (char*)buf + pos, len, 0);
39 if (ret <= 0) {
40 // LOG(ERROR) << "recv data fail, fd =" << fd << " error " <<
41 // strerror(errno)
42 // << " ret:" << ret;
43 return ret;
44 }
45 pos += ret;
46 len -= ret;
47 }
48 return pos;
49}
50
51int SendInternal(int fd, const void* buf, size_t len) {
52 if (fd < 0) {
53 return -2;
54 }
55 size_t pos = 0;
56 while (pos < len) {
57 int ret = send(fd, (char*)buf + pos, len - pos, 0);
58 if (ret < 0) {
59 LOG(ERROR) << "send data fail, fd =" << fd << " error "
60 << strerror(errno);
61 return -1;
62 }
63 pos += ret;
64 }
65 return pos;
66}
67
68} // namespace
69
70TcpSocket::TcpSocket() : socket_fd_(-1) { InitSocket(); }
71
72TcpSocket::TcpSocket(int socket_fd) : socket_fd_(socket_fd) {}
73
75
77 Close();
78 InitSocket();
79}
80
82 if (socket_fd_ >= 0) {
83 close(socket_fd_);
84 socket_fd_ = -1;
85 }
86}
87
88int TcpSocket::InitSocket() {
89 if ((socket_fd_ = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
90 LOG(ERROR) << "create TcpSocket error: " << strerror(errno)
91 << " (errno: " << errno << ")";
92 return -1;
93 }
94 return 0;
95}
96
97int TcpSocket::Listen(const std::string& ip, int port) {
98 int on = 1;
99 if (setsockopt(socket_fd_, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) != 0) {
100 LOG(ERROR) << "set TcpSocket opt fail, error" << strerror(errno);
101 return -1;
102 }
103
104 struct sockaddr_in servaddr;
105 memset(&servaddr, 0, sizeof(servaddr));
106 servaddr.sin_family = AF_INET;
107 servaddr.sin_addr.s_addr = inet_addr(ip.data());
108 servaddr.sin_port = htons(port);
109
110 if (bind(socket_fd_, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1) {
111 LOG(ERROR) << "bind TcpSocket error: " << strerror(errno)
112 << "(errno: " << errno << ")";
113 return -1;
114 }
115
116 if (listen(socket_fd_, 10) == -1) {
117 LOG(ERROR) << "listen TcpSocket error: " << strerror(errno)
118 << "(errno: " << errno << ")";
119 return -1;
120 }
121 if (port == 0) {
122 struct sockaddr_in localaddr;
123 socklen_t len = sizeof(localaddr);
124 int ret = getsockname(socket_fd_, (struct sockaddr*)&localaddr, &len);
125 if (ret != 0) {
126 LOG(ERROR) << "get binding port fail:" << strerror(errno);
127 } else {
128 binding_port_ = ntohs(localaddr.sin_port);
129 }
130 } else {
131 binding_port_ = port;
132 }
133 return 0;
134}
135
136int TcpSocket::GetBindingPort() { return binding_port_; }
137
138std::unique_ptr<Socket> TcpSocket::Accept() {
139 int conn_fd = 0;
140 if ((conn_fd = accept(socket_fd_, (struct sockaddr*)NULL, NULL)) == -1) {
141 // LOG(ERROR) << "accept:" << socket_fd_
142 // << " TcpSocket error: " << strerror(errno) << "(errno: " <<
143 // errno
144 // << ")" << std::this_thread::get_id();
145 return nullptr;
146 }
147 return std::make_unique<TcpSocket>(conn_fd);
148}
149
150int TcpSocket::Connect(const std::string& ip, int port) {
151 if (socket_fd_ < 0) {
152 LOG(ERROR) << "socket fd invalid:" << socket_fd_;
153 return -1;
154 }
155 struct sockaddr_in servaddr;
156 memset(&servaddr, 0, sizeof(servaddr));
157 servaddr.sin_family = AF_INET;
158 servaddr.sin_addr.s_addr = inet_addr(ip.data());
159 servaddr.sin_port = htons(port);
160
161 if (connect(socket_fd_, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) {
162 LOG(ERROR) << "fd:" << socket_fd_ << " connect ip:" << ip
163 << " port:" << port << " error: " << strerror(errno)
164 << "(errno: " << errno << ")";
165 return -1;
166 }
167 // LOG(ERROR) << "connect to:" << ip << " " << port;
168
169 return 0;
170}
171
172int TcpSocket::SetAsync(bool is_open) {
173 unsigned long ul = is_open;
174 return ioctl(socket_fd_, FIONBIO, (unsigned long*)&ul);
175}
176
177int TcpSocket::Send(const std::string& data) {
178 size_t data_size = data.size();
179 size_t send_ret = SendInternal(socket_fd_, &data_size, sizeof(data_size));
180 if (send_ret != sizeof(data_size)) {
181 if (static_cast<int>(send_ret) == -1) {
182 LOG(ERROR) << "send data error: " << strerror(errno)
183 << "(errno: " << errno << ")";
184 return -1;
185 }
186 return -2;
187 }
188
189 send_ret = SendInternal(socket_fd_, data.c_str(), data_size);
190 if (send_ret != data_size) {
191 if (static_cast<int>(send_ret) == -1) {
192 LOG(ERROR) << "send data not done: " << strerror(errno)
193 << "(errno: " << errno << ")";
194 return -1;
195 } else {
196 return -2;
197 }
198 }
199 return 0;
200}
201
202int TcpSocket::Recv(void** buf, size_t* len) {
203 int ret = RecvInternal(socket_fd_, len, sizeof(size_t));
204 if (ret <= 0) {
205 return ret;
206 }
207 *buf = malloc(*len);
208 ret = RecvInternal(socket_fd_, *buf, *len);
209 if (ret <= 0) {
210 return ret;
211 }
212 return ret;
213}
214
215void TcpSocket::SetRecvTimeout(int64_t microseconds) {
216 if (socket_fd_ < 0) {
217 return;
218 }
219 struct timeval timeout = {microseconds / 1000000,
220 static_cast<int>(microseconds % 1000000)};
221 if (setsockopt(socket_fd_, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout,
222 sizeof(struct timeval)) != 0) {
223 LOG(ERROR) << "set recv timeout:" << microseconds
224 << " failed:" << strerror(errno);
225 }
226}
227
228void TcpSocket::SetSendTimeout(int64_t microseconds) {
229 struct timeval timeout = {microseconds / 1000000,
230 static_cast<int>(microseconds % 1000000)};
231 if (setsockopt(socket_fd_, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout,
232 sizeof(struct timeval)) != 0) {
233 LOG(ERROR) << "set second timeout failed:" << strerror(errno);
234 }
235}
236
237} // namespace resdb
std::string data
void Close() override
int Connect(const std::string &ip, int port) override
void SetRecvTimeout(int64_t microseconds) override
int Send(const std::string &data) override
int Recv(void **buf, size_t *len) override
int GetBindingPort() override
void ReInit() override
void SetSendTimeout(int64_t microseconds) override
std::unique_ptr< Socket > Accept() override
int Listen(const std::string &ip, int port) override
int SetAsync(bool is_open=true) override