epoger@google.com | ec3ed6a | 2011-07-28 14:26:00 +0000 | [diff] [blame] | 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 | */ |
yangsu@google.com | c5aeccd | 2011-07-17 14:42:08 +0000 | [diff] [blame] | 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" |
yangsu@google.com | f3493f0 | 2011-08-08 15:12:05 +0000 | [diff] [blame] | 14 | |
yangsu@google.com | c5aeccd | 2011-07-17 14:42:08 +0000 | [diff] [blame] | 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 |
yangsu@google.com | f3493f0 | 2011-08-08 15:12:05 +0000 | [diff] [blame] | 21 | #define MAX_WAITING_CLIENTS 3 |
yangsu@google.com | c5aeccd | 2011-07-17 14:42:08 +0000 | [diff] [blame] | 22 | #define NONBLOCKING_SOCKETS |
yangsu@google.com | c5aeccd | 2011-07-17 14:42:08 +0000 | [diff] [blame] | 23 | |
| 24 | class SkSocket { |
| 25 | public: |
| 26 | SkSocket(); |
robertphillips@google.com | 05141c2 | 2012-04-27 12:54:01 +0000 | [diff] [blame] | 27 | virtual ~SkSocket(); |
yangsu@google.com | c5aeccd | 2011-07-17 14:42:08 +0000 | [diff] [blame] | 28 | |
| 29 | enum State { |
| 30 | kError_state, |
| 31 | kBegin_state, |
| 32 | kIncomplete_state, |
| 33 | kDone_state |
| 34 | }; |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 35 | |
yangsu@google.com | c5aeccd | 2011-07-17 14:42:08 +0000 | [diff] [blame] | 36 | enum DataType { |
| 37 | kPipeAppend_type, |
| 38 | kPipeReplace_type, |
| 39 | kString_type, |
| 40 | kInt_type |
| 41 | }; |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 42 | |
yangsu@google.com | f3493f0 | 2011-08-08 15:12:05 +0000 | [diff] [blame] | 43 | bool isConnected() { return fConnected; } |
| 44 | /** |
yangsu@google.com | c5aeccd | 2011-07-17 14:42:08 +0000 | [diff] [blame] | 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. |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 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 |
yangsu@google.com | ef7bdfa | 2011-08-12 14:27:47 +0000 | [diff] [blame] | 56 | * full |
yangsu@google.com | c5aeccd | 2011-07-17 14:42:08 +0000 | [diff] [blame] | 57 | */ |
| 58 | int writePacket(void* data, size_t size, DataType type = kPipeAppend_type); |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 59 | |
yangsu@google.com | f3493f0 | 2011-08-08 15:12:05 +0000 | [diff] [blame] | 60 | /** |
yangsu@google.com | c5aeccd | 2011-07-17 14:42:08 +0000 | [diff] [blame] | 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, |
yangsu@google.com | f3493f0 | 2011-08-08 15:12:05 +0000 | [diff] [blame] | 65 | * unless there was an error, in which case the method returns -1. \For |
yangsu@google.com | c5aeccd | 2011-07-17 14:42:08 +0000 | [diff] [blame] | 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. |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 69 | * NOTE: This method guarantees that all the data in a logical packet will |
yangsu@google.com | ef7bdfa | 2011-08-12 14:27:47 +0000 | [diff] [blame] | 70 | * be read so it may block temporarily if it's waiting for parts of a |
yangsu@google.com | f3493f0 | 2011-08-08 15:12:05 +0000 | [diff] [blame] | 71 | * packet |
yangsu@google.com | c5aeccd | 2011-07-17 14:42:08 +0000 | [diff] [blame] | 72 | */ |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 73 | int readPacket(void (*onRead)(int cid, const void* data, size_t size, |
yangsu@google.com | c5aeccd | 2011-07-17 14:42:08 +0000 | [diff] [blame] | 74 | DataType type, void*), void* context); |
| 75 | |
yangsu@google.com | f3493f0 | 2011-08-08 15:12:05 +0000 | [diff] [blame] | 76 | /** |
| 77 | * Suspend network transfers until resume() is called. Leaves all |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 78 | * connections in tact. |
yangsu@google.com | f3493f0 | 2011-08-08 15:12:05 +0000 | [diff] [blame] | 79 | */ |
yangsu@google.com | c5aeccd | 2011-07-17 14:42:08 +0000 | [diff] [blame] | 80 | void suspendAll() { fReadSuspended = fWriteSuspended = true; } |
yangsu@google.com | f3493f0 | 2011-08-08 15:12:05 +0000 | [diff] [blame] | 81 | /** |
| 82 | * Resume all network transfers. |
| 83 | */ |
yangsu@google.com | c5aeccd | 2011-07-17 14:42:08 +0000 | [diff] [blame] | 84 | void resumeAll() { fReadSuspended = fWriteSuspended = false; } |
yangsu@google.com | f3493f0 | 2011-08-08 15:12:05 +0000 | [diff] [blame] | 85 | /** |
| 86 | * Other helper functions |
| 87 | */ |
yangsu@google.com | c5aeccd | 2011-07-17 14:42:08 +0000 | [diff] [blame] | 88 | void suspendRead() { fReadSuspended = true; } |
| 89 | void resumeRead() { fReadSuspended = false; } |
| 90 | void suspendWrite() { fWriteSuspended = true; } |
| 91 | void resumeWrite() { fWriteSuspended = false; } |
| 92 | |
| 93 | protected: |
| 94 | struct header { |
| 95 | bool done; |
| 96 | int bytes; |
| 97 | DataType type; |
| 98 | }; |
| 99 | |
yangsu@google.com | f3493f0 | 2011-08-08 15:12:05 +0000 | [diff] [blame] | 100 | /** |
| 101 | * Create a socket and return its file descriptor. Returns -1 on failure |
| 102 | */ |
yangsu@google.com | c5aeccd | 2011-07-17 14:42:08 +0000 | [diff] [blame] | 103 | int createSocket(); |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 104 | |
yangsu@google.com | f3493f0 | 2011-08-08 15:12:05 +0000 | [diff] [blame] | 105 | /** |
| 106 | * Close the socket specified by the socket file descriptor argument. Will |
| 107 | * update fMaxfd and working set properly |
| 108 | */ |
yangsu@google.com | c5aeccd | 2011-07-17 14:42:08 +0000 | [diff] [blame] | 109 | void closeSocket(int sockfd); |
| 110 | |
yangsu@google.com | f3493f0 | 2011-08-08 15:12:05 +0000 | [diff] [blame] | 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 | */ |
yangsu@google.com | c5aeccd | 2011-07-17 14:42:08 +0000 | [diff] [blame] | 116 | virtual void onFailedConnection(int sockfd); |
| 117 | |
yangsu@google.com | f3493f0 | 2011-08-08 15:12:05 +0000 | [diff] [blame] | 118 | /** |
| 119 | * Set the socket specified by the socket file descriptor as nonblocking |
| 120 | */ |
yangsu@google.com | c5aeccd | 2011-07-17 14:42:08 +0000 | [diff] [blame] | 121 | void setNonBlocking(int sockfd); |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 122 | |
yangsu@google.com | f3493f0 | 2011-08-08 15:12:05 +0000 | [diff] [blame] | 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 | */ |
yangsu@google.com | c5aeccd | 2011-07-17 14:42:08 +0000 | [diff] [blame] | 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; |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 137 | |
| 138 | /** |
yangsu@google.com | f3493f0 | 2011-08-08 15:12:05 +0000 | [diff] [blame] | 139 | * fMasterSet contains all the file descriptors to be used for read/write. |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 140 | * For clients, this only contains the client socket. For servers, this |
yangsu@google.com | f3493f0 | 2011-08-08 15:12:05 +0000 | [diff] [blame] | 141 | * contains all the file descriptors associated with established connections |
| 142 | * to clients |
| 143 | */ |
yangsu@google.com | c5aeccd | 2011-07-17 14:42:08 +0000 | [diff] [blame] | 144 | fd_set fMasterSet; |
yangsu@google.com | c5aeccd | 2011-07-17 14:42:08 +0000 | [diff] [blame] | 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 |
yangsu@google.com | f3493f0 | 2011-08-08 15:12:05 +0000 | [diff] [blame] | 150 | * be specified, but make sure that client/server use the same port |
yangsu@google.com | c5aeccd | 2011-07-17 14:42:08 +0000 | [diff] [blame] | 151 | */ |
| 152 | class SkTCPServer : public SkSocket { |
| 153 | public: |
| 154 | SkTCPServer(int port = DEFAULT_PORT); |
robertphillips@google.com | 05141c2 | 2012-04-27 12:54:01 +0000 | [diff] [blame] | 155 | virtual ~SkTCPServer(); |
yangsu@google.com | c5aeccd | 2011-07-17 14:42:08 +0000 | [diff] [blame] | 156 | |
yangsu@google.com | f3493f0 | 2011-08-08 15:12:05 +0000 | [diff] [blame] | 157 | /** |
| 158 | * Accept any incoming connections to the server, will accept 1 connection |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 159 | * at a time. Returns -1 on error. For blocking sockets, this method will |
yangsu@google.com | f3493f0 | 2011-08-08 15:12:05 +0000 | [diff] [blame] | 160 | * block until a client calls connectToServer() |
| 161 | */ |
| 162 | int acceptConnections(); |
yangsu@google.com | c5aeccd | 2011-07-17 14:42:08 +0000 | [diff] [blame] | 163 | |
yangsu@google.com | f3493f0 | 2011-08-08 15:12:05 +0000 | [diff] [blame] | 164 | /** |
| 165 | * Disconnect all connections to clients. Returns -1 on error |
| 166 | */ |
| 167 | int disconnectAll(); |
yangsu@google.com | c5aeccd | 2011-07-17 14:42:08 +0000 | [diff] [blame] | 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 | |
yangsu@google.com | f3493f0 | 2011-08-08 15:12:05 +0000 | [diff] [blame] | 181 | /** |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 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 |
yangsu@google.com | f3493f0 | 2011-08-08 15:12:05 +0000 | [diff] [blame] | 184 | * until the connection is accepted by the server. |
| 185 | */ |
yangsu@google.com | c5aeccd | 2011-07-17 14:42:08 +0000 | [diff] [blame] | 186 | int connectToServer(); |
yangsu@google.com | f3493f0 | 2011-08-08 15:12:05 +0000 | [diff] [blame] | 187 | protected: |
| 188 | /** |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 189 | * Client needs to recreate the socket when a connection is broken because |
| 190 | * connect can only be called successfully once. |
yangsu@google.com | f3493f0 | 2011-08-08 15:12:05 +0000 | [diff] [blame] | 191 | */ |
yangsu@google.com | c5aeccd | 2011-07-17 14:42:08 +0000 | [diff] [blame] | 192 | virtual void onFailedConnection(int sockfd); |
| 193 | private: |
| 194 | sockaddr_in fServerAddr; |
| 195 | typedef SkSocket INHERITED; |
| 196 | }; |
| 197 | |
| 198 | #endif |