/* * 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 #include #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