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 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
|
/*
* Modification History
*
* 2001-January-9 Jason Rohrer
* Created.
*
* 2001-January-28 Jason Rohrer
* Added a static framework init function.
*
* 2001-November-13 Jason Rohrer
* Changed timeout parameter to signed, since -1 is a possible argument.
*
* 2002-March-29 Jason Rohrer
* Added Fortify inclusion.
*
* 2002-August-2 Jason Rohrer
* Added functon for getting remote host address.
*
* 2003-February-3 Jason Rohrer
* Added a function for getting the local host address from a socket.
*
* 2003-August-12 Jason Rohrer
* Added more verbose comment about receive timeout parameter.
* Added a function for flushing socket sends.
*
* 2003-November-20 Jason Rohrer
* Made flush function robust against bogus receive return values.
*
* 2004-December13 Jason Rohrer
* Added a breakConnection function.
*
* 2005-July-5 Jason Rohrer
* Added port number when getting address of remote host.
*
* 2006-May-28 Jason Rohrer
* Changed timeout behavior slightly to support emulation of non-blocking mode.
* Added support for non-blocking sends.
*
* 2008-September-30 Jason Rohrer
* Added support for non-blocking connect.
*
* 2010-January-26 Jason Rohrer
* Added support for disabling Nagle algorithm.
*/
#include "minorGems/common.h"
#ifndef SOCKET_CLASS_INCLUDED
#define SOCKET_CLASS_INCLUDED
#include "minorGems/network/HostAddress.h"
#include "minorGems/system/Time.h"
#ifdef FORTIFY
#include "minorGems/util/development/fortify/fortify.h"
#endif
/**
* Network socket. Does not contain an interface for listening to connections
* (see SocketServer for these interfaces) or for establishing connections
* (see SocketClient for these interfaces).
*
* Note: Implementation for the functions defined here is provided
* separately for each platform (in the mac/ linux/ and win32/
* subdirectories).
*
* @author Jason Rohrer
*/
class Socket {
public:
/**
* Constructor for a socket.
*
* Should not be called directly. Use SocketClient or SocketServer
* to obtain an outbound or inbound socket connection.
*/
Socket();
// destroying a Socket closes the connection
~Socket();
/**
* Initializes the socket framework. Must be called
* once by program before sockets are used. Note
* that SocketClient and SocketServer both should call
* init automatically when they are first used.
*
* @return 0 on success, or -1 on failure.
*/
static int initSocketFramework();
/**
* Gets whether the socket framework has been initialized.
*
* @return true if the framework has been initialized.
*/
static char isFrameworkInitialized();
/**
* For outbound sockets that were opened in non-blocking mode:
*
* Get whether socket is connected yet.
*
* @return 1 on success, 0 on still waiting, -1 on error.
*/
int isConnected();
/**
* Sends bytes through this socket.
*
* @param inBuffer the buffer of bytes to send.
* @param inNumBytes the number of bytes to send.
* @param inAllowedToBlock set to false to prevent blocking.
* Defaults to true.
* @param inAllowDelay set to false to disable Nagle algorithm,
* where a buffer should be sent NOW without waiting for
* more data accumulation.
* Defaults to true.
*
* @return the number of bytes sent successfully,
* or -1 for a socket error.
* Returns -2 if not allowed to block and the operation
* would block.
*/
int send( unsigned char *inBuffer, int inNumBytes,
char inAllowedToBlock = true,
char inAllowDelay = true );
/**
* Receives bytes from this socket.
*
* @param inBuffer the buffer where received bytes will be put.
* Must be pre-allocated memory space.
* @param inNumBytes the number of bytes to read from the socket.
* @param inTimeout the timeout for this receive operation in
* milliseconds. Set to -1 for an infinite timeout.
* -2 is returned from this call in the event of a timeout.
* If timeout is set, only available data is returned (up
* to, but not more than inNumBytes). The socket does not
* wait for all inNumBytes to become available before returning.
* Thus, a timeout return value (-2) means no data was available
* before the timeout. If some data is available, we never
* time out. If no timeout is set (-1 for infinite), the socket
* waits for all inNumBytes to arrive before returning.
* Thus, setting a timeout of 0 effectively puts the socket
* into non-blocking mode.
*
* @return the number of bytes read successfully,
* or -1, -2 for a socket error or timeout, respectively.
*/
int receive( unsigned char *inBuffer, int inNumBytes,
long inTimeout );
/**
* Flushes sent data through the socket.
*
* Intended to be called before deleting the socket to ensure
* that data goes through. The mechanism used by this function
* does not guarantee that data goes through, but it works
* better than simply closing the socket on many platforms.
*
* The method used by this call works best if the remote
* host closes the connection. For example, if we send the
* remote host a "connection closing" indicator, then
* call writeFlushBeforeClose, and the remote host closes
* the connection upon receiving the indicator, all of our
* sent data will be received by the remote host after
* writeFlushBeforeClose returns (assuming that the maximum
* time is long enough for the remote host to actually close
* the connection).
*
* Good maximum times should be in the several-second range,
* though the Apache system uses 30 seconds. For slow connections,
* this might be necessary.
*
* This call will cause any received data to be discarded.
*
* This call DOES NOT close the socket. The socket must be deleted
* as usual after this call returns.
*
* @param inMaxTimeInMilliseconds the maximum time to wait
* in milliseconds. This call may block slightly longer than
* this if the remote host is still sending data.
*/
void sendFlushBeforeClose( int inMaxTimeInMilliseconds );
/**
* Forces this socket's connection to break, causing any blocked
* send or receive operations to fail.
*
* Note that this operation is inherently not thread-safe, so
* some external mechanism must be used to ensure that the socket
* is not destroyed by another thread before breakConnection is called.
* The SocketManager class is one such external mechanism.
*/
void breakConnection();
/**
* Gets the host connected to the other end of this socket.
*
* @return the address of the remote host, or NULL if obtaining
* the address fails. The port of the returned address
* will always be set to the port that the host is connecting from.
* Must be destroyed by caller if non-NULL.
*/
HostAddress *getRemoteHostAddress();
/**
* Gets the local address attached to this socket.
*
* Getting the local address from a socket is more
* accurate than non-connected methods (for example, the methods
* used in HostAddress.h implementations.
*
* @return the address of the local host, or NULL if obtaining
* the address fails. The port of the returned address
* will always be set to 0.
* Must be destroyed by caller if non-NULL.
*/
HostAddress *getLocalHostAddress();
/**
* Used by platform-specific implementations.
*/
void *mNativeObjectPointer;
// called by socket client to set connected status
void setConnected( char inConnected ) {
mConnected = inConnected;
}
private:
static char sInitialized;
char mConnected;
char mIsConnectionBroken;
// toggle Nagle algorithm (inValue=1 turns it off)
void setNoDelay( int inValue );
};
inline Socket::Socket()
: mConnected( true ), mIsConnectionBroken( false ) {
}
inline char Socket::isFrameworkInitialized() {
return sInitialized;
}
inline void Socket::sendFlushBeforeClose( int inMaxTimeInMilliseconds ) {
unsigned char *tempBuffer = new unsigned char[1];
int numRead = -2;
int timeout = 1000;
if( timeout > inMaxTimeInMilliseconds ) {
timeout = inMaxTimeInMilliseconds;
}
long totalTimeout = 0;
unsigned long startSec;
unsigned long startMsec;
Time::getCurrentTime( &startSec, &startMsec );
// keep reading data from socket until we get an error
// or wait too long (pass our max timeout)
while( numRead != -1 && totalTimeout < inMaxTimeInMilliseconds ) {
numRead =
this->receive( tempBuffer, 1, timeout );
// track total time whether the receive timed out or not
totalTimeout =
(long)( Time::getMillisecondsSince( startSec, startMsec ) );
}
delete [] tempBuffer;
}
#endif
|