portability/ip_sockets.hpp

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
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
#ifndef STLPLUS_IP_SOCKET
#define STLPLUS_IP_SOCKET
////////////////////////////////////////////////////////////////////////////////
 
// Author:    Andy Rushton
// Copyright: (c) Southampton University 1999-2004
//            (c) Andy Rushton           2004 onwards
// License:   BSD License, see ../docs/license.html
 
// A platform-independent (Unix and Windows anyway) interface to Internet-Protocol sockets
 
////////////////////////////////////////////////////////////////////////////////
#include "portability_fixes.hpp"
#include <string>
 
namespace stlplus
{
 
  //////////////////////////////////////////////////////////////////////////////
  // internals
  // use a PIMPL interface to hide the platform-specifics in the implementation
 
  class IP_socket_internals;
 
  ////////////////////////////////////////////////////////////////////////////
  // Types of socket supported
 
  enum IP_socket_type {undefined_socket_type = -1, TCP = 0, UDP = 1};
 
  //////////////////////////////////////////////////////////////////////////////
  // Socket class
 
  class IP_socket
  {
  public:
 
    ////////////////////////////////////////////////////////////////////////////
    // constructors/destructors
 
    // create an uninitialised socket
    IP_socket(void);
 
    // create an initialised socket
    // - type: create either a TCP or UDP socket
    IP_socket(IP_socket_type type);
 
    // destroy the socket, closing it if open
    ~IP_socket(void);
 
    // copying is implemented as aliasing
    IP_socket(const IP_socket&);
    IP_socket& operator=(const IP_socket&);
 
    ////////////////////////////////////////////////////////////////////////////
    // initialisation
 
    // initialise the socket
    // - type: create either a TCP or UDP socket
    // - returns success status
    bool initialise(IP_socket_type type);
 
    // test whether this is an initialised socket
    // - returns whether this is initialised
    bool initialised(void) const;
 
    // close, i.e. disconnect the socket
    // - returns a success flag
    bool close(void);
 
    //////////////////////////////////////////////////////////////////////////////
    // Socket configuration
 
    // function for performing IP lookup (i.e. gethostbyname)
    // could be standalone but making it a member means that it can use the socket's error handler
    // i.e. if this fails, the sockets error code will be set - clear it to use the socket again
    // - remote_address: IP name (stlplus.sourceforge.net) or dotted number (216.34.181.96)
    // - returns the IP address as a long integer - zero if there's an error
    unsigned long ip_lookup(const std::string& remote_address);
 
    // test whether a socket is ready to communicate
    // - readable: test whether socket is ready to read
    // - writeable: test whether a socket is ready to write
    // - timeout: if socket is not ready, time to wait before giving up - in micro-seconds - 0 means don't wait
    // returns false if not ready or error - use error() method to tell - true if ready
    bool select(bool readable, bool writeable, unsigned timeout = 0);
 
    // bind the socket to a port so that it can receive from specific address - typically used by a client
    // - remote_address: IP number of remote server to send/receive to/from
    // - local_port: port on local machine to bind to the address
    // - returns success flag
    bool bind(unsigned long remote_address, unsigned short local_port);
 
    // bind the socket to a port so that it can receive from any address - typically used by a server
    // - local_port: port on local machine to bind to the address
    // - returns success flag
    bool bind_any(unsigned short local_port);
 
    // set this socket up to be a listening port
    // socket must be bound to a port already
    // - queue: length of backlog queue to manage - may be zero meaning no queue
    // - returns success status
    bool listen(unsigned short queue = 0);
 
    // test for a connection on the socket
    // only applicable if it has been set up as a listening port
    // - timeout: how long to wait in microseconds if not connected yet
    // - returns true if a connection is ready to be accepted
    bool accept_ready(unsigned timeout = 0) const;
 
    // accept a connection on the socket
    // only applicable if it has been set up as a listening port
    // - returns the connection as a new socket
    IP_socket accept(void);
 
    // create a connection - usually used by a client
    // TCP: client connect to a remote server
    // UDP: setup remote address and port for sends
    // - remote_address: IP number already looked up using ip_lookup
    // - remote_port: port to connect to
    // - returns a success flag
    bool connect(unsigned long remote_address, unsigned short remote_port);
 
