|  | /* | 
|  | * Copyright 2011 Google Inc. | 
|  | * | 
|  | * Use of this source code is governed by a BSD-style license that can be | 
|  | * found in the LICENSE file. | 
|  | */ | 
|  | #ifndef SkNetIO_DEFINED | 
|  | #define SkNetIO_DEFINED | 
|  |  | 
|  | #include <netinet/in.h> | 
|  | #include <sys/socket.h> | 
|  | #include "SkTypes.h" | 
|  | #include "SkStream.h" | 
|  |  | 
|  | /* PACKET and HEADER Format */ | 
|  | #define PACKET_SIZE 1024 | 
|  | #define HEADER_SIZE 20 | 
|  | #define CONTENT_SIZE 1004 | 
|  |  | 
|  | #define DEFAULT_PORT 15555 | 
|  | #define MAX_WAITING_CLIENTS 3 | 
|  | #define NONBLOCKING_SOCKETS | 
|  |  | 
|  | class SkSocket { | 
|  | public: | 
|  | SkSocket(); | 
|  | virtual ~SkSocket(); | 
|  |  | 
|  | enum State { | 
|  | kError_state, | 
|  | kBegin_state, | 
|  | kIncomplete_state, | 
|  | kDone_state | 
|  | }; | 
|  |  | 
|  | enum DataType { | 
|  | kPipeAppend_type, | 
|  | kPipeReplace_type, | 
|  | kString_type, | 
|  | kInt_type | 
|  | }; | 
|  |  | 
|  | bool isConnected() { return fConnected; } | 
|  | /** | 
|  | * Write data to the socket. Data is a pointer to the beginning of the data | 
|  | * to be sent and dataSize specifies the number of bytes to send. This | 
|  | * method will spread the data across multiple packets if the data can't all | 
|  | * fit in a single packet. The method will write all the data to each of the | 
|  | * socket's open connections until all the bytes have been successfully sent | 
|  | * and return total the number of bytes written to all clients, unless there | 
|  | * was an error during the transfer, in which case the method returns -1. | 
|  | * For blocking sockets, write will block indefinitely if the socket at the | 
|  | * other end of the connection doesn't receive any data. | 
|  | * NOTE: This method guarantees that all of the data will be sent unless | 
|  | * there was an error, so it may block temporarily when the write buffer is | 
|  | * full | 
|  | */ | 
|  | int writePacket(void* data, size_t size, DataType type = kPipeAppend_type); | 
|  |  | 
|  | /** | 
|  | * Read a logical packet from socket. The data read will be stored | 
|  | * sequentially in the dataArray. This method will keep running until all | 
|  | * the data in a logical chunk has been read (assembling multiple partial | 
|  | * packets if necessary) and return the number of bytes successfully read, | 
|  | * unless there was an error, in which case the method returns -1. \For | 
|  | * nonblocking sockets, read will return 0 if there's nothing to read. For | 
|  | * blocking sockets, read will block indefinitely if the socket doesn't | 
|  | * receive any data. | 
|  | * NOTE: This method guarantees that all the data in a logical packet will | 
|  | * be read so it may block temporarily if it's waiting for parts of a | 
|  | * packet | 
|  | */ | 
|  | int readPacket(void (*onRead)(int cid, const void* data, size_t size, | 
|  | DataType type, void*), void* context); | 
|  |  | 
|  | /** | 
|  | * Suspend network transfers until resume() is called. Leaves all | 
|  | * connections in tact. | 
|  | */ | 
|  | void suspendAll() { fReadSuspended = fWriteSuspended = true; } | 
|  | /** | 
|  | * Resume all network transfers. | 
|  | */ | 
|  | void resumeAll() { fReadSuspended = fWriteSuspended = false; } | 
|  | /** | 
|  | * Other helper functions | 
|  | */ | 
|  | void suspendRead() { fReadSuspended = true; } | 
|  | void resumeRead() { fReadSuspended = false; } | 
|  | void suspendWrite()  { fWriteSuspended = true; } | 
|  | void resumeWrite()  { fWriteSuspended = false; } | 
|  |  | 
|  | protected: | 
|  | struct header { | 
|  | bool        done; | 
|  | int         bytes; | 
|  | DataType    type; | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * Create a socket and return its file descriptor. Returns -1 on failure | 
|  | */ | 
|  | int createSocket(); | 
|  |  | 
|  | /** | 
|  | * Close the socket specified by the socket file descriptor argument. Will | 
|  | * update fMaxfd and working set properly | 
|  | */ | 
|  | void closeSocket(int sockfd); | 
|  |  | 
|  | /** | 
|  | * Called when a broken or terminated connection has been detected. Closes | 
|  | * the socket file descriptor and removes it from the master set by default. | 
|  | * Override to handle broken connections differently | 
|  | */ | 
|  | virtual void onFailedConnection(int sockfd); | 
|  |  | 
|  | /** | 
|  | * Set the socket specified by the socket file descriptor as nonblocking | 
|  | */ | 
|  | void setNonBlocking(int sockfd); | 
|  |  | 
|  | /** | 
|  | * Add the socket specified by the socket file descriptor to the master | 
|  | * file descriptor set, which is used to in the select() to detect new data | 
|  | * or connections | 
|  | */ | 
|  | void addToMasterSet(int sockfd); | 
|  |  | 
|  | bool    fConnected; | 
|  | bool    fReady; | 
|  | bool    fReadSuspended; | 
|  | bool    fWriteSuspended; | 
|  | int     fMaxfd; | 
|  | int     fPort; | 
|  | int     fSockfd; | 
|  |  | 
|  | /** | 
|  | * fMasterSet contains all the file descriptors to be used for read/write. | 
|  | * For clients, this only contains the client socket. For servers, this | 
|  | * contains all the file descriptors associated with established connections | 
|  | * to clients | 
|  | */ | 
|  | fd_set  fMasterSet; | 
|  | }; | 
|  |  | 
|  | /* | 
|  | * TCP server. Can accept simultaneous connections to multiple SkTCPClients and | 
|  | * read/write data back and forth using read/writePacket calls. Port number can | 
|  | * be specified, but make sure that client/server use the same port | 
|  | */ | 
|  | class SkTCPServer : public SkSocket { | 
|  | public: | 
|  | SkTCPServer(int port = DEFAULT_PORT); | 
|  | virtual ~SkTCPServer(); | 
|  |  | 
|  | /** | 
|  | * Accept any incoming connections to the server, will accept 1 connection | 
|  | * at a time. Returns -1 on error. For blocking sockets, this method will | 
|  | * block until a client calls connectToServer() | 
|  | */ | 
|  | int acceptConnections(); | 
|  |  | 
|  | /** | 
|  | * Disconnect all connections to clients. Returns -1 on error | 
|  | */ | 
|  | int disconnectAll(); | 
|  | private: | 
|  | typedef SkSocket INHERITED; | 
|  | }; | 
|  |  | 
|  | /* | 
|  | * TCP client. Will connect to the server specified in the constructor. If a | 
|  | * port number is specified, make sure that it's the same as the port number on | 
|  | * the server | 
|  | */ | 
|  | class SkTCPClient : public SkSocket { | 
|  | public: | 
|  | SkTCPClient(const char* hostname, int port = DEFAULT_PORT); | 
|  |  | 
|  | /** | 
|  | * Connect to server. Returns -1 on error or failure. Call this to connect | 
|  | * or reconnect to the server. For blocking sockets, this method will block | 
|  | * until the connection is accepted by the server. | 
|  | */ | 
|  | int connectToServer(); | 
|  | protected: | 
|  | /** | 
|  | * Client needs to recreate the socket when a connection is broken because | 
|  | * connect can only be called successfully once. | 
|  | */ | 
|  | virtual void onFailedConnection(int sockfd); | 
|  | private: | 
|  | sockaddr_in fServerAddr; | 
|  | typedef SkSocket INHERITED; | 
|  | }; | 
|  |  | 
|  | #endif |