Author: Kev <klmitch@mit.edu>
authorKevin L. Mitchell <klmitch@mit.edu>
Sun, 10 Dec 2000 00:43:35 +0000 (00:43 +0000)
committerKevin L. Mitchell <klmitch@mit.edu>
Sun, 10 Dec 2000 00:43:35 +0000 (00:43 +0000)
Log message:

Now we're using the struct iovec stuff.

Status: probably stable

Testing needed:

This patch makes some changes to some OS-specific code that I cannot test;
the new code needs to be compiled on several different platforms and a
report of any warnings or errors during compile-time or of any problems
under very heavy load needs to be made.  In making such reports, make sure
you report the system type (uname -a output), and also report the results
of "ls -l ircd/ircd_osdep.c"

Testing done:

It's been tested and seems to work under Linux 2.2.16-3.

git-svn-id: file:///home/klmitch/undernet-ircu/undernet-ircu-svn/ircu2/trunk@331 c9e4aea6-c8fd-4c43-8297-357d70d61c8c

12 files changed:
ChangeLog
include/ircd_osdep.h
include/msgq.h
include/s_bsd.h
ircd/msgq.c
ircd/os_bsd.c
ircd/os_generic.c
ircd/os_linux.c
ircd/os_solaris.c
ircd/s_bsd.c
ircd/s_serv.c
ircd/send.c

index c679dad68689caa9c255f110a736b02ffcf9eb3d..17c5028d7085061b6266b72acbafb00ead97f04a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,35 @@
 2000-12-09  Kevin L. Mitchell  <klmitch@mit.edu>
 
+       * ircd/send.c (send_queued): call deliver_it with appropriate
+       arguments
+
+       * ircd/s_serv.c: reorder a couple of headers--cosmetic
+
+       * ircd/s_bsd.c (deliver_it): make deliver_it work with a struct
+       MsgQ
+
+       * ircd/os_solaris.c (os_sendv_nonb): function for calling writev
+       with appropriate iovec
+
+       * ircd/os_linux.c (os_sendv_nonb): function for calling writev
+       with appropriate iovec
+
+       * ircd/os_generic.c (os_sendv_nonb): function for calling writev
+       with appropriate iovec
+
+       * ircd/os_bsd.c (os_sendv_nonb): function for calling writev with
+       appropriate iovec
+
+       * ircd/msgq.c (msgq_mapiov): add a len_p argument for totalling up
+       exactly how much we're trying to write out to the fd
+
+       * include/s_bsd.h: make deliver_it take a struct MsgQ
+
+       * include/msgq.h: add a len_p argument to msgq_mapiov to help
+       detect short writes that indicate possible socket blocking
+
+       * include/ircd_osdep.h: declare os_sendv_nonb()
+
        * ircd/channel.c (modebuf_mode): don't add empty modes...
 
 2000-12-08  Kevin L. Mitchell  <klmitch@mit.edu>
index db9b023df2bc00e6f2475852871284ac5fc584c5..f991a41ee66566c03ab53862bf2c82cdf39f6ba5 100644 (file)
@@ -8,6 +8,7 @@
 
 struct Client;
 struct sockaddr_in;
