Home | History | Annotate | Download | only in Networking
      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 
     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      */
     80     void suspendAll() { fReadSuspended = fWriteSuspended = true; }
     81     /**
     82      * Resume all network transfers.
     83      */
     84     void resumeAll() { fReadSuspended = fWriteSuspended = false; }
     85     /**
     86      * Other helper functions
     87      */
     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 
    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