From 87076072135f04bcd4d068af96368f4939c5404e Mon Sep 17 00:00:00 2001 From: "Kevin L. Mitchell" Date: Sun, 10 Dec 2000 00:43:35 +0000 Subject: [PATCH] Author: Kev 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 --- ChangeLog | 30 ++++++++++++++++++++++++++++++ include/ircd_osdep.h | 3 +++ include/msgq.h | 3 ++- include/s_bsd.h | 3 ++- ircd/msgq.c | 8 +++++++- ircd/os_bsd.c | 33 +++++++++++++++++++++++++++++++++ ircd/os_generic.c | 33 +++++++++++++++++++++++++++++++++ ircd/os_linux.c | 41 +++++++++++++++++++++++++++++++++++++++++ ircd/os_solaris.c | 33 +++++++++++++++++++++++++++++++++ ircd/s_bsd.c | 8 +++++--- ircd/s_serv.c | 3 ++- ircd/send.c | 3 +-- 12 files changed, 192 insertions(+), 9 deletions(-) diff --git a/ChangeLog b/ChangeLog index c679dad..17c5028 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,35 @@ 2000-12-09 Kevin L. Mitchell + * 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 diff --git a/include/ircd_osdep.h b/include/ircd_osdep.h index db9b023..f991a41 100644 --- a/include/ircd_osdep.h +++ b/include/ircd_osdep.h @@ -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); diff --git a/include/msgq.h b/include/msgq.h index 8f3747c..a66e3fc 100644 --- a/include/msgq.h +++ b/include/msgq.h @@ -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); diff --git a/include/s_bsd.h b/include/s_bsd.h index dcada22..91bf9fa 100644 --- a/include/s_bsd.h +++ b/include/s_bsd.h @@ -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); diff --git a/ircd/msgq.c b/ircd/msgq.c index 3fd22a0..bc45233 100644 --- a/ircd/msgq.c +++ b/ircd/msgq.c @@ -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 */ diff --git a/ircd/os_bsd.c b/ircd/os_bsd.c index 09ce225..a4d3a9a 100644 --- a/ircd/os_bsd.c +++ b/ircd/os_bsd.c @@ -19,20 +19,25 @@ * $Id$ * */ +#define _XOPEN_SOURCE /* make limits.h #define IOV_MAX */ + #include "ircd_osdep.h" #include "config.h" +#include "msgq.h" #include #include #include #include #include +#include #include #include #include #include #include #include +#include #include #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))) { diff --git a/ircd/os_generic.c b/ircd/os_generic.c index 40d57d6..7e36564 100644 --- a/ircd/os_generic.c +++ b/ircd/os_generic.c @@ -19,12 +19,16 @@ * $Id$ * */ +#define _XOPEN_SOURCE /* make limits.h #define IOV_MAX */ + #include "ircd_osdep.h" #include "config.h" +#include "msgq.h" #include #include #include +#include #include #include #include @@ -33,6 +37,7 @@ #include #include #include +#include #if 0 #include @@ -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))) { diff --git a/ircd/os_linux.c b/ircd/os_linux.c index e3dc5e7..f48e552 100644 --- a/ircd/os_linux.c +++ b/ircd/os_linux.c @@ -19,11 +19,15 @@ * $Id$ * */ +#define _XOPEN_SOURCE /* make limits.h #define IOV_MAX */ + #include "ircd_osdep.h" +#include "msgq.h" #include #include #include +#include #include #include #include @@ -32,6 +36,7 @@ #include #include #include +#include #include #if 0 #include @@ -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) { diff --git a/ircd/os_solaris.c b/ircd/os_solaris.c index 7c67cd1..9c3c353 100644 --- a/ircd/os_solaris.c +++ b/ircd/os_solaris.c @@ -19,10 +19,14 @@ * $Id$ * */ +#define _XOPEN_SOURCE /* make limits.h #define IOV_MAX */ + #include "ircd_osdep.h" +#include "msgq.h" #include #include +#include #include #include #include @@ -32,6 +36,7 @@ #include #include #include +#include #include /* @@ -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))) { diff --git a/ircd/s_bsd.c b/ircd/s_bsd.c index 980fe0e..36cb7dc 100644 --- a/ircd/s_bsd.c +++ b/ircd/s_bsd.c @@ -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: diff --git a/ircd/s_serv.c b/ircd/s_serv.c index dab6bfb..aa02c73 100644 --- a/ircd/s_serv.c +++ b/ircd/s_serv.c @@ -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" diff --git a/ircd/send.c b/ircd/send.c index 96bd12b..95d35bb 100644 --- a/ircd/send.c +++ b/ircd/send.c @@ -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)) -- 2.20.1