    // test whether a socket is connected and ready to communicate, returns on successful connect or timeout
    // - timeout: how long to wait in microseconds if not connected yet
    // - returns true if connected and ready to communicate, false if not ready or error
    bool connected(unsigned timeout = 0);
 
    ////////////////////////////////////////////////////////////////////////////
    // sending/receiving
 
    // test whether a socket is connected and ready to send data, returns if ready or on timeout
    // - timeout: how long to wait in microseconds if not connected yet (blocking)
    // - returns status
    bool send_ready(unsigned timeout = 0);
 
    // send data through a connection-based (TCP) socket
    // if the data is long only part of it may be sent. The sent part is
    // removed from the data, so the same string can be sent again and again
    // until it is empty.
    // - data: string containing data to be sent - any data successfully sent is removed
    // - returns success flag
    bool send(std::string& data);
 
    // send data through a connectionless (UDP) socket
    // the data will be sent as a single packet
    // - packet: string containing data to be sent - any data successfully sent is removed
    // - remote_address: address of the remote host to send to - optional if the socket has been connected to remote
    // - remote_port: port of the remote host to send to - optional if the socket has been connected to remote
    // - returns success flag
    bool send_packet(std::string& packet, unsigned long remote_address, unsigned short remote_port);
 
    // send data through a connectionless (UDP) socket
    // the data will be sent as a single packet
    // only works if the socket has been connected to remote
    // - packet: string containing data to be sent - any data successfully sent is removed
    // - returns success flag
    bool send_packet(std::string& packet);
 
    // test whether a socket is connected and ready to receive data, returns if ready or on timeout
    // - timeout: how long to wait in microseconds if not connected yet (blocking)
    // - returns status
    bool receive_ready(unsigned wait = 0);
 
    // receive data through a connection-based (TCP) socket
    // if the data is long only part of it may be received. The received data
    // is appended to the string, building it up in stages, so the same string
    // can be received again and again until all information has been
    // received.
    // - data: string receiving data from socket - any data successfully received is appended
    // - returns success flag
    bool receive(std::string& data);
 
    // receive data through a connectionless (UDP) socket
    // - packet: string receiving data from socket - any data successfully received is appended
    // - remote_address: returns the address of the remote host received from
    // - remote_port: returns the port of the remote host received from
    // - returns success flag
    bool receive_packet(std::string& packet, unsigned long& remote_address, unsigned short& remote_port);
 
    // variant of above which does not give back the address and port of the sender
    // receive data through a connectionless (UDP) socket
    // - packet: string receiving data from socket - any data successfully received is appended
    // - returns success flag
    bool receive_packet(std::string& packet);
 
    ////////////////////////////////////////////////////////////////////////////
    // informational
 
    // gets the type of socket
    // - returns undefined_socket_type, TCP or UDP
    IP_socket_type type(void) const;
 
    // the local port number of the connection
    // returns the port number, 0 if not bound to a port
    unsigned short local_port(void) const;
 
    // the remote address of the connection
    // returns the address, 0 if not connected
    unsigned long remote_address(void) const;
 
    // the remote port number of the connection
    // returns the port number, 0 if not connected to a port
    unsigned short remote_port(void) const;
 
    ////////////////////////////////////////////////////////////////////////////
    // error handling
    // errors are set internally
    // an error code of 0 is the test for no error, don't rely on the message being an empty string
    // an error code != 0 means an error, then there will be a message explaining the error
 
    // indicate an error - mostly used internally, you can set your own errors - use a negative code
    void set_error (int error, const std::string& message) const;
 
    // if an error is set it stays set - so you must clear it before further operations
    void clear_error (void) const;
 
    // get the error code of the last error
    int error(void) const;
 
    // get the explanatory message of the last error
    std::string message(void) const;
 
    ////////////////////////////////////////////////////////////////////////////
 
  private:
    friend class IP_socket_internals;
    IP_socket_internals* m_impl;
  };
 
 
} // end namespace stlplus
 
#endif