📄 sockutil.h
字号:
// sockutil.h// some utilities built on top of sockets layer// copyright SafeTP Development Group, Inc., 2000 Terms of use are as specified in license.txt#ifndef __SOCKUTIL_H#define __SOCKUTIL_H#include "socket.h" // socket funcs, fd_set, timeval#include "str.h" // string#include "exc.h" // exceptions#ifdef _MSC_VER // MSVC may have a definition for this#ifdef interface#undef interface#endif#endif// ----------------- exceptions -----------------------// thrown by SOCKET funcsclass xSocket : public xBase {public: SOCKET socket; // socket on which failure occurred bool graceful; // true if is simple graceful closure bool temporary; // true if the failure might go away if we wait a while // (this field is set to false initially) // for now, does not include much information for diagnosing // the problem and recovering, because I'm not sure what // info I want; however, all xSocket exceptions *do* imply // that the socket has been closedpublic: // error condition ctor xSocket(SOCKET s, char const *msg); // simple socket-closed ctor xSocket(SOCKET s); xSocket(xSocket const &obj); ~xSocket();};// thrown by resolveHostNameclass xResolveFailure : public xBase {public: string hostname; // name we failed to mappublic: xResolveFailure(char const *hostname); xResolveFailure(xResolveFailure const &obj); ~xResolveFailure();};// ---------------- open-socket counting ----------------------// this is (# of successful socket()/accept() calls) -// (# of successful closesocket() calls)// sm: hiding this name because of thread-safety concerns//extern int socketsOpen;// this is (# of successful socket()/accept() calls) -// (# of successful closesocket() calls)int numSocketsOpen();// inc/decrement the open-sockets countvoid incOpenSockets();void decOpenSockets();// ---------------- standalone funcs ----------------------// ------ receive helpers ------// block until next character read from socket// (relies on OS internal buffering...)char recvChar(SOCKET s);// block until next line (terminated by CRLF) is received// (very inefficient due to use of recvChar!)string recvLine(SOCKET s);// return the next string that appears on the wire, but don't// remove it from the network buffers; block until such a string// arrives; returns the string *without* the CRLF itself.// (also see notes in sockutil.cpp)string peekLine(SOCKET s);// read 4 bytes, convert from network byte order to host byte order,// and return them as an integerunsigned long recvNBO32(SOCKET s);// read 'len' bytes from 's', blocking as necessary; throws an// exception if EOF happens firstvoid recvAll(SOCKET s, char *buf, int len);// read up to 'len' bytes; may read less if EOF encountered; either// way, returns the # of bytes read (may be 0 for immediate EOF)int recvAllToEOF(SOCKET s, char *buf, int len);// block until at least one byte arrives, then read what is waiting,// up to 'len' bytes// returns # of bytes actually read// returns 0 if the socket has been closed// throws an exception on error// intent is to route all receives through this fn, rather than calling// recv() directlyint basicRecv(SOCKET s, char *buf, int len);// ------ send helpers ------// send a single charactervoid sendChar(SOCKET s, char c);// send all of 'buf', blocking as necessaryvoid sendAll(SOCKET s, char const *buf, int len);// calls sendAll(s, str, strlen(str))void sendAllString(SOCKET s, char const *str);// send end-of-line sequence (CRLF)void sendEOL(SOCKET s);// write value, as 4 bytes in network byte order, to 's'void sendNBO32(SOCKET s, unsigned long value);// block until we can send at least one byte;// send up to 'len' bytes of 'data' to socket 's'// returns the # of bytes actually sent// returns 0 if the other side has closed the socket// throws exception on error// intent is to do all sends via this fn, rather than send() directlyint basicSend(SOCKET s, char const *data, int len);// ------ error handlers ------// generic socket error handler// 'msg' is normally the name of the socket lib function that failed// 's' is the socket on which the error occurred, or (SOCKET)NULL if// no particular socket is to blame (e.g. select() failure)// when 'close' is true, this fn will try to close the socket// it is generally expected that this fn throws an exception;// an alternative is to print a message and call exit or abort// (letting this fn return normally is very risky)void xsocket(SOCKET s, char const *msg, bool close=false);// throw the xsocket exception, with 'graceful' = truevoid xsocketClosed(SOCKET s);// ------ error determination ------// map an error code into a human-readable string, null-terminated but// with no newline, or NULL if the code is not understood; the returned// pointer must be treated as a pointer to a static area that will be// overwritten by the next call, even that is not necessarily true on// some systemschar const *errorCodeString(int socket_error_code);// return the error code for use with errorCodeString; only defined after// a socket function returns an error code (usually either SOCKET_ERROR// or INVALID_SOCKET)int getSocketErrorCode();// compose a complete error message string (msg is as in xsocket)string socketErrString(char const *msg);// ------ socket open and close ------// defines a range of allowable ports for use in some operation, or// says that any port is acceptableclass PortRange {public: bool restricted; // when true, use only ports from the given range int low, high; // allowable range; endpoints are *allowed*public: PortRange(); // defaults to unrestricted PortRange(int L, int H) { setRange(L, H); } void setRange(int L, int H) { low = L; high = H; restricted = true; }};// create a listener socket to listen to a particular port on a// particular interface; if port=PORT_ANY, the OS picks the port to// listen toenum { PORT_ANY=0 };SOCKET interface_listen_socket(IPAddress interface, int port);// this one listens to the given port on *all* interfacesinline SOCKET listen_socket(int port) { return interface_listen_socket(INADDR_ANY, port); }// this tries to bind any port in the specified range; eventually// it will give up and throw xSocket (with temporary=true) if it can'tSOCKET interface_listen_socket_range(IPAddress interface, PortRange const &range);// accept a connection on the given listening socketSOCKET accept_socket(SOCKET s);// create a socket and connect it to a remote host/port; optionally// constrain the locally-bound port to 'range'SOCKET connect_socket(IPAddress ipaddr, int port, PortRange const *range = NULL);// close the socket; two reasons to not call OS directly:// - winsock uses closesocket() whereas UNIX uses close()// - this fn calls xsocket on failurevoid close_socket(SOCKET s);// ------ endpoint queries ------// retrieve socket local address and local portvoid getSockName(SOCKET s, sockaddr_in &addr);IPAddress getLocalAddress(SOCKET s);int getLocalPort(SOCKET s);// retrieve socket remote address and remote portvoid getSockPeer(SOCKET s, sockaddr_in &addr);IPAddress getRemoteAddress(SOCKET s);int getRemotePort(SOCKET s);// ------ nonblocking tests ------// returns true if 's' has been closedbool isClosed(SOCKET s);// throw xSocket if 's' is closedvoid checkClosed(SOCKET s);// return true if the named socket has data waiting// (or has been closed, etc.)bool pollReadable(SOCKET s);// true if this socket is a listener socket// (always returns false under some systems.. :( )bool isListening(SOCKET s);// ------ formatting ------// return string of form, "n.n.n.n"string formatAddress(IPAddress addr);// return string of form, "n.n.n.n, port m"string formatAddress(IPAddress addr, int port);// return a string of the form, "n.n.n.n, port m"string formatAddress(sockaddr_in const &saddr);// ------ most socket state ------// print to stdout info about local and remote endpoint names (host/port)void printSocketInfo(SOCKET s);// complete socket information, in form:// [l.l.l.l:p - r.r.r.r:q]// l - local address// p - local port// r - remote address// q - remote port// traps any exceptions, and prints if is listenerstring sockInfo(SOCKET s);// ------ system init/deinit ------// system-specific initializationvoid socket_lib_init();// similar deinitialization (needed only for Winsock...)void socket_lib_deinit();// ------ other random funcs ------// simple endianness check for the machine we're running onbool isBigEndian();// return the port number of a service, or 0 for not found// (the return value is in *host* byte order, unlike// getservbyname(), the function this calls)int getServByName(char const *serviceName);// (blocking)// map string into address; correctly handles addresses in// decimal-dot notationIPAddress resolveHostName(char const *hostname);// -------------- parsing ---------------// given an address in "AAA.BBB.CCC.DDD" format, return the address// as an IPAddress; throws an exception if the address format is// invalidIPAddress parseDottedDecimal(char const *decimalAddr);// if 'addrAndPort' is of the form "AAA.BBB.CCC.DDD:PPPP", return with// 'ipaddr' equal to parsed AAA...DDD, and 'port' equal to parsed PPPP;// if 'addrAndPort' is of form "PPPP", return with 'ipaddr' set to// INADDR_ANY and 'port' set to parsed PPPP; any others will result in// a formatting exception being thrownvoid parseAddrAndPort(IPAddress &ipaddr, int &port, char const *addrAndPort);// ---------------- SocketSet -------------------// implements a set of sockets to improve the interface to select():// - automate calculation of 'nfds', the first parameter to select// - automatically call FD_ZERO// - call xsocket when select() fails// I had originally been more ambitious about what this class would do,// but limitations on easily available data structures reduced it to// handling only the simplest casesclass SocketSet {private: // data fd_set set; // socket api data structure unsigned maxSocket; // largest value of any SOCKET in the set bool used; // when true, must reset before another use int numSockets; // # of (valid) sockets added static timeval timeZero; // {0,0}, the "poll" timeout valuepublic: // funcs SocketSet(); // init to empty ~SocketSet(); // dealloc // ----- selectors ----- // determine if a specific socket is in the set bool contains(SOCKET s) const; // # of sockets added that were valid // (we have this fn to code can add a bunch of sockets, some of which // might be invalid, then ask how many were in fact valid) int numAdded() const { return numSockets; } // ----- mutators ----- // add the given socket to the set, unless the socket is INVALID_SOCKET, // in which case it is not an error but nothing is changed void add(SOCKET s); // return to state where no sockets are in set, // and thus allow re-use of the object void reset(); // the select call: // - sets 'used', so must reset() before next add() or select() // - returns socket select()'s return value, unless select() // returns SOCKET_ERROR, in which case xsocket() is called // - this set is modified by the call, such that the sockets stll // in the set are the ones select() is saying have new information // - r/w/e are used to determine whether to pass this set as each of // the corresponding select() arguments; at least one of these must // be set to true // the 'const' is commented out because some systems have select declared // with non-const 'timeout' parameter.. I don't know if these systems // actually modify timeout, or are just declared incorrectly; caller code // probably should be prepared for the former int select(bool read, bool write, bool except, /*const*/ struct timeval *timeout); // block until one of the sockets is readable, return how many there are then int blockUntilReadable() { return select(true, false, false, NULL); } // return immediately the # of readable sockets int pollReadable() { return select(true, false, false, &timeZero); }};#endif // __SOCKUTIL_H
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -