]> git.netwichtig.de Git - user/henk/code/inspircd.git/commitdiff
Merge branch 'master+writev'
authorAttila Molnar <attilamolnar@hush.com>
Fri, 6 Mar 2015 17:04:13 +0000 (18:04 +0100)
committerAttila Molnar <attilamolnar@hush.com>
Fri, 6 Mar 2015 17:04:13 +0000 (18:04 +0100)
include/socketengine.h
src/inspsocket.cpp
src/socketengine.cpp
win/inspircd_win32wrapper.h

index 895457b89191034666b11ba9bcc89dce367c4882..f30289913b8b929008c08281e02c57cc12759e11 100644 (file)
 #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.
index ee5287e5f33888e0cd24b46f0ce68979cf2d33f9..2646e265f0f610707b824768f76b84f432beb13e 100644 (file)
 #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)
index 1c91ccdea0c37f52d6cb5d1ac2c8469bd79004aa..eadfc73d3e7b1bebdfb28afdc3304180d095d814 100644 (file)
@@ -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);
index a19bdf857a2f18d09ced8235d449a3f8d0cf14c1..2218d930063d0d42aa40620a5f58679e511905b3 100644 (file)
@@ -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;
+}