aboutsummaryrefslogtreecommitdiffhomepage
path: root/experimental/Networking/SkSockets.h
blob: 8d85446ecc6a54459588c1f29c1a787381f4d28c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
/*
 * 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