blob: 3149be6f55e16b69f9f788a19c58f813b9159cd2 [file] [log] [blame]
Brian Silvermanf7bd1c22015-12-24 16:07:11 -08001/*
2 TCPStream.h
3
4 TCPStream class definition. TCPStream provides methods to trasnfer
5 data between peers over a TCP/IP connection.
6
7 ------------------------------------------
8
9 Copyright © 2013 [Vic Hargrave - http://vichargrave.com]
10
11 Licensed under the Apache License, Version 2.0 (the "License");
12 you may not use this file except in compliance with the License.
13 You may obtain a copy of the License at
14
15 http://www.apache.org/licenses/LICENSE-2.0
16
17 Unless required by applicable law or agreed to in writing, software
18 distributed under the License is distributed on an "AS IS" BASIS,
19 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 See the License for the specific language governing permissions and
21 limitations under the License.
22*/
23
24#include "TCPStream.h"
25
26#ifdef _WIN32
27#include <WinSock2.h>
28#else
29#include <arpa/inet.h>
30#include <netinet/tcp.h>
31#include <unistd.h>
32#endif
33
34TCPStream::TCPStream(int sd, struct sockaddr_in* address) : m_sd(sd) {
35 char ip[50];
36#ifdef _WIN32
37 unsigned long size = sizeof(ip) - 1;
38 WSAAddressToString((struct sockaddr*)address, sizeof sockaddr_in, nullptr, ip, &size);
39#else
40 inet_ntop(PF_INET, (struct in_addr*)&(address->sin_addr.s_addr), ip,
41 sizeof(ip) - 1);
42#endif
43 m_peerIP = ip;
44 m_peerPort = ntohs(address->sin_port);
45}
46
47TCPStream::~TCPStream() { close(); }
48
49std::size_t TCPStream::send(const char* buffer, std::size_t len, Error* err) {
50 if (m_sd < 0) {
51 *err = kConnectionClosed;
52 return 0;
53 }
54#ifdef _WIN32
55 WSABUF wsaBuf;
56 wsaBuf.buf = const_cast<char*>(buffer);
57 wsaBuf.len = (ULONG)len;
58 DWORD rv;
59 bool result = true;
60 while (WSASend(m_sd, &wsaBuf, 1, &rv, 0, nullptr, nullptr) == SOCKET_ERROR) {
61 if (WSAGetLastError() != WSAEWOULDBLOCK) {
62 result = false;
63 break;
64 }
65 Sleep(1);
66 }
67 if (!result) {
68 char Buffer[128];
69#ifdef _MSC_VER
70 sprintf_s(Buffer, "Send() failed: WSA error=%d\n", WSAGetLastError());
71#else
72 std::snprintf(Buffer, 128, "Send() failed: WSA error=%d\n", WSAGetLastError());
73#endif
74 OutputDebugStringA(Buffer);
75 *err = kConnectionReset;
76 return 0;
77 }
78#else
79 ssize_t rv = write(m_sd, buffer, len);
80 if (rv < 0) {
81 *err = kConnectionReset;
82 return 0;
83 }
84#endif
85 return static_cast<std::size_t>(rv);
86}
87
88std::size_t TCPStream::receive(char* buffer, std::size_t len, Error* err,
89 int timeout) {
90 if (m_sd < 0) {
91 *err = kConnectionClosed;
92 return 0;
93 }
94#ifdef _WIN32
95 int rv;
96#else
97 ssize_t rv;
98#endif
99 if (timeout <= 0) {
100#ifdef _WIN32
101 rv = recv(m_sd, buffer, len, 0);
102#else
103 rv = read(m_sd, buffer, len);
104#endif
105 }
106 else if (WaitForReadEvent(timeout)) {
107#ifdef _WIN32
108 rv = recv(m_sd, buffer, len, 0);
109#else
110 rv = read(m_sd, buffer, len);
111#endif
112 } else {
113 *err = kConnectionTimedOut;
114 return 0;
115 }
116 if (rv < 0) {
117 *err = kConnectionReset;
118 return 0;
119 }
120 return static_cast<std::size_t>(rv);
121}
122
123void TCPStream::close() {
124 if (m_sd >= 0) {
125#ifdef _WIN32
126 ::shutdown(m_sd, SD_BOTH);
127 closesocket(m_sd);
128#else
129 ::shutdown(m_sd, SHUT_RDWR);
130 ::close(m_sd);
131#endif
132 }
133 m_sd = -1;
134}
135
136llvm::StringRef TCPStream::getPeerIP() const { return m_peerIP; }
137
138int TCPStream::getPeerPort() const { return m_peerPort; }
139
140void TCPStream::setNoDelay() {
141 int optval = 1;
142 setsockopt(m_sd, IPPROTO_TCP, TCP_NODELAY, (char*)&optval, sizeof optval);
143}
144
145bool TCPStream::WaitForReadEvent(int timeout) {
146 fd_set sdset;
147 struct timeval tv;
148
149 tv.tv_sec = timeout;
150 tv.tv_usec = 0;
151 FD_ZERO(&sdset);
152 FD_SET(m_sd, &sdset);
153 if (select(m_sd + 1, &sdset, NULL, NULL, &tv) > 0) {
154 return true;
155 }
156 return false;
157}