+int SocketEngine::RecvFrom(EventHandler* fd, void *buf, size_t len, int flags, sockaddr *from, socklen_t *fromlen)
+{
+ int nbRecvd = recvfrom(fd->GetFd(), (char*)buf, len, flags, from, fromlen);
+ if (nbRecvd > 0)
+ stats.Update(nbRecvd, 0);
+ return nbRecvd;
+}
+
+int SocketEngine::Send(EventHandler* fd, const void *buf, size_t len, int flags)
+{
+ int nbSent = send(fd->GetFd(), (const char*)buf, len, flags);
+ if (nbSent > 0)
+ stats.Update(0, nbSent);
+ return nbSent;
+}
+
+int SocketEngine::Recv(EventHandler* fd, void *buf, size_t len, int flags)
+{
+ int nbRecvd = recv(fd->GetFd(), (char*)buf, len, flags);
+ if (nbRecvd > 0)
+ stats.Update(nbRecvd, 0);
+ return nbRecvd;
+}
+
+int SocketEngine::SendTo(EventHandler* fd, const void *buf, size_t len, int flags, const sockaddr *to, socklen_t tolen)
+{
+ int nbSent = sendto(fd->GetFd(), (const char*)buf, len, flags, to, tolen);
+ if (nbSent > 0)
+ stats.Update(0, nbSent);
+ 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);
+#ifdef _WIN32
+ if ((ret == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK))
+ errno = EINPROGRESS;
+#endif
+ return ret;
+}
+
+int SocketEngine::Shutdown(EventHandler* fd, int how)
+{
+ return shutdown(fd->GetFd(), how);
+}
+
+int SocketEngine::Bind(int fd, const irc::sockets::sockaddrs& addr)
+{
+ return bind(fd, &addr.sa, addr.sa_size());
+}
+
+int SocketEngine::Listen(int sockfd, int backlog)
+{
+ return listen(sockfd, backlog);
+}
+
+int SocketEngine::Shutdown(int fd, int how)
+{
+ return shutdown(fd, how);
+}
+
+void SocketEngine::Statistics::Update(size_t len_in, size_t len_out)
+{
+ CheckFlush();
+ indata += len_in;
+ outdata += len_out;
+}
+
+void SocketEngine::Statistics::CheckFlush() const
+{
+ // Reset the in/out byte counters if it has been more than a second
+ time_t now = ServerInstance->Time();
+ if (lastempty != now)
+ {
+ lastempty = now;
+ indata = outdata = 0;
+ }
+}
+
+void SocketEngine::Statistics::GetBandwidth(float& kbitpersec_in, float& kbitpersec_out, float& kbitpersec_total) const
+{
+ CheckFlush();
+ float in_kbit = indata * 8;
+ float out_kbit = outdata * 8;
+ kbitpersec_total = ((in_kbit + out_kbit) / 1024);
+ kbitpersec_in = in_kbit / 1024;
+ kbitpersec_out = out_kbit / 1024;
+}
+
+std::string SocketEngine::LastError()
+{
+#ifndef _WIN32
+ return strerror(errno);
+#else
+ char szErrorString[500];
+ DWORD dwErrorCode = WSAGetLastError();
+ if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)szErrorString, _countof(szErrorString), NULL) == 0)
+ sprintf_s(szErrorString, _countof(szErrorString), "Error code: %u", dwErrorCode);
+
+ std::string::size_type p;
+ std::string ret = szErrorString;
+ while ((p = ret.find_last_of("\r\n")) != std::string::npos)
+ ret.erase(p, 1);
+
+ return ret;
+#endif
+}
+
+std::string SocketEngine::GetError(int errnum)
+{
+#ifndef _WIN32
+ return strerror(errnum);
+#else
+ WSASetLastError(errnum);
+ return LastError();
+#endif
+}