1 /*
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 */
7 #include <netdb.h>
8 #include <unistd.h>
9 #include <errno.h>
10 #include <fcntl.h>
11 #include "experimental/Networking/SkSockets.h"
12 #include "include/core/SkData.h"
13
SkSocket()14 SkSocket::SkSocket() {
15 fMaxfd = 0;
16 FD_ZERO(&fMasterSet);
17 fConnected = false;
18 fReady = false;
19 fReadSuspended = false;
20 fWriteSuspended = false;
21 fSockfd = this->createSocket();
22 }
23
~SkSocket()24 SkSocket::~SkSocket() {
25 this->closeSocket(fSockfd);
26 shutdown(fSockfd, 2); //stop sending/receiving
27 }
28
createSocket()29 int SkSocket::createSocket() {
30 int sockfd = socket(AF_INET, SOCK_STREAM, 0);
31 if (sockfd < 0) {
32 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));
39 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
closeSocket(int sockfd)49 void SkSocket::closeSocket(int sockfd) {
50 if (!fReady)
51 return;
52
53 close(sockfd);
54 //SkDebugf("Closed fd:%d\n", sockfd);
55
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 }
63 if (0 == fMaxfd)
64 fConnected = false;
65 }
66
onFailedConnection(int sockfd)67 void SkSocket::onFailedConnection(int sockfd) {
68 this->closeSocket(sockfd);
69 }
70
setNonBlocking(int sockfd)71 void SkSocket::setNonBlocking(int sockfd) {
72 int flags = fcntl(sockfd, F_GETFL);
73 fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
74 }
75
addToMasterSet(int sockfd)76 void SkSocket::addToMasterSet(int sockfd) {
77 FD_SET(sockfd, &fMasterSet);
78 if (sockfd > fMaxfd)
79 fMaxfd = sockfd;
80 }
81
readPacket(void (* onRead)(int,const void *,size_t,DataType,void *),void * context)82 int SkSocket::readPacket(void (*onRead)(int, const void*, size_t, DataType,
83 void*), void* context) {
84 if (!fConnected || !fReady || NULL == onRead || NULL == context
85 || fReadSuspended)
86 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 }
145 //SkDebugf("read packet(done:%d, bytes:%d) from fd:%d in %d tries\n",
146 // h.done, h.bytes, fSockfd, attempts);
147 stream.write(packet + HEADER_SIZE, h.bytes);
148 bytesReadInPacket = 0;
149 attempts = 0;
150 bytesReadInTransfer += h.bytes;
151 }
152
153 if (failure) {
154 onRead(i, NULL, 0, h.type, context);
155 this->onFailedConnection(i);
156 continue;
157 }
158
159 if (bytesReadInTransfer > 0) {
160 SkData* data = stream.copyToData();
161 SkASSERT(data->size() == bytesReadInTransfer);
162 onRead(i, data->data(), data->size(), h.type, context);
163 data->unref();
164
165 totalBytesRead += bytesReadInTransfer;
166 }
167 }
168 return totalBytesRead;
169 }
170
writePacket(void * data,size_t size,DataType type)171 int 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 int bytesWrittenInTransfer = 0;
183 int bytesWrittenInPacket = 0;
184 int attempts = 0;
185 bool failure = false;
186 while (bytesWrittenInTransfer < size && fConnected && !failure) {
187 memset(packet, 0, PACKET_SIZE);
188 h.done = (size - bytesWrittenInTransfer <= CONTENT_SIZE);
189 h.bytes = (h.done) ? size - bytesWrittenInTransfer : CONTENT_SIZE;
190 h.type = type;
191 memcpy(packet, &h.done, sizeof(bool));
192 memcpy(packet + sizeof(bool), &h.bytes, sizeof(int));
193 memcpy(packet + sizeof(bool) + sizeof(int), &h.type, sizeof(DataType));
194 memcpy(packet + HEADER_SIZE, (char*)data + bytesWrittenInTransfer,
195 h.bytes);
196
197 int retval = write(i, packet + bytesWrittenInPacket,
198 PACKET_SIZE - bytesWrittenInPacket);
199 attempts++;
200
201 if (retval < 0) {
202 if (errno == EPIPE) {
203 //SkDebugf("broken pipe, client closed connection");
204 failure = true;
205 break;
206 }
207 #ifdef NONBLOCKING_SOCKETS
208 else if (errno == EWOULDBLOCK || errno == EAGAIN) {
209 if (bytesWrittenInPacket > 0 || bytesWrittenInTransfer > 0)
210 continue; //incomplete packet or frame, keep trying
211 else
212 break; //client not available, skip current transfer
213 }
214 #endif
215 else {
216 //SkDebugf("write(%d) failed with error:%s\n", i,
217 // strerror(errno));
218 failure = true;
219 break;
220 }
221 }
222
223 bytesWrittenInPacket += retval;
224 if (bytesWrittenInPacket < PACKET_SIZE)
225 continue; //incomplete packet, keep trying
226
227 SkASSERT(bytesWrittenInPacket == PACKET_SIZE);
228 //SkDebugf("wrote to packet(done:%d, bytes:%d) to fd:%d in %d tries\n",
229 // h.done, h.bytes, i, attempts);
230 bytesWrittenInTransfer += h.bytes;
231 bytesWrittenInPacket = 0;
232 attempts = 0;
233 }
234
235 if (failure)
236 this->onFailedConnection(i);
237
238 totalBytesWritten += bytesWrittenInTransfer;
239 }
240 return totalBytesWritten;
241 }
242
243 ////////////////////////////////////////////////////////////////////////////////
SkTCPServer(int port)244 SkTCPServer::SkTCPServer(int port) {
245 sockaddr_in serverAddr;
246 serverAddr.sin_family = AF_INET;
247 serverAddr.sin_addr.s_addr = INADDR_ANY;
248 serverAddr.sin_port = htons(port);
249
250 if (bind(fSockfd, (sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) {
251 SkDebugf("ERROR on binding: %s\n", strerror(errno));
252 fReady = false;
253 }
254 }
255
~SkTCPServer()256 SkTCPServer::~SkTCPServer() {
257 this->disconnectAll();
258 }
259
acceptConnections()260 int SkTCPServer::acceptConnections() {
261 if (!fReady)
262 return -1;
263
264 listen(fSockfd, MAX_WAITING_CLIENTS);
265 int newfd;
266 for (int i = 0; i < MAX_WAITING_CLIENTS; ++i) {
267 #ifdef NONBLOCKING_SOCKETS
268 fd_set workingSet;
269 FD_ZERO(&workingSet);
270 FD_SET(fSockfd, &workingSet);
271 timeval timeout;
272 timeout.tv_sec = 0;
273 timeout.tv_usec = 0;
274 int sel = select(fSockfd + 1, &workingSet, NULL, NULL, &timeout);
275 if (sel < 0) {
276 SkDebugf("select() failed with error %s\n", strerror(errno));
277 continue;
278 }
279 if (sel == 0) //select() timed out
280 continue;
281 #endif
282 sockaddr_in clientAddr;
283 socklen_t clientLen = sizeof(clientAddr);
284 newfd = accept(fSockfd, (struct sockaddr*)&clientAddr, &clientLen);
285 if (newfd< 0) {
286 SkDebugf("accept() failed with error %s\n", strerror(errno));
287 continue;
288 }
289 SkDebugf("New incoming connection - %d\n", newfd);
290 fConnected = true;
291 #ifdef NONBLOCKING_SOCKETS
292 this->setNonBlocking(newfd);
293 #endif
294 this->addToMasterSet(newfd);
295 }
296 return 0;
297 }
298
299
disconnectAll()300 int SkTCPServer::disconnectAll() {
301 if (!fConnected || !fReady)
302 return -1;
303 for (int i = 0; i <= fMaxfd; ++i) {
304 if (FD_ISSET(i, &fMasterSet))
305 this->closeSocket(i);
306 }
307 fConnected = false;
308 return 0;
309 }
310
311 ////////////////////////////////////////////////////////////////////////////////
SkTCPClient(const char * hostname,int port)312 SkTCPClient::SkTCPClient(const char* hostname, int port) {
313 //Add fSockfd since the client will be using it to read/write
314 this->addToMasterSet(fSockfd);
315
316 hostent* server = gethostbyname(hostname);
317 if (server) {
318 fServerAddr.sin_family = AF_INET;
319 memcpy((char*)&fServerAddr.sin_addr.s_addr, (char*)server->h_addr,
320 server->h_length);
321 fServerAddr.sin_port = htons(port);
322 }
323 else {
324 //SkDebugf("ERROR, no such host\n");
325 fReady = false;
326 }
327 }
328
onFailedConnection(int sockfd)329 void SkTCPClient::onFailedConnection(int sockfd) { //cleanup and recreate socket
330 SkASSERT(sockfd == fSockfd);
331 this->closeSocket(fSockfd);
332 fSockfd = this->createSocket();
333 //Add fSockfd since the client will be using it to read/write
334 this->addToMasterSet(fSockfd);
335 }
336
connectToServer()337 int SkTCPClient::connectToServer() {
338 if (!fReady)
339 return -1;
340 if (fConnected)
341 return 0;
342
343 int conn = connect(fSockfd, (sockaddr*)&fServerAddr, sizeof(fServerAddr));
344 if (conn < 0) {
345 #ifdef NONBLOCKING_SOCKETS
346 if (errno == EINPROGRESS || errno == EALREADY)
347 return conn;
348 #endif
349 if (errno != EISCONN) {
350 //SkDebugf("error: %s\n", strerror(errno));
351 this->onFailedConnection(fSockfd);
352 return conn;
353 }
354 }
355 fConnected = true;
356 SkDebugf("Succesfully reached server\n");
357 return 0;
358 }
359