aboutsummaryrefslogtreecommitdiff
path: root/xmlrpc++/src/XmlRpcSocket.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xmlrpc++/src/XmlRpcSocket.cpp')
-rw-r--r--xmlrpc++/src/XmlRpcSocket.cpp260
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);
+}
+
+