[BACK]Return to NetConnection.c++ CVS log [TXT][DIR] Up to [Development] / fam / fam

Annotation of fam/fam/NetConnection.c++, Revision 1.1

1.1     ! trev        1: //  Copyright (C) 1999 Silicon Graphics, Inc.  All Rights Reserved.
        !             2: //
        !             3: //  This program is free software; you can redistribute it and/or modify it
        !             4: //  under the terms of version 2 of the GNU General Public License as
        !             5: //  published by the Free Software Foundation.
        !             6: //
        !             7: //  This program is distributed in the hope that it would be useful, but
        !             8: //  WITHOUT ANY WARRANTY; without even the implied warranty of
        !             9: //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  Further, any
        !            10: //  license provided herein, whether implied or otherwise, is limited to
        !            11: //  this program in accordance with the express provisions of the GNU
        !            12: //  General Public License.  Patent licenses, if any, provided herein do not
        !            13: //  apply to combinations of this program with other product or programs, or
        !            14: //  any other product whatsoever.  This program is distributed without any
        !            15: //  warranty that the program is delivered free of the rightful claim of any
        !            16: //  third person by way of infringement or the like.  See the GNU General
        !            17: //  Public License for more details.
        !            18: //
        !            19: //  You should have received a copy of the GNU General Public License along
        !            20: //  with this program; if not, write the Free Software Foundation, Inc., 59
        !            21: //  Temple Place - Suite 330, Boston MA 02111-1307, USA.
        !            22:
        !            23: #include "NetConnection.h"
        !            24:
        !            25: #include <assert.h>
        !            26: #include <errno.h>
        !            27: #include <stdarg.h>
        !            28: #include <stddef.h>
        !            29: #include <stdio.h>
        !            30: #include <string.h>
        !            31: #include <sys/ioctl.h>
        !            32: #include <sys/socket.h>
        !            33: #include <unistd.h>
        !            34: #include <netinet/in.h>
        !            35:
        !            36: #include "Log.h"
        !            37: #include "Scheduler.h"
        !            38:
        !            39: NetConnection::NetConnection(int a_fd,
        !            40: 			     UnblockHandler uhandler, void *uclosure)
        !            41:     : fd(a_fd),
        !            42:       iready(true), oready(true),
        !            43:       iend(ibuf + sizeof(ibuf)),
        !            44:       itail(ibuf),
        !            45:       unblock_handler(uhandler), closure(uclosure)
        !            46: {
        !            47:     // It must be the case that Length is a 32 bit int.
        !            48:     assert (sizeof(Length) == 4);
        !            49:
        !            50:     omsgList = omsgListTail = NULL;
        !            51:
        !            52:     // Enable nonblocking output on socket.
        !            53:
        !            54:     int yes = 1;
        !            55:     if (ioctl(fd, FIONBIO, &yes) < 0)
        !            56:     {   Log::perror("can't set NBIO on fd %d", fd);
        !            57: 	shutdown(false);
        !            58: 	return;
        !            59:     }
        !            60:
        !            61: #ifdef TINY_BUFFERS			/* This kills throughput. */
        !            62:
        !            63:     // Reduce kernel's send and receive buffer sizes.  Useful for debugging
        !            64:     // flow control.
        !            65:
        !            66:     if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &osize, sizeof osize))
        !            67: 	Log::perror("setsockopt(%d, SO_SNDBUF)", fd);
        !            68:     if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &isize, sizeof isize))
        !            69: 	Log::perror("setsockopt(%d, SO_RCVBUF)", fd);
        !            70:
        !            71: #endif /* !TINY_BUFFERS */
        !            72:
        !            73:     // Wait for something to read.
        !            74:
        !            75:     (void) Scheduler::install_read_handler(fd, read_handler, this);
        !            76: }
        !            77:
        !            78: NetConnection::~NetConnection()
        !            79: {
        !            80:     shutdown(false);
        !            81: }
        !            82:
        !            83: void
        !            84: NetConnection::shutdown(bool call_input)
        !            85: {
        !            86:     if (fd >= 0)
        !            87:     {
        !            88:         Log::info("Shutting down connection");
        !            89: 	Scheduler::IOHandler oldh;
        !            90: 	if (iready && oready)
        !            91: 	{   oldh = Scheduler::remove_read_handler(fd);
        !            92: 	    assert(oldh == read_handler);
        !            93: 	}
        !            94: 	if (!oready)
        !            95: 	{   oldh = Scheduler::remove_write_handler(fd);
        !            96: 	    assert(oldh == write_handler);
        !            97: 	}
        !            98: 	(void) close(fd);
        !            99: 	fd = -1;
        !           100: 	oready = true;
        !           101: 	if (call_input)
        !           102: 	    input_msg(NULL, 0);
        !           103:     }
        !           104: }
        !           105:
        !           106: ///////////////////////////////////////////////////////////////////////////////
        !           107: //  Input
        !           108:
        !           109: void
        !           110: NetConnection::read_handler(int fd, void *closure)
        !           111: {
        !           112:     NetConnection *connection = (NetConnection *) closure;
        !           113:     assert(fd == connection->fd);
        !           114:     connection->input();
        !           115: }
        !           116:
        !           117: void
        !           118: NetConnection::input()
        !           119: {
        !           120:     if (fd < 0)
        !           121: 	return;
        !           122:
        !           123:     // Read from socket.
        !           124:
        !           125:     assert(itail < iend);
        !           126:     int maxbytes = iend - itail;
        !           127:     int ret = recv(fd, itail, maxbytes, 0);
        !           128:     if (ret < 0)
        !           129:     {   if (errno != EAGAIN && errno != ECONNRESET)
        !           130: 	{   Log::perror("fd %d read error", fd);
        !           131: 	    shutdown();
        !           132: 	}
        !           133: 	return;
        !           134:     }
        !           135:     else if (ret == 0)
        !           136:     {   shutdown();
        !           137: 	return;
        !           138:     }
        !           139:     else // (ret > 0)
        !           140:     {
        !           141: 	itail += ret;
        !           142:     }
        !           143:
        !           144:     deliver_input();
        !           145: }
        !           146:
        !           147: void
        !           148: NetConnection::deliver_input()
        !           149: {
        !           150:     // Find messages and process them.
        !           151:
        !           152:     char *ihead = ibuf;
        !           153:     while (iready && oready && ihead + sizeof (Length) <= itail)
        !           154:     {
        !           155:         Length len;
        !           156:         memcpy(&len, ihead, sizeof(Length));
        !           157: 	len = ntohl(len);
        !           158:
        !           159: 	if (len > MAXMSGSIZE)
        !           160: 	{   Log::error("fd %d message length %d bytes exceeds max of %d.",
        !           161: 		       fd, len, MAXMSGSIZE);
        !           162: 	    shutdown();
        !           163: 	    return;
        !           164: 	}
        !           165: 	if (ihead + sizeof (Length) + len > itail)
        !           166: 	    break;
        !           167:
        !           168: 	// Call the message reader.
        !           169:
        !           170: 	if (input_msg(ihead + sizeof (Length), len) == false) {
        !           171:             // if input_msg sees an error in the message and thinks
        !           172:             // the connection should be closed, it will return false.
        !           173:             shutdown();
        !           174:             return;
        !           175:         }
        !           176:
        !           177: 	ihead += sizeof (Length) + len;
        !           178:     }
        !           179:
        !           180:     // If data remain in buffer, slide them to the left.
        !           181:
        !           182:     assert(ihead <= itail);
        !           183:     int remaining = itail - ihead;
        !           184:     if (remaining && ihead != ibuf)
        !           185: 	memmove(ibuf, ihead, remaining);
        !           186:     itail = ibuf + remaining;
        !           187:     assert(itail < iend);
        !           188: }
        !           189:
        !           190: bool
        !           191: NetConnection::ready_for_output() const
        !           192: {
        !           193:     return oready;
        !           194: }
        !           195:
        !           196: void
        !           197: NetConnection::ready_for_input(bool tf)
        !           198: {
        !           199:     set_handlers(tf, oready);
        !           200: }
        !           201:
        !           202: ///////////////////////////////////////////////////////////////////////////////
        !           203: //  Output
        !           204:
        !           205: void
        !           206: NetConnection::mprintf(const char *format, ...)
        !           207: {
        !           208:     if (fd < 0)
        !           209: 	return;				// if closed, do nothing.
        !           210:
        !           211:     va_list args;
        !           212:     va_start(args, format);
        !           213:
        !           214:     msgList_t * msg = new msgList_t;
        !           215:     msg->next = NULL;
        !           216:     Length len = vsnprintf(
        !           217:         msg->msg + 4, MAXMSGSIZE + 1, format, args) + 1;
        !           218:     va_end(args);
        !           219:
        !           220:     if (len <= 0 || len == MAXMSGSIZE+1) {
        !           221:         Log::error("tried to write a message that was too big");
        !           222:         assert(0);
        !           223:         // protocol botch.  Don't send the message.
        !           224:         return;
        !           225:     }
        !           226:
        !           227:     if (omsgListTail) {
        !           228:         omsgListTail = omsgListTail->next = msg;
        !           229:     } else {
        !           230:         omsgList = omsgListTail = msg;
        !           231:     }
        !           232:     msg->len = 4 + len;
        !           233:
        !           234:     len = htonl(len);
        !           235:     memcpy(msg->msg, &len, 4);
        !           236:     flush();
        !           237: }
        !           238:
        !           239: void
        !           240: NetConnection::flush()
        !           241: {
        !           242:     while (omsgList)
        !           243:     {
        !           244: 	int ret = send(fd, omsgList->msg, omsgList->len, 0);
        !           245:         if (ret < 0 && errno == EWOULDBLOCK)
        !           246:         {
        !           247:             break;
        !           248:         } else
        !           249:         {
        !           250:             if (ret >= 0)
        !           251:             {
        !           252:                 assert(ret == omsgList->len);
        !           253:             } else
        !           254:             {
        !           255:                 /* Since the client library can close it's fd before
        !           256:                  * getting acks from all FAMCancelMonitor requests we
        !           257:                  * may get a broken pipe error here when writing the ack.
        !           258:                  * Don't threat this as an error, since that fills the logs
        !           259:                  * with crap.
        !           260:                  */
        !           261:                 if (errno == EPIPE)
        !           262:                 {
        !           263:                     Log::debug("fd %d write error: %m", fd);
        !           264:                 } else
        !           265:                 {
        !           266:                     Log::error("fd %d write error: %m", fd);
        !           267:                 }
        !           268:             }
        !           269:             msgList_t *oldHead = omsgList;
        !           270:             omsgList = omsgList->next;
        !           271:             if (omsgListTail == oldHead) {
        !           272:                 omsgListTail = NULL;
        !           273:             }
        !           274:             delete oldHead;
        !           275: 	}
        !           276:     }
        !           277:     set_handlers(iready, !omsgList);
        !           278: }
        !           279:
        !           280: void
        !           281: NetConnection::set_handlers(bool new_iready, bool new_oready)
        !           282: {
        !           283:     Scheduler::IOHandler oldh;
        !           284:     bool call_unblock = false;
        !           285:
        !           286:     if (oready != new_oready)
        !           287:     {   if (new_oready)
        !           288: 	{   oldh = Scheduler::remove_write_handler(fd);
        !           289: 	    assert(oldh == write_handler);
        !           290: 	    call_unblock = true;
        !           291: 	}
        !           292: 	else
        !           293: 	{   oldh = Scheduler::install_write_handler(fd, write_handler, this);
        !           294: 	    assert(oldh == NULL);
        !           295: 	}
        !           296:     }
        !           297:
        !           298:     //  Install read_handler iff iready && oready.
        !           299:
        !           300:     if ((iready && oready) != (new_iready && new_oready))
        !           301:     {
        !           302: 	if (new_iready && new_oready)
        !           303: 	{   oldh = Scheduler::install_read_handler(fd, read_handler, this);
        !           304: 	    assert(oldh == NULL);
        !           305: 	}
        !           306: 	else
        !           307: 	{   oldh = Scheduler::remove_read_handler(fd);
        !           308: 	    assert(oldh == read_handler);
        !           309: 	}
        !           310:     }
        !           311:     bool old_iready = iready;
        !           312:     iready = new_iready;
        !           313:     oready = new_oready;
        !           314:
        !           315:     //  If we unblocked output, call the unblock handler.
        !           316:     //  If there's input to deliver, deliver it.
        !           317:
        !           318:     if (call_unblock && unblock_handler)
        !           319:     {   assert(!iready || old_iready);
        !           320: 	(*unblock_handler)(closure);
        !           321:     }
        !           322:     else if (iready && !old_iready)
        !           323: 	deliver_input();
        !           324: }
        !           325:
        !           326: void
        !           327: NetConnection::write_handler(int fd, void *closure)
        !           328: {
        !           329:     NetConnection *connection = (NetConnection *) closure;
        !           330:     assert(connection->fd == fd);
        !           331:     connection->flush();
        !           332: }
        !           333:

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>