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 #ifndef SkNetIO_DEFINED
8 #define SkNetIO_DEFINED
9 
10 #include <netinet/in.h>
11 #include <sys/socket.h>
12 #include "SkTypes.h"
13 #include "SkStream.h"
14 
15 /* PACKET and HEADER Format */
16 #define PACKET_SIZE 1024
17 #define HEADER_SIZE 20
18 #define CONTENT_SIZE 1004
19 
20 #define DEFAULT_PORT 15555
21 #define MAX_WAITING_CLIENTS 3
22 #define NONBLOCKING_SOCKETS
23 
24 class SkSocket {
25 public:
26     SkSocket();
27     virtual ~SkSocket();
28 
29     enum State {
30         kError_state,
31         kBegin_state,
32         kIncomplete_state,
33         kDone_state
34     };
35 
36     enum DataType {
37         kPipeAppend_type,
38         kPipeReplace_type,
39         kString_type,
40         kInt_type
41     };
42 
isConnected()43     bool isConnected() { return fConnected; }
44     /**
45      * Write data to the socket. Data is a pointer to the beginning of the data
46      * to be sent and dataSize specifies the number of bytes to send. This
47      * method will spread the data across multiple packets if the data can't all
48      * fit in a single packet. The method will write all the data to each of the
49      * socket's open connections until all the bytes have been successfully sent
50      * and return total the number of bytes written to all clients, unless there
51      * was an error during the transfer, in which case the method returns -1.
52      * For blocking sockets, write will block indefinitely if the socket at the
53      * other end of the connection doesn't receive any data.
54      * NOTE: This method guarantees that all of the data will be sent unless
55      * there was an error, so it may block temporarily when the write buffer is
56      * full
57      */
58     int writePacket(void* data, size_t size, DataType type = kPipeAppend_type);
59 
60     /**
61      * Read a logical packet from socket. The data read will be stored
62      * sequentially in the dataArray. This method will keep running until all
63      * the data in a logical chunk has been read (assembling multiple partial
64      * packets if necessary) and return the number of bytes successfully read,
65      * unless there was an error, in which case the method returns -1. \For
66      * nonblocking sockets, read will return 0 if there's nothing to read. For
67      * blocking sockets, read will block indefinitely if the socket doesn't
68      * receive any data.
69      * NOTE: This method guarantees that all the data in a logical packet will
70      * be read so it may block temporarily if it's waiting for parts of a
71      * packet
72      */
73     int readPacket(void (*onRead)(int cid, const void* data, size_t size,
74                                   DataType type, void*), void* context);
75 
76     /**
77      * Suspend network transfers until resume() is called. Leaves all
78      * connections in tact.
79      */
suspendAll()80     void suspendAll() { fReadSuspended = fWriteSuspended = true; }
81     /**
82      * Resume all network transfers.
83      */
resumeAll()84     void resumeAll() { fReadSuspended = fWriteSuspended = false; }
85     /**
86      * Other helper functions
87      */
suspendRead()88     void suspendRead() { fReadSuspended = true; }
resumeRead()89     void resumeRead() { fReadSuspended = false; }
suspendWrite()90     void suspendWrite()  { fWriteSuspended = true; }
resumeWrite()91     void resumeWrite()  { fWriteSuspended = false; }
92 
93 protected:
94     struct header {
95         bool        done;
96         int         bytes;
97         DataType    type;
98     };
99 
100     /**
101      * Create a socket and return its file descriptor. Returns -1 on failure
102      */
103     int createSocket();
104 
105     /**
106      * Close the socket specified by the socket file descriptor argument. Will
107      * update fMaxfd and working set properly
108      */
109     void closeSocket(int sockfd);
110 
111     /**
112      * Called when a broken or terminated connection has been detected. Closes
113      * the socket file descriptor and removes it from the master set by default.
114      * Override to handle broken connections differently
115      */
116     virtual void onFailedConnection(int sockfd);
117 
118     /**
119      * Set the socket specified by the socket file descriptor as nonblocking
120      */
121     void setNonBlocking(int sockfd);
122 
123     /**
124      * Add the socket specified by the socket file descriptor to the master
125      * file descriptor set, which is used to in the select() to detect new data
126      * or connections
127      */
128     void addToMasterSet(int sockfd);
129 
130     bool    fConnected;
131     bool    fReady;
132     bool    fReadSuspended;
133     bool    fWriteSuspended;
134     int     fMaxfd;
135     int     fPort;
136     int     fSockfd;
137 
138     /**
139      * fMasterSet contains all the file descriptors to be used for read/write.
140      * For clients, this only contains the client socket. For servers, this
141      * contains all the file descriptors associated with established connections
142      * to clients
143      */
144     fd_set  fMasterSet;
145 };
146 
147 /*
148  * TCP server. Can accept simultaneous connections to multiple SkTCPClients and
149  * read/write data back and forth using read/writePacket calls. Port number can
150  * be specified, but make sure that client/server use the same port
151  */
152 class SkTCPServer : public SkSocket {
153 public:
154     SkTCPServer(int port = DEFAULT_PORT);
155     virtual ~SkTCPServer();
156 
157     /**
158      * Accept any incoming connections to the server, will accept 1 connection
159      * at a time. Returns -1 on error. For blocking sockets, this method will
160      * block until a client calls connectToServer()
161      */
162     int acceptConnections();
163 
164     /**
165      * Disconnect all connections to clients. Returns -1 on error
166      */
167     int disconnectAll();
168 private:
169     typedef SkSocket INHERITED;
170 };
171 
172 /*
173  * TCP client. Will connect to the server specified in the constructor. If a
174  * port number is specified, make sure that it's the same as the port number on
175  * the server
176  */
177 class SkTCPClient : public SkSocket {
178 public:
179     SkTCPClient(const char* hostname, int port = DEFAULT_PORT);
180 
181     /**
182      * Connect to server. Returns -1 on error or failure. Call this to connect
183      * or reconnect to the server. For blocking sockets, this method will block
184      * until the connection is accepted by the server.
185      */
186     int connectToServer();
187 protected:
188     /**
189      * Client needs to recreate the socket when a connection is broken because
190      * connect can only be called successfully once.
191      */
192     virtual void onFailedConnection(int sockfd);
193 private:
194     sockaddr_in fServerAddr;
195     typedef SkSocket INHERITED;
196 };
197 
198 #endif
199