+struct MsgQ;
 
 typedef enum IOResult {
   IO_FAILURE = -1,
@@ -31,6 +32,8 @@ extern IOResult os_recv_nonb(int fd, char* buf, unsigned int length,
                         unsigned int* length_out);
 extern IOResult os_send_nonb(int fd, const char* buf, unsigned int length,
                         unsigned int* length_out);
+extern IOResult os_sendv_nonb(int fd, struct MsgQ* buf,
+                             unsigned int* len_in, unsigned int* len_out);
 extern IOResult os_recvfrom_nonb(int fd, char* buf, unsigned int len,
                                  unsigned int* length_out,
                                  struct sockaddr_in* from_out);
index 8f3747c649e261f4b8898484ad0b5dea137e3dfc..a66e3fc6020e40356fdaca8b6680cadc5331e9c2 100644 (file)
@@ -84,7 +84,8 @@ struct MsgQ {
 extern void msgq_init(struct MsgQ *mq);
 extern void msgq_delete(struct MsgQ *mq, unsigned int length);
 extern const char *msgq_map(const struct MsgQ *mq, unsigned int *length_p);
-extern int msgq_mapiov(const struct MsgQ *mq, struct iovec *iov, int count);
+extern int msgq_mapiov(const struct MsgQ *mq, struct iovec *iov, int count,
+                      unsigned int *len);
 extern struct MsgBuf *msgq_make(struct Client *dest, const char *format, ...);
 extern struct MsgBuf *msgq_vmake(struct Client *dest, const char *format,
                                 va_list args);
index dcada222a06cf7cd1f9c507fd898c9899ffd338c..91bf9fa12dc13fffd9c855938914a40e6a95e7e2 100644 (file)
@@ -21,6 +21,7 @@ struct Client;
 struct ConfItem;
 struct Listener;
 struct DNSReply;
+struct MsgQ;
 
 /*
  * TCP window sizes
@@ -78,7 +79,7 @@ struct Pollable {
 /*
  * Proto types
  */
-extern unsigned int deliver_it(struct Client *cptr, const char *str, unsigned int len);
+extern unsigned int deliver_it(struct Client *cptr, struct MsgQ *buf);
 extern int connect_server(struct ConfItem* aconf, struct Client* by,
                           struct DNSReply* reply);
 extern void release_dns_reply(struct Client* cptr);
index 3fd22a06621ecf02e2a8aa2408cf525c0e80f0dc..bc45233bbd6e730ea128d125090a5d10ab2d43d0 100644 (file)
@@ -168,7 +168,8 @@ msgq_map(const struct MsgQ *mq, unsigned int *length_p)
  * struct iovec's.
  */
 int
-msgq_mapiov(const struct MsgQ *mq, struct iovec *iov, int count)
+msgq_mapiov(const struct MsgQ *mq, struct iovec *iov, int count,
+           unsigned int *len)
 {
   struct Msg *queue;
   struct Msg *prio;
@@ -177,6 +178,7 @@ msgq_mapiov(const struct MsgQ *mq, struct iovec *iov, int count)
   assert(0 != mq);
   assert(0 != iov);
   assert(0 != count);
+  assert(0 != len);
 
   if (mq->length <= 0) /* no data to map */
     return 0;
@@ -184,6 +186,7 @@ msgq_mapiov(const struct MsgQ *mq, struct iovec *iov, int count)
   if (mq->queue.head && mq->queue.head->sent > 0) { /* partial msg on norm q */
     iov[i].iov_base = mq->queue.head->msg->msg + mq->queue.head->sent;
     iov[i].iov_len = mq->queue.head->msg->length - mq->queue.head->sent;
+    *len += iov[i].iov_len;
 
     queue = mq->queue.head->next; /* where we start later... */
 
@@ -196,6 +199,7 @@ msgq_mapiov(const struct MsgQ *mq, struct iovec *iov, int count)
   if (mq->prio.head && mq->prio.head->sent > 0) { /* partial msg on prio q */
     iov[i].iov_base = mq->prio.head->msg->msg + mq->prio.head->sent;
     iov[i].iov_len = mq->prio.head->msg->length - mq->prio.head->sent;
+    *len += iov[i].iov_len;
 
     prio = mq->prio.head->next; /* where we start later... */
 
@@ -208,6 +212,7 @@ msgq_mapiov(const struct MsgQ *mq, struct iovec *iov, int count)
   for (; prio; prio = prio->next) { /* go through prio queue */
     iov[i].iov_base = prio->msg->msg; /* store message */
     iov[i].iov_len = prio->msg->length;
+    *len += iov[i].iov_len;
 
     i++; /* filled an iovec... */
     if (!--count) /* check for space */
@@ -217,6 +222,7 @@ msgq_mapiov(const struct MsgQ *mq, struct iovec *iov, int count)
   for (; queue; queue = queue->next) { /* go through normal queue */
     iov[i].iov_base = queue->msg->msg;
     iov[i].iov_len = queue->msg->length;
+    *len += iov[i].iov_len;
 
     i++; /* filled an iovec... */
     if (!--count) /* check for space */
index 09ce225fb7902434794a04f8994806fc2a9eef63..a4d3a9ae3d7a84424d83667833f023a0cb2993f3 100644 (file)
  * $Id$
  *
  */
+#define _XOPEN_SOURCE  /* make limits.h #define IOV_MAX */
+
 #include "ircd_osdep.h"
 #include "config.h"
+#include "msgq.h"
 
 #include <assert.h>
 #include <sys/types.h>
 #include <sys/time.h>
 #include <sys/resource.h>
 #include <errno.h>
+#include <limits.h>
 #include <fcntl.h>
 #include <netinet/in.h>
 #include <stdio.h>
 #include <string.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
+#include <sys/uio.h>
 #include <unistd.h>
 
 #ifdef HPUX
@@ -315,6 +320,34 @@ IOResult os_send_nonb(int fd, const char* buf, unsigned int length,
   return IO_FAILURE;
 }
 
+IOResult os_sendv_nonb(int fd, struct MsgQ* buf, unsigned int* count_in,
+                      unsigned int* count_out)
+{
+  int res;
+  int count;
+  struct iovec iov[IOV_MAX];
+
+  assert(0 != buf);
+  assert(0 != count_in);
+  assert(0 != count_out);
+
+  *count_in = 0;
+  *count_out = 0;
+  errno = 0;
+
+  count = msgq_mapiov(buf, iov, IOV_MAX, count_in);
+
+  if (-1 < (res = writev(fd, iov, count))) {
+    *count_out = (unsigned) res;
+    return IO_SUCCESS;
+  }
+  else if (EWOULDBLOCK == errno || EAGAIN == errno ||
+          ENOMEM == errno || ENOBUFS == errno)
+    return IO_BLOCKED;
+
+  return IO_FAILURE;
+}
+
 int os_connect_nonb(int fd, const struct sockaddr_in* sin)
 {
   if (connect(fd, (struct sockaddr*) sin, sizeof(struct sockaddr_in))) {
index 40d57d6442219d7740a81384b946cc3859249681..7e36564125fe8b2efd0dcb52ae46147603b796b4 100644 (file)
  * $Id$
  *
  */
+#define _XOPEN_SOURCE  /* make limits.h #define IOV_MAX */
+
 #include "ircd_osdep.h"
 #include "config.h"
+#include "msgq.h"
 
 #include <assert.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <limits.h>
 #include <netinet/in.h>
 #include <stdio.h>
 #include <string.h>
@@ -33,6 +37,7 @@
 #include <sys/resource.h>
 #include <sys/socket.h>
 #include <sys/time.h>
+#include <sys/uio.h>
 
 #if 0
 #include <unistd.h>
@@ -317,6 +322,34 @@ IOResult os_send_nonb(int fd, const char* buf, unsigned int length,
   return IO_FAILURE;
 }
 
+IOResult os_sendv_nonb(int fd, struct MsgQ* buf, unsigned int* count_in,
+                      unsigned int* count_out)
+{
+  int res;
+  int count;
+  struct iovec iov[IOV_MAX];
+
+  assert(0 != buf);
+  assert(0 != count_in);
+  assert(0 != count_out);
+
+  *count_in = 0;
+  *count_out = 0;
+  errno = 0;
+
+  count = msgq_mapiov(buf, iov, IOV_MAX, count_in);
+
+  if (-1 < (res = writev(fd, iov, count))) {
+    *count_out = (unsigned) res;
+    return IO_SUCCESS;
+  }
+  else if (EWOULDBLOCK == errno || EAGAIN == errno ||
+          ENOMEM == errno || ENOBUFS == errno)
+    return IO_BLOCKED;
+
+  return IO_FAILURE;
+}
+
 int os_connect_nonb(int fd, const struct sockaddr_in* sin)
 {
   if (connect(fd, (struct sockaddr*) sin, sizeof(struct sockaddr_in))) {
index e3dc5e7d616d6b5de099382cb23e431433ea63f0..f48e552ce1b9be5b2f53207d8c3bc97008b6b533 100644 (file)
  * $Id$
  *
  */
+#define _XOPEN_SOURCE  /* make limits.h #define IOV_MAX */
+
 #include "ircd_osdep.h"
+#include "msgq.h"
 
 #include <assert.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <limits.h>
 #include <stdio.h>
 #include <netinet/in.h>
 #include <string.h>
@@ -32,6 +36,7 @@
 #include <sys/socket.h>
 #include <sys/types.h>
 #include <sys/times.h>
+#include <sys/uio.h>
 #include <sys/param.h>
 #if 0
 #include <unistd.h>
@@ -253,6 +258,42 @@ IOResult os_send_nonb(int fd, const char* buf, unsigned int length,
   return IO_FAILURE;
 }
 
+/*
+ * os_sendv_nonb - non blocking writev to a connection
+ * returns:
+ *  1  if data was written
+ *    count_out contains amount written
+ *   
+ *  0  if write call blocked, recoverable error
+ *  -1 if an unrecoverable error occurred
+ */
+IOResult os_sendv_nonb(int fd, struct MsgQ* buf, unsigned int* count_in,
+                      unsigned int* count_out)
+{
+  int res;
+  int count;
+  struct iovec iov[IOV_MAX];
+
+  assert(0 != buf);
+  assert(0 != count_in);
+  assert(0 != count_out);
+
+  *count_in = 0;
+  *count_out = 0;
+  errno = 0;
+
+  count = msgq_mapiov(buf, iov, IOV_MAX, count_in);
+
+  if (-1 < (res = writev(fd, iov, count))) {
+    *count_out = (unsigned) res;
+    return IO_SUCCESS;
+  }
+  else if (EAGAIN == errno || ENOMEM == errno || ENOBUFS == errno)
+    return IO_BLOCKED;
+
+  return IO_FAILURE;
+}
+
 
 int os_connect_nonb(int fd, const struct sockaddr_in* sin)
 {
index 7c67cd1395cffbf0269382776a404307142f21fb..9c3c35387205656eece9a1340e4805a27c02047c 100644 (file)
  * $Id$
  *
  */
+#define _XOPEN_SOURCE  /* make limits.h #define IOV_MAX */
+
 #include "ircd_osdep.h"
+#include "msgq.h"
 
 #include <assert.h>
 #include <errno.h>
+#include <limits.h>
 #include <netinet/in.h>
 #include <stdio.h>
 #include <string.h>
@@ -32,6 +36,7 @@
 #include <sys/resource.h>
 #include <sys/socket.h>
 #include <sys/types.h>
+#include <sys/uio.h>
 #include <unistd.h>
 
 /*
@@ -214,6 +219,34 @@ IOResult os_send_nonb(int fd, const char* buf, unsigned int length,
   return IO_FAILURE;
 }
 
+IOResult os_sendv_nonb(int fd, struct MsgQ* buf, unsigned int* count_in,
+                      unsigned int* count_out)
+{
+  int res;
+  int count;
+  struct iovec iov[IOV_MAX];
+
+  assert(0 != buf);
+  assert(0 != count_in);
+  assert(0 != count_out);
+
+  *count_in = 0;
+  *count_out = 0;
+  errno = 0;
+
+  count = msgq_mapiov(buf, iov, IOV_MAX, count_in);
+
+  if (-1 < (res = writev(fd, iov, count))) {
+    *count_out = (unsigned) res;
+    return IO_SUCCESS;
+  }
+  else if (EAGAIN == errno || ENOBUFS == errno ||
+          ENOMEM == errno || ENOSR == errno)
+    return IO_BLOCKED;
+
+  return IO_FAILURE;
+}
+
 int os_connect_nonb(int fd, const struct sockaddr_in* sin)
 {
   if (connect(fd, (struct sockaddr*) sin, sizeof(struct sockaddr_in))) {
index 980fe0e614ee90df7ac360e74d0ea4e9703ac33f..36cb7dcfac930933a31ebbd94329185e75a2c8e5 100644 (file)
@@ -33,6 +33,7 @@
 #include "list.h"
 #include "listener.h"
 #include "msg.h"
+#include "msgq.h"
 #include "numeric.h"
 #include "numnicks.h"
 #include "packet.h"
@@ -327,12 +328,13 @@ static int connect_inet(struct ConfItem* aconf, struct Client* cptr)
  *      net.loads today anyway. Commented out the alarms to save cpu.
  *      --Run
  */
-unsigned int deliver_it(struct Client *cptr, const char *str, unsigned int len)
+unsigned int deliver_it(struct Client *cptr, struct MsgQ *buf)
 {
   unsigned int bytes_written = 0;
+  unsigned int bytes_count = 0;
   assert(0 != cptr);
 
-  switch (os_send_nonb(cptr->fd, str, len, &bytes_written)) {
+  switch (os_sendv_nonb(cptr->fd, buf, &bytes_count, &bytes_written)) {
   case IO_SUCCESS:
     cptr->flags &= ~FLAGS_BLOCKED;
 
@@ -350,7 +352,7 @@ unsigned int deliver_it(struct Client *cptr, const char *str, unsigned int len)
      * XXX - hrmm.. set blocked here? the socket didn't
      * say it was blocked
      */
-    if (bytes_written < len)
+    if (bytes_written < bytes_count)
       cptr->flags |= FLAGS_BLOCKED;
     break;
   case IO_BLOCKED:
index dab6bfb5decc0f8e94fbe34d3f79ca451dee88cd..aa02c73e43a5e9865aae4ada2c6b54c34304d600 100644 (file)
@@ -36,8 +36,9 @@
 #include "ircd_xopen.h"
 #include "jupe.h"
 #include "list.h"
-#include "msg.h"
 #include "match.h"
+#include "msg.h"
+#include "msgq.h"
 #include "numeric.h"
 #include "numnicks.h"
 #include "parse.h"
index 96bd12b3b1d5246b86068417d916aaec1bc5b13b..95d35bbba958cfdfe485e754dd0f5cfeccb54b18 100644 (file)
@@ -148,9 +148,8 @@ void send_queued(struct Client *to)
 
   while (MsgQLength(&to->sendQ) > 0) {
     unsigned int len;
-    const char* msg = msgq_map(&to->sendQ, &len);
 
-    if ((len = deliver_it(to, msg, len))) {
+    if ((len = deliver_it(to, &to->sendQ))) {
       msgq_delete(&to->sendQ, len);
       to->lastsq = MsgQLength(&to->sendQ) / 1024;
       if (IsBlocked(to))