blob: 4304b6cfd6ddeccaa0ee8c9bc5571560dbbab880 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
yangsu@google.comc5aeccd2011-07-17 14:42:08 +00007#include <netdb.h>
8#include <unistd.h>
9#include <errno.h>
10#include <fcntl.h>
11#include "SkSockets.h"
12#include "SkData.h"
13
14SkSocket::SkSocket() {
15 fMaxfd = 0;
16 FD_ZERO(&fMasterSet);
17 fConnected = false;
18 fReady = false;
19 fReadSuspended = false;
20 fWriteSuspended = false;
21 fSockfd = this->createSocket();
yangsu@google.comc5aeccd2011-07-17 14:42:08 +000022}
23
24SkSocket::~SkSocket() {
25 this->closeSocket(fSockfd);
yangsu@google.comef7bdfa2011-08-12 14:27:47 +000026 shutdown(fSockfd, 2); //stop sending/receiving
yangsu@google.comc5aeccd2011-07-17 14:42:08 +000027}
28
29int SkSocket::createSocket() {
30 int sockfd = socket(AF_INET, SOCK_STREAM, 0);
31 if (sockfd < 0) {
yangsu@google.comf3493f02011-08-08 15:12:05 +000032 SkDebugf("ERROR opening socket\n");
33 return -1;
34 }
35 int reuse = 1;
36
37 if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int)) < 0) {
38 SkDebugf("error: %s\n", strerror(errno));
yangsu@google.comc5aeccd2011-07-17 14:42:08 +000039 return -1;
40 }
41#ifdef NONBLOCKING_SOCKETS
42 this->setNonBlocking(sockfd);
43#endif
44 //SkDebugf("Opened fd:%d\n", sockfd);
45 fReady = true;
46 return sockfd;
47}
48
49void SkSocket::closeSocket(int sockfd) {
50 if (!fReady)
51 return;
52
yangsu@google.comc5aeccd2011-07-17 14:42:08 +000053 close(sockfd);
yangsu@google.comf3493f02011-08-08 15:12:05 +000054 //SkDebugf("Closed fd:%d\n", sockfd);
yangsu@google.comc5aeccd2011-07-17 14:42:08 +000055
56 if (FD_ISSET(sockfd, &fMasterSet)) {
57 FD_CLR(sockfd, &fMasterSet);
58 if (sockfd >= fMaxfd) {
59 while (FD_ISSET(fMaxfd, &fMasterSet) == false && fMaxfd > 0)
60 fMaxfd -= 1;
61 }
62 }
yangsu@google.comf3493f02011-08-08 15:12:05 +000063 if (0 == fMaxfd)
yangsu@google.comc5aeccd2011-07-17 14:42:08 +000064 fConnected = false;
yangsu@google.comc5aeccd2011-07-17 14:42:08 +000065}
66
67void SkSocket::onFailedConnection(int sockfd) {
68 this->closeSocket(sockfd);
69}
70
71void SkSocket::setNonBlocking(int sockfd) {
72 int flags = fcntl(sockfd, F_GETFL);
73 fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
74}
75
76void SkSocket::addToMasterSet(int sockfd) {
77 FD_SET(sockfd, &fMasterSet);
78 if (sockfd > fMaxfd)
79 fMaxfd = sockfd;
80}
81
yangsu@google.comf3493f02011-08-08 15:12:05 +000082int SkSocket::readPacket(void (*onRead)(int, const void*, size_t, DataType,
yangsu@google.comc5aeccd2011-07-17 14:42:08 +000083 void*), void* context) {
yangsu@google.comf3493f02011-08-08 15:12:05 +000084 if (!fConnected || !fReady || NULL == onRead || NULL == context
85 || fReadSuspended)
yangsu@google.comc5aeccd2011-07-17 14:42:08 +000086 return -1;
87
88 int totalBytesRead = 0;
89
90 char packet[PACKET_SIZE];
91 for (int i = 0; i <= fMaxfd; ++i) {
92 if (!FD_ISSET (i, &fMasterSet))
93 continue;
94
95 memset(packet, 0, PACKET_SIZE);
96 SkDynamicMemoryWStream stream;
97 int attempts = 0;
98 bool failure = false;
99 int bytesReadInTransfer = 0;
100 int bytesReadInPacket = 0;
101 header h;
102 h.done = false;
103 h.bytes = 0;
104 while (!h.done && fConnected && !failure) {
105 int retval = read(i, packet + bytesReadInPacket,
106 PACKET_SIZE - bytesReadInPacket);
107
108 ++attempts;
109 if (retval < 0) {
110#ifdef NONBLOCKING_SOCKETS
111 if (errno == EWOULDBLOCK || errno == EAGAIN) {
112 if (bytesReadInPacket > 0 || bytesReadInTransfer > 0)
113 continue; //incomplete packet or frame, keep tring
114 else
115 break; //nothing to read
116 }
117#endif
118 //SkDebugf("Read() failed with error: %s\n", strerror(errno));
119 failure = true;
120 break;
121 }
122
123 if (retval == 0) {
124 //SkDebugf("Peer closed connection or connection failed\n");
125 failure = true;
126 break;
127 }
128
129 SkASSERT(retval > 0);
130 bytesReadInPacket += retval;
131 if (bytesReadInPacket < PACKET_SIZE) {
132 //SkDebugf("Read %d/%d\n", bytesReadInPacket, PACKET_SIZE);
133 continue; //incomplete packet, keep trying
134 }
135
136 SkASSERT((bytesReadInPacket == PACKET_SIZE) && !failure);
137 memcpy(&h.done, packet, sizeof(bool));
138 memcpy(&h.bytes, packet + sizeof(bool), sizeof(int));
139 memcpy(&h.type, packet + sizeof(bool) + sizeof(int), sizeof(DataType));
140 if (h.bytes > CONTENT_SIZE || h.bytes <= 0) {
141 //SkDebugf("bad packet\n");
142 failure = true;
143 break;
144 }
yangsu@google.comf3493f02011-08-08 15:12:05 +0000145 //SkDebugf("read packet(done:%d, bytes:%d) from fd:%d in %d tries\n",
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000146 // h.done, h.bytes, fSockfd, attempts);
yangsu@google.comf3493f02011-08-08 15:12:05 +0000147 stream.write(packet + HEADER_SIZE, h.bytes);
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000148 bytesReadInPacket = 0;
149 attempts = 0;
150 bytesReadInTransfer += h.bytes;
151 }
152
153 if (failure) {
yangsu@google.comef7bdfa2011-08-12 14:27:47 +0000154 onRead(i, NULL, 0, h.type, context);
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000155 this->onFailedConnection(i);
156 continue;
157 }
158
159 if (bytesReadInTransfer > 0) {
160 SkData* data = stream.copyToData();
161 SkASSERT(data->size() == bytesReadInTransfer);
yangsu@google.comf3493f02011-08-08 15:12:05 +0000162 onRead(i, data->data(), data->size(), h.type, context);
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000163 data->unref();
164
165 totalBytesRead += bytesReadInTransfer;
166 }
167 }
168 return totalBytesRead;
169}
170
171int SkSocket::writePacket(void* data, size_t size, DataType type) {
172 if (size < 0|| NULL == data || !fConnected || !fReady || fWriteSuspended)
173 return -1;
174
175 int totalBytesWritten = 0;
176 header h;
177 char packet[PACKET_SIZE];
178 for (int i = 0; i <= fMaxfd; ++i) {
179 if (!FD_ISSET (i, &fMasterSet))
180 continue;
181
182 //Don't signal broken pipe
183 setsockopt(i, SOL_SOCKET, SO_NOSIGPIPE, (void*)1, sizeof(int));
184 int bytesWrittenInTransfer = 0;
185 int bytesWrittenInPacket = 0;
186 int attempts = 0;
187 bool failure = false;
188 while (bytesWrittenInTransfer < size && fConnected && !failure) {
189 memset(packet, 0, PACKET_SIZE);
190 h.done = (size - bytesWrittenInTransfer <= CONTENT_SIZE);
191 h.bytes = (h.done) ? size - bytesWrittenInTransfer : CONTENT_SIZE;
192 h.type = type;
193 memcpy(packet, &h.done, sizeof(bool));
194 memcpy(packet + sizeof(bool), &h.bytes, sizeof(int));
195 memcpy(packet + sizeof(bool) + sizeof(int), &h.type, sizeof(DataType));
196 memcpy(packet + HEADER_SIZE, (char*)data + bytesWrittenInTransfer,
197 h.bytes);
198
199 int retval = write(i, packet + bytesWrittenInPacket,
200 PACKET_SIZE - bytesWrittenInPacket);
201 attempts++;
202
203 if (retval < 0) {
204 if (errno == EPIPE) {
205 //SkDebugf("broken pipe, client closed connection");
206 failure = true;
207 break;
208 }
209#ifdef NONBLOCKING_SOCKETS
210 else if (errno == EWOULDBLOCK || errno == EAGAIN) {
211 if (bytesWrittenInPacket > 0 || bytesWrittenInTransfer > 0)
yangsu@google.comf3493f02011-08-08 15:12:05 +0000212 continue; //incomplete packet or frame, keep trying
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000213 else
214 break; //client not available, skip current transfer
215 }
216#endif
217 else {
218 //SkDebugf("write(%d) failed with error:%s\n", i,
219 // strerror(errno));
220 failure = true;
221 break;
222 }
223 }
224
225 bytesWrittenInPacket += retval;
yangsu@google.comf3493f02011-08-08 15:12:05 +0000226 if (bytesWrittenInPacket < PACKET_SIZE)
227 continue; //incomplete packet, keep trying
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000228
229 SkASSERT(bytesWrittenInPacket == PACKET_SIZE);
230 //SkDebugf("wrote to packet(done:%d, bytes:%d) to fd:%d in %d tries\n",
231 // h.done, h.bytes, i, attempts);
232 bytesWrittenInTransfer += h.bytes;
233 bytesWrittenInPacket = 0;
234 attempts = 0;
235 }
236
yangsu@google.comf3493f02011-08-08 15:12:05 +0000237 if (failure)
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000238 this->onFailedConnection(i);
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000239
240 totalBytesWritten += bytesWrittenInTransfer;
241 }
242 return totalBytesWritten;
243}
yangsu@google.comf3493f02011-08-08 15:12:05 +0000244
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000245////////////////////////////////////////////////////////////////////////////////
246SkTCPServer::SkTCPServer(int port) {
247 sockaddr_in serverAddr;
248 serverAddr.sin_family = AF_INET;
249 serverAddr.sin_addr.s_addr = INADDR_ANY;
250 serverAddr.sin_port = htons(port);
251
252 if (bind(fSockfd, (sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) {
yangsu@google.comf3493f02011-08-08 15:12:05 +0000253 SkDebugf("ERROR on binding: %s\n", strerror(errno));
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000254 fReady = false;
255 }
256}
257
258SkTCPServer::~SkTCPServer() {
yangsu@google.comf3493f02011-08-08 15:12:05 +0000259 this->disconnectAll();
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000260}
261
yangsu@google.comf3493f02011-08-08 15:12:05 +0000262int SkTCPServer::acceptConnections() {
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000263 if (!fReady)
264 return -1;
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000265
yangsu@google.comf3493f02011-08-08 15:12:05 +0000266 listen(fSockfd, MAX_WAITING_CLIENTS);
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000267 int newfd;
yangsu@google.comf3493f02011-08-08 15:12:05 +0000268 for (int i = 0; i < MAX_WAITING_CLIENTS; ++i) {
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000269#ifdef NONBLOCKING_SOCKETS
270 fd_set workingSet;
271 FD_ZERO(&workingSet);
272 FD_SET(fSockfd, &workingSet);
yangsu@google.comf3493f02011-08-08 15:12:05 +0000273 timeval timeout;
274 timeout.tv_sec = 0;
275 timeout.tv_usec = 0;
276 int sel = select(fSockfd + 1, &workingSet, NULL, NULL, &timeout);
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000277 if (sel < 0) {
yangsu@google.comf3493f02011-08-08 15:12:05 +0000278 SkDebugf("select() failed with error %s\n", strerror(errno));
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000279 continue;
280 }
281 if (sel == 0) //select() timed out
282 continue;
283#endif
284 sockaddr_in clientAddr;
285 socklen_t clientLen = sizeof(clientAddr);
286 newfd = accept(fSockfd, (struct sockaddr*)&clientAddr, &clientLen);
287 if (newfd< 0) {
yangsu@google.comf3493f02011-08-08 15:12:05 +0000288 SkDebugf("accept() failed with error %s\n", strerror(errno));
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000289 continue;
290 }
yangsu@google.comf3493f02011-08-08 15:12:05 +0000291 SkDebugf("New incoming connection - %d\n", newfd);
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000292 fConnected = true;
293#ifdef NONBLOCKING_SOCKETS
294 this->setNonBlocking(newfd);
295#endif
296 this->addToMasterSet(newfd);
297 }
298 return 0;
299}
300
301
yangsu@google.comf3493f02011-08-08 15:12:05 +0000302int SkTCPServer::disconnectAll() {
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000303 if (!fConnected || !fReady)
304 return -1;
yangsu@google.comf3493f02011-08-08 15:12:05 +0000305 for (int i = 0; i <= fMaxfd; ++i) {
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000306 if (FD_ISSET(i, &fMasterSet))
307 this->closeSocket(i);
308 }
309 fConnected = false;
310 return 0;
311}
312
313////////////////////////////////////////////////////////////////////////////////
314SkTCPClient::SkTCPClient(const char* hostname, int port) {
315 //Add fSockfd since the client will be using it to read/write
316 this->addToMasterSet(fSockfd);
317
318 hostent* server = gethostbyname(hostname);
319 if (server) {
320 fServerAddr.sin_family = AF_INET;
321 memcpy((char*)&fServerAddr.sin_addr.s_addr, (char*)server->h_addr,
322 server->h_length);
323 fServerAddr.sin_port = htons(port);
324 }
325 else {
326 //SkDebugf("ERROR, no such host\n");
327 fReady = false;
328 }
329}
330
yangsu@google.comf3493f02011-08-08 15:12:05 +0000331void SkTCPClient::onFailedConnection(int sockfd) { //cleanup and recreate socket
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000332 SkASSERT(sockfd == fSockfd);
333 this->closeSocket(fSockfd);
334 fSockfd = this->createSocket();
335 //Add fSockfd since the client will be using it to read/write
336 this->addToMasterSet(fSockfd);
337}
338
339int SkTCPClient::connectToServer() {
340 if (!fReady)
341 return -1;
342 if (fConnected)
343 return 0;
344
345 int conn = connect(fSockfd, (sockaddr*)&fServerAddr, sizeof(fServerAddr));
346 if (conn < 0) {
347#ifdef NONBLOCKING_SOCKETS
348 if (errno == EINPROGRESS || errno == EALREADY)
349 return conn;
350#endif
351 if (errno != EISCONN) {
352 //SkDebugf("error: %s\n", strerror(errno));
353 this->onFailedConnection(fSockfd);
354 return conn;
355 }
356 }
357 fConnected = true;
yangsu@google.comf3493f02011-08-08 15:12:05 +0000358 SkDebugf("Succesfully reached server\n");
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000359 return 0;
360}