diff options
author | IOhannes m zmölnig <zmoelnig@users.sourceforge.net> | 2005-03-08 10:23:43 +0000 |
---|---|---|
committer | IOhannes m zmölnig <zmoelnig@users.sourceforge.net> | 2005-03-08 10:23:43 +0000 |
commit | 922cb5559b9f2f97279fa24cc9c5862c8b666495 (patch) | |
tree | 10b3616acd63f3d60689c1a26aa4ccadf6115511 /xmlrpc++/src/XmlRpcSocket.cpp |
This commit was generated by cvs2svn to compensate for changes in r2603,svn2git-root
which included commits to RCS files with non-trunk default branches.
svn path=/trunk/externals/iem/iemxmlrpc/; revision=2604
Diffstat (limited to 'xmlrpc++/src/XmlRpcSocket.cpp')
-rw-r--r-- | xmlrpc++/src/XmlRpcSocket.cpp | 260 |
1 files changed, 260 insertions, 0 deletions
diff --git a/xmlrpc++/src/XmlRpcSocket.cpp b/xmlrpc++/src/XmlRpcSocket.cpp new file mode 100644 index 0000000..b71ef94 --- /dev/null +++ b/xmlrpc++/src/XmlRpcSocket.cpp @@ -0,0 +1,260 @@ + +#include "XmlRpcSocket.h" +#include "XmlRpcUtil.h" + +#ifndef MAKEDEPEND + +#if defined(_WINDOWS) +# include <stdio.h>
+# include <winsock2.h> +//# pragma lib(WS2_32.lib) + +# define EINPROGRESS WSAEINPROGRESS +# define EWOULDBLOCK WSAEWOULDBLOCK +# define ETIMEDOUT WSAETIMEDOUT +#else +extern "C" { +# include <unistd.h> +# include <stdio.h> +# include <sys/types.h> +# include <sys/socket.h> +# include <netinet/in.h> +# include <netdb.h> +# include <errno.h> +# include <fcntl.h> +} +#endif // _WINDOWS + +#endif // MAKEDEPEND + + +using namespace XmlRpc; + + + +#if defined(_WINDOWS) + +static void initWinSock() +{ + static bool wsInit = false; + if (! wsInit) + { + WORD wVersionRequested = MAKEWORD( 2, 0 ); + WSADATA wsaData; + WSAStartup(wVersionRequested, &wsaData); + wsInit = true; + } +} + +#else + +#define initWinSock() + +#endif // _WINDOWS + + +// These errors are not considered fatal for an IO operation; the operation will be re-tried.
+static inline bool
+nonFatalError()
+{
+ int err = XmlRpcSocket::getError();
+ return (err == EINPROGRESS || err == EAGAIN || err == EWOULDBLOCK || err == EINTR);
+}
+
+
+ +int +XmlRpcSocket::socket() +{ + initWinSock(); + return (int) ::socket(AF_INET, SOCK_STREAM, 0); +} + + +void +XmlRpcSocket::close(int fd) +{ + XmlRpcUtil::log(4, "XmlRpcSocket::close: fd %d.", fd); +#if defined(_WINDOWS) + closesocket(fd); +#else + ::close(fd); +#endif // _WINDOWS +} + + + + +bool +XmlRpcSocket::setNonBlocking(int fd) +{ +#if defined(_WINDOWS) + unsigned long flag = 1; + return (ioctlsocket((SOCKET)fd, FIONBIO, &flag) == 0); +#else + return (fcntl(fd, F_SETFL, O_NONBLOCK) == 0); +#endif // _WINDOWS +} + + +bool +XmlRpcSocket::setReuseAddr(int fd) +{ + // Allow this port to be re-bound immediately so server re-starts are not delayed + int sflag = 1; + return (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&sflag, sizeof(sflag)) == 0); +} + + +// Bind to a specified port +bool +XmlRpcSocket::bind(int fd, int port) +{ + struct sockaddr_in saddr; + memset(&saddr, 0, sizeof(saddr)); + saddr.sin_family = AF_INET; + saddr.sin_addr.s_addr = htonl(INADDR_ANY); + saddr.sin_port = htons((u_short) port); + return (::bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)) == 0); +} + + +// Set socket in listen mode +bool +XmlRpcSocket::listen(int fd, int backlog) +{ + return (::listen(fd, backlog) == 0); +} + + +int +XmlRpcSocket::accept(int fd) +{ + struct sockaddr_in addr; +#if defined(_WINDOWS) + int +#else + socklen_t +#endif + addrlen = sizeof(addr); + + return (int) ::accept(fd, (struct sockaddr*)&addr, &addrlen); +} + + + +// Connect a socket to a server (from a client) +bool +XmlRpcSocket::connect(int fd, std::string& host, int port) +{ + struct sockaddr_in saddr; + memset(&saddr, 0, sizeof(saddr)); + saddr.sin_family = AF_INET; + + struct hostent *hp = gethostbyname(host.c_str()); + if (hp == 0) return false; + + saddr.sin_family = hp->h_addrtype; + memcpy(&saddr.sin_addr, hp->h_addr, hp->h_length); + saddr.sin_port = htons((u_short) port); + + // For asynch operation, this will return EWOULDBLOCK (windows) or + // EINPROGRESS (linux) and we just need to wait for the socket to be writable... + int result = ::connect(fd, (struct sockaddr *)&saddr, sizeof(saddr)); + return result == 0 || nonFatalError(); +} + + + +// Read available text from the specified socket. Returns false on error. +bool +XmlRpcSocket::nbRead(int fd, std::string& s, bool *eof) +{ + const int READ_SIZE = 4096; // Number of bytes to attempt to read at a time + char readBuf[READ_SIZE]; + + bool wouldBlock = false; + *eof = false; + + while ( ! wouldBlock && ! *eof) { +#if defined(_WINDOWS) + int n = recv(fd, readBuf, READ_SIZE-1, 0); +#else + int n = read(fd, readBuf, READ_SIZE-1); +#endif + XmlRpcUtil::log(5, "XmlRpcSocket::nbRead: read/recv returned %d.", n); +
+ if (n > 0) { + readBuf[n] = 0; + s.append(readBuf, n); + } else if (n == 0) { + *eof = true; + } else if (nonFatalError()) { + wouldBlock = true; + } else { + return false; // Error + } + } + return true; +} + + +// Write text to the specified socket. Returns false on error. +bool +XmlRpcSocket::nbWrite(int fd, std::string& s, int *bytesSoFar) +{ + int nToWrite = int(s.length()) - *bytesSoFar; + char *sp = const_cast<char*>(s.c_str()) + *bytesSoFar; + bool wouldBlock = false; + + while ( nToWrite > 0 && ! wouldBlock ) { +#if defined(_WINDOWS) + int n = send(fd, sp, nToWrite, 0); +#else + int n = write(fd, sp, nToWrite); +#endif + XmlRpcUtil::log(5, "XmlRpcSocket::nbWrite: send/write returned %d.", n); + + if (n > 0) { + sp += n; + *bytesSoFar += n; + nToWrite -= n; + } else if (nonFatalError()) { + wouldBlock = true; + } else { + return false; // Error + } + } + return true; +} + + +// Returns last errno +int +XmlRpcSocket::getError() +{ +#if defined(_WINDOWS) + return WSAGetLastError(); +#else + return errno; +#endif +} + + +// Returns message corresponding to last errno +std::string +XmlRpcSocket::getErrorMsg() +{ + return getErrorMsg(getError()); +} + +// Returns message corresponding to errno... well, it should anyway +std::string +XmlRpcSocket::getErrorMsg(int error) +{ + char err[60]; + snprintf(err,sizeof(err),"error %d", error); + return std::string(err); +} + + |