summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/socketengine.h35
-rw-r--r--src/inspsocket.cpp51
-rw-r--r--src/socketengine.cpp27
-rw-r--r--win/inspircd_win32wrapper.h26
4 files changed, 89 insertions, 50 deletions
diff --git a/include/socketengine.h b/include/socketengine.h
index 895457b89..f30289913 100644
--- a/include/socketengine.h
+++ b/include/socketengine.h
@@ -29,6 +29,14 @@
#include "socket.h"
#include "base.h"
+#ifndef _WIN32
+#include <sys/uio.h>
+#endif
+
+#ifndef IOV_MAX
+#define IOV_MAX 1024
+#endif
+
/** Types of event an EventHandler may receive.
* EVENT_READ is a readable file descriptor,
* and EVENT_WRITE is a writeable file descriptor.
@@ -306,6 +314,12 @@ class CoreExport SocketEngine
}
public:
+#ifndef _WIN32
+ typedef iovec IOVector;
+#else
+ typedef WindowsIOVec IOVector;
+#endif
+
/** Constructor.
* The constructor transparently initializes
* the socket engine which the ircd is using.
@@ -434,6 +448,27 @@ public:
*/
static int Send(EventHandler* fd, const void *buf, size_t len, int flags);
+ /** Abstraction for vector write function writev().
+ * This function should emulate its namesake system call exactly.
+ * @param fd EventHandler to send data with
+ * @param iov Array of IOVectors containing the buffers to send and their lengths in the platform's
+ * native format.
+ * @param count Number of elements in iov.
+ * @return This method should return exactly the same values as the system call it emulates.
+ */
+ static int WriteV(EventHandler* fd, const IOVector* iov, int count);
+
+#ifdef _WIN32
+ /** Abstraction for vector write function writev() that accepts a POSIX format iovec.
+ * This function should emulate its namesake system call exactly.
+ * @param fd EventHandler to send data with
+ * @param iov Array of iovecs containing the buffers to send and their lengths in POSIX format.
+ * @param count Number of elements in iov.
+ * @return This method should return exactly the same values as the system call it emulates.
+ */
+ static int WriteV(EventHandler* fd, const iovec* iov, int count);
+#endif
+
/** Abstraction for BSD sockets recv(2).
* This function should emulate its namesake system call exactly.
* @param fd This version of the call takes an EventHandler instead of a bare file descriptor.
diff --git a/src/inspsocket.cpp b/src/inspsocket.cpp
index ee5287e5f..2646e265f 100644
--- a/src/inspsocket.cpp
+++ b/src/inspsocket.cpp
@@ -25,14 +25,6 @@
#include "inspircd.h"
#include "iohook.h"
-#ifndef DISABLE_WRITEV
-#include <sys/uio.h>
-#endif
-
-#ifndef IOV_MAX
-#define IOV_MAX 1024
-#endif
-
BufferedSocket::BufferedSocket()
{
Timeout = NULL;
@@ -225,9 +217,7 @@ void StreamSocket::DoWrite()
return;
}
-#ifndef DISABLE_WRITEV
if (GetIOHook())
-#endif
{
int rv = -1;
try
@@ -254,7 +244,7 @@ void StreamSocket::DoWrite()
}
std::string& front = sendq.front();
int itemlen = front.length();
- if (GetIOHook())
+
{
rv = GetIOHook()->OnStreamSocketWrite(this, front);
if (rv > 0)
@@ -278,39 +268,6 @@ void StreamSocket::DoWrite()
return;
}
}
-#ifdef DISABLE_WRITEV
- else
- {
- rv = SocketEngine::Send(this, front.data(), itemlen, 0);
- if (rv == 0)
- {
- SetError("Connection closed");
- return;
- }
- else if (rv < 0)
- {
- if (errno == EINTR || SocketEngine::IgnoreError())
- SocketEngine::ChangeEventMask(this, FD_WANT_FAST_WRITE | FD_WRITE_WILL_BLOCK);
- else
- SetError(SocketEngine::LastError());
- return;
- }
- else if (rv < itemlen)
- {
- SocketEngine::ChangeEventMask(this, FD_WANT_FAST_WRITE | FD_WRITE_WILL_BLOCK);
- front.erase(0, rv);
- sendq_len -= rv;
- return;
- }
- else
- {
- sendq_len -= itemlen;
- sendq.pop_front();
- if (sendq.empty())
- SocketEngine::ChangeEventMask(this, FD_WANT_EDGE_WRITE);
- }
- }
-#endif
}
}
catch (CoreException& modexcept)
@@ -319,7 +276,6 @@ void StreamSocket::DoWrite()
modexcept.GetSource().c_str(), modexcept.GetReason().c_str());
}
}
-#ifndef DISABLE_WRITEV
else
{
// don't even try if we are known to be blocking
@@ -341,14 +297,14 @@ void StreamSocket::DoWrite()
int rv_max = 0;
int rv;
{
- iovec iovecs[MYIOV_MAX];
+ SocketEngine::IOVector iovecs[MYIOV_MAX];
for (int i = 0; i < bufcount; i++)
{
iovecs[i].iov_base = const_cast<char*>(sendq[i].data());
iovecs[i].iov_len = sendq[i].length();
rv_max += sendq[i].length();
}
- rv = writev(fd, iovecs, bufcount);
+ rv = SocketEngine::WriteV(this, iovecs, bufcount);
}
if (rv == (int)sendq_len)
@@ -412,7 +368,6 @@ void StreamSocket::DoWrite()
SocketEngine::ChangeEventMask(this, eventChange);
}
}
-#endif
}
void StreamSocket::WriteData(const std::string &data)
diff --git a/src/socketengine.cpp b/src/socketengine.cpp
index 1c91ccdea..eadfc73d3 100644
--- a/src/socketengine.cpp
+++ b/src/socketengine.cpp
@@ -224,6 +224,33 @@ int SocketEngine::SendTo(EventHandler* fd, const void *buf, size_t len, int flag
return nbSent;
}
+int SocketEngine::WriteV(EventHandler* fd, const IOVector* iovec, int count)
+{
+ int sent = writev(fd->GetFd(), iovec, count);
+ if (sent > 0)
+ stats.Update(0, sent);
+ return sent;
+}
+
+#ifdef _WIN32
+int SocketEngine::WriteV(EventHandler* fd, const iovec* iovec, int count)
+{
+ // On Windows the fields in iovec are not in the order required by the Winsock API; IOVector has
+ // the fields in the correct order.
+ // Create temporary IOVectors from the iovecs and pass them to the WriteV() method that accepts the
+ // platform's native struct.
+ IOVector wiovec[128];
+ count = std::min(count, static_cast<int>(sizeof(wiovec) / sizeof(IOVector)));
+
+ for (int i = 0; i < count; i++)
+ {
+ wiovec[i].iov_len = iovec[i].iov_len;
+ wiovec[i].iov_base = reinterpret_cast<char*>(iovec[i].iov_base);
+ }
+ return WriteV(fd, wiovec, count);
+}
+#endif
+
int SocketEngine::Connect(EventHandler* fd, const sockaddr *serv_addr, socklen_t addrlen)
{
int ret = connect(fd->GetFd(), serv_addr, addrlen);
diff --git a/win/inspircd_win32wrapper.h b/win/inspircd_win32wrapper.h
index a19bdf857..2218d9300 100644
--- a/win/inspircd_win32wrapper.h
+++ b/win/inspircd_win32wrapper.h
@@ -199,8 +199,6 @@ CoreExport void closedir(DIR * handle);
void * ::operator new(size_t iSize);
void ::operator delete(void * ptr);
-#define DISABLE_WRITEV
-
#include <exception>
class CWin32Exception : public std::exception
@@ -218,3 +216,27 @@ private:
// Same value as EXIT_STATUS_FORK (EXIT_STATUS_FORK is unused on Windows)
#define EXIT_STATUS_SERVICE 4
+
+// POSIX iovec
+struct iovec
+{
+ void* iov_base; // Starting address
+ size_t iov_len; // Number of bytes to transfer
+};
+
+// Windows WSABUF with POSIX field names
+struct WindowsIOVec
+{
+ // POSIX iovec has iov_base then iov_len, WSABUF in Windows has the fields in reverse order
+ u_long iov_len; // Number of bytes to transfer
+ char FAR* iov_base; // Starting address
+};
+
+inline ssize_t writev(int fd, const WindowsIOVec* iov, int count)
+{
+ DWORD sent;
+ int ret = WSASend(fd, reinterpret_cast<LPWSABUF>(const_cast<WindowsIOVec*>(iov)), count, &sent, 0, NULL, NULL);
+ if (ret == 0)
+ return sent;
+ return -1;
+}