⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fifo.c++

📁 fax相关的东西
💻 C++
字号:
/*	$Id: FIFO.c++,v 1.5 2005/05/30 14:52:33 tim Exp $ *//* * Copyright (c) 1990-1996 Sam Leffler * Copyright (c) 1991-1996 Silicon Graphics, Inc. * HylaFAX is a trademark of Silicon Graphics * * Permission to use, copy, modify, distribute, and sell this software and  * its documentation for any purpose is hereby granted without fee, provided * that (i) the above copyright notices and this permission notice appear in * all copies of the software and related documentation, and (ii) the names of * Sam Leffler and Silicon Graphics may not be used in any advertising or * publicity relating to the software without the specific, prior written * permission of Sam Leffler and Silicon Graphics. *  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.   *  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE  * OF THIS SOFTWARE. */#include "port.h"#include "Sys.h"#include "config.h"#include "HylaFAXServer.h"#include "Dispatcher.h"/* * Support for communication with the HylaFAX queuer via FIFO's. *//* * Create the client FIFO and open it for use. */boolHylaFAXServer::initClientFIFO(fxStr& emsg){    clientFIFOName = fxStr::format(FAX_CLIENTDIR "/%u", getpid());    if (Sys::mkfifo(clientFIFOName, 0622) < 0 && errno != EEXIST) {	emsg = fxStr::format("Could not create %s: %s",	    (const char*) clientFIFOName, strerror(errno));	return (false);    }    clientFd = Sys::open(clientFIFOName, CONFIG_OPENFIFO|O_NDELAY);    if (clientFd == -1) {	emsg = fxStr::format("Could not open FIFO file %s: %s",	    (const char*) clientFIFOName, strerror(errno));	return (false);    }    if (!Sys::isFIFOFile(clientFd)) {	emsg = clientFIFOName | " is not a FIFO special file";	return (false);    }    // open should set O_NDELAY, but just to be sure...    if (fcntl(clientFd, F_SETFL, fcntl(clientFd, F_GETFL, 0) | O_NDELAY) < 0)	logError("initClientFIFO %s: fcntl: %m", (const char*) clientFIFOName);    Dispatcher::instance().link(clientFd, Dispatcher::ReadMask, this);    return (true);}/* * Respond to input on a FIFO file descriptor. */intHylaFAXServer::FIFOInput(int fd){    char buf[2048];    int cc;    while ((cc = Sys::read(fd, buf, sizeof (buf)-1)) > 0) {	if (cc == sizeof(buf)-1)	    logWarning("FIFO Read full: %d", cc);	buf[cc] = '\0';	char* bp = &buf[0];	do {	    if (bp[0] == '!') {		/*		 * This is an event message from the scheduler		 * generated by a previously registered trigger.		 * Setup the unpacking work and dispatch it.		 */		TriggerMsgHeader h;		u_int left = &buf[cc]-bp;		bool needy = false;		if (left < sizeof(TriggerMsgHeader))		{		    needy = true;		} else		{		    memcpy(&h, bp, sizeof (h));		// copy to align fields		    if (left < h.length)			needy = true;		}		if (needy)		{		    /*		     * Handle the case where the buffer was read full.  This means that		     * we have a "partial" message at the end of buf, and the rest in		     * the FIFO.		     *		     * buf[n] is NEVER read from the file, it's always 1-past.  If we		     * have reached buf[n], we know we are past the read data.		     *		     * We have (left) bytes of the message at the end of the buf.		     * We move them to the front, and read as much more as we can to		     * fill buf back up, leaving it in the same state as if this was		     * the initial read.		     */		    memmove(buf, bp, left);		    cc = Sys::read(fd, buf+left, (sizeof(buf)-1) - left) + left;		    buf[cc] = '\0';		    bp = &buf[0];		} else {		    triggerEvent(h, bp+sizeof (h));		    bp += h.length;		}	    } else {		/*		 * Break up '\0'-separated records and strip		 * any trailing '\n' so that "echo mumble>FIFO"		 * works (i.e. echo appends a '\n' character).		 */		char* cp = strchr(bp, '\0');		/*		 * Handle the case where the buffer was read full.  This means that		 * we have a "partial" message at the end of buf, and the rest in		 * the FIFO.		 *		 * buf[n] is NEVER read from the file, it's always 1-past.  If we		 * have reached buf[n], we know we are past the read data.		 *		 * We have (cp - bp) bytes of the message at the end of the buf.		 * We move them to the front, and read as much more as we can to		 * fill buf back up, leaving it in the same state as if this was		 * the initial read.		 */		if (cp == &buf[sizeof(buf)-1])		{		    memmove(buf, bp, cp-bp);		    cc = Sys::read(fd, buf+(cp-bp), (sizeof(buf)-1) - (cp-bp)) + (cp-bp);		    buf[cc] = '\0';		    bp = &buf[0];		    cp = strchr(bp, '\0');		}		if (cp > bp) {		    if (cp[-1] == '\n') {			cp[-1] = '\0';			FIFOMessage(bp, &cp[-1]-bp);		    } else			FIFOMessage(bp, cp-bp);		}		bp = cp+1;	    }	} while (bp < &buf[cc]);    }    return (0);}voidHylaFAXServer::FIFOMessage(const char* cp, u_int){    if (IS(WAITFIFO)) {	/*	 * Someone is waiting for a response	 * from the server.  Stash the response	 * and notify them by marking the	 * response as arrived.	 */	fifoResponse = cp;	state &= ~S_WAITFIFO;	return;    }    switch (cp[0]) {    case 'H':				// HELLO when queuer restarts	if (faxqFd >= 0)	    Sys::close(faxqFd), faxqFd = -1;	if (trigSpec != "") {		// reload trigger	    fxStr emsg;	    (void) loadTrigger(emsg);	}	break;    }}/* * Send a message to the central queuer process. */boolHylaFAXServer::sendQueuerMsg(fxStr& emsg, const fxStr& msg){    bool retry = false;again:    if (faxqFd == -1) {#ifdef FIFOSELECTBUG	/*	 * We try multiple times to open the appropriate FIFO	 * file because the system has a kernel bug that forces	 * the server to close+reopen the FIFO file descriptors	 * for each message received on the FIFO (yech!).	 */	int tries = 0;	do {	    if (tries > 0)		sleep(1);	    faxqFd = Sys::open(faxqFIFOName, O_WRONLY|O_NDELAY);	} while (faxqFd == -1 && errno == ENXIO && ++tries < 5);#else	faxqFd = Sys::open(faxqFIFOName, O_WRONLY|O_NDELAY);#endif	if (faxqFd == -1) {	    emsg = fxStr::format("Unable to open scheduler FIFO: %s",		strerror(errno));	    return (false);	}	/*	 * Turn off O_NDELAY so that write will block if FIFO is full.	 */	if (fcntl(faxqFd, F_SETFL, fcntl(faxqFd, F_GETFL, 0) &~ O_NDELAY) < 0)	    logError("fcntl: %m");    }    ssize_t len = msg.length()+1;    if (Sys::write(faxqFd, msg, len) != len) {	if (errno == EBADF || errno == EPIPE) {	    /*	     * The queuer process is gone.  Try again	     * once in case it has been restarted.	     */	    Sys::close(faxqFd), faxqFd = -1;	    if (!retry) {		retry = true;		goto again;	    }	}	emsg = fxStr::format("FIFO write failed: %s", strerror(errno));	logError(emsg);	return (false);    } else	return (true);}/* * Send a message to the central queuer process. */boolHylaFAXServer::sendQueuer(fxStr& emsg, const char* fmt ...){    va_list ap;    va_start(ap, fmt);    bool ok = sendQueuerMsg(emsg, fxStr::vformat(fmt, ap));    va_end(ap);    return (ok);}/* * Send a message to the central queuer process * and wait for a response on our client FIFO. */boolHylaFAXServer::sendQueuerACK(fxStr& emsg, const char* fmt, ...){    va_list ap;    va_start(ap, fmt);    bool b = vsendQueuerACK(emsg, fmt, ap);    va_end(ap);    return (b);}boolHylaFAXServer::vsendQueuerACK(fxStr& emsg, const char* fmt, va_list ap){    if (clientFd == -1) {	emsg = "Bad server state, client FIFO is not open";	return (false);    }    fxStr msg = fxStr::vformat(fmt, ap);    if (msg.length() < 2) {			// sanity check	emsg = "Bad FIFO message, too short to be valid";	return (false);    }    msg.insert(clientFIFOName | ":", 1);	// insert FIFO name for reply     bool ok = sendQueuerMsg(emsg, msg);    if (ok) {	Dispatcher& disp = Dispatcher::instance();	for (state |= S_WAITFIFO; IS(WAITFIFO); disp.dispatch())	    ;	if (fifoResponse.length() < 2) {	// too short to be valid	    emsg = "Unexpected response from scheduler: \"" |fifoResponse| "\"";	    ok = false;	} else if (fifoResponse[0] == msg[0]) {	// response to our request	    ok = (fifoResponse[1] == '*');	    if (!ok)		emsg = "Unspecified reason (scheduler NAK'd request)";	} else					// user abort	    ok = false;    }    return (ok);}/* * Send a message to a modem process via the per-modem FIFO. */boolHylaFAXServer::sendModem(const char* modem, fxStr& emsg, const char* fmt ...){    fxStr fifoName(modem);    canonDevID(fifoName);			// convert pathname -> devid    fifoName.insert("/" FAX_FIFO ".");		// prepend /FIFO. string#ifdef FIFOSELECTBUG    /*     * We try multiple times to open the appropriate FIFO     * file because the system has a kernel bug that forces     * the server to close+reopen the FIFO file descriptors     * for each message received on the FIFO (yech!).     */    int fd;    int tries = 0;    do {	if (tries > 0)	    sleep(1);	fd = Sys::open(fifoName, O_WRONLY|O_NDELAY);    } while (fd == -1 && errno == ENXIO && ++tries < 5);#else    int fd = Sys::open(fifoName, O_WRONLY|O_NDELAY);#endif    if (fd == -1) {	emsg = fxStr::format("Unable to open %s: %s",	    (const char*) fifoName, strerror(errno));	return (false);    }    va_list ap;    va_start(ap, fmt);    fxStr msg = fxStr::vformat(fmt, ap);    va_end(ap);    ssize_t len = msg.length()+1;    if (Sys::write(fd, msg, len) != len) {	emsg = fxStr::format("write to %s failed: %s",	    (const char*) fifoName, strerror(errno));	logError(emsg);	return (false);    } else	return (true);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -