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