FIFO.c++
上传用户:weiyuanprp
上传日期:2020-05-20
资源大小:1169k
文件大小:10k
源码类别:

传真(Fax)编程

开发平台:

C/C++

  1. /* $Id: FIFO.c++,v 1.1.1.1 2005/11/11 21:32:03 faxguy Exp $ */
  2. /*
  3.  * Copyright (c) 1990-1996 Sam Leffler
  4.  * Copyright (c) 1991-1996 Silicon Graphics, Inc.
  5.  * HylaFAX is a trademark of Silicon Graphics
  6.  *
  7.  * Permission to use, copy, modify, distribute, and sell this software and 
  8.  * its documentation for any purpose is hereby granted without fee, provided
  9.  * that (i) the above copyright notices and this permission notice appear in
  10.  * all copies of the software and related documentation, and (ii) the names of
  11.  * Sam Leffler and Silicon Graphics may not be used in any advertising or
  12.  * publicity relating to the software without the specific, prior written
  13.  * permission of Sam Leffler and Silicon Graphics.
  14.  * 
  15.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  16.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  17.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  18.  * 
  19.  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
  20.  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
  21.  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  22.  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
  23.  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
  24.  * OF THIS SOFTWARE.
  25.  */
  26. #include "port.h"
  27. #include "Sys.h"
  28. #include "config.h"
  29. #include "HylaFAXServer.h"
  30. #include "Dispatcher.h"
  31. /*
  32.  * Support for communication with the HylaFAX queuer via FIFO's.
  33.  */
  34. /*
  35.  * Create the client FIFO and open it for use.
  36.  */
  37. bool
  38. HylaFAXServer::initClientFIFO(fxStr& emsg)
  39. {
  40.     clientFIFOName = fxStr::format(FAX_CLIENTDIR "/%u", getpid());
  41.     if (Sys::mkfifo(clientFIFOName, 0622) < 0 && errno != EEXIST) {
  42. emsg = fxStr::format("Could not create %s: %s",
  43.     (const char*) clientFIFOName, strerror(errno));
  44. return (false);
  45.     }
  46.     clientFd = Sys::open(clientFIFOName, CONFIG_OPENFIFO|O_NDELAY);
  47.     if (clientFd == -1) {
  48. emsg = fxStr::format("Could not open FIFO file %s: %s",
  49.     (const char*) clientFIFOName, strerror(errno));
  50. return (false);
  51.     }
  52.     if (!Sys::isFIFOFile(clientFd)) {
  53. emsg = clientFIFOName | " is not a FIFO special file";
  54. return (false);
  55.     }
  56.     // open should set O_NDELAY, but just to be sure...
  57.     if (fcntl(clientFd, F_SETFL, fcntl(clientFd, F_GETFL, 0) | O_NDELAY) < 0)
  58. logError("initClientFIFO %s: fcntl: %m", (const char*) clientFIFOName);
  59.     Dispatcher::instance().link(clientFd, Dispatcher::ReadMask, this);
  60.     return (true);
  61. }
  62. /*
  63.  * Respond to input on a FIFO file descriptor.
  64.  */
  65. int
  66. HylaFAXServer::FIFOInput(int fd)
  67. {
  68.     char buf[2048];
  69.     int cc;
  70.     while ((cc = Sys::read(fd, buf, sizeof (buf)-1)) > 0) {
  71. if (cc == sizeof(buf)-1)
  72.     logWarning("FIFO Read full: %d", cc);
  73. buf[cc] = '';
  74. char* bp = &buf[0];
  75. do {
  76.     if (bp[0] == '!') {
  77. /*
  78.  * This is an event message from the scheduler
  79.  * generated by a previously registered trigger.
  80.  * Setup the unpacking work and dispatch it.
  81.  */
  82. TriggerMsgHeader h;
  83. u_int left = &buf[cc]-bp;
  84. bool needy = false;
  85. if (left < sizeof(TriggerMsgHeader))
  86. {
  87.     needy = true;
  88. } else
  89. {
  90.     memcpy(&h, bp, sizeof (h)); // copy to align fields
  91.     if (left < h.length)
  92. needy = true;
  93. }
  94. if (needy)
  95. {
  96.     /*
  97.      * Handle the case where the buffer was read full.  This means that
  98.      * we have a "partial" message at the end of buf, and the rest in
  99.      * the FIFO.
  100.      *
  101.      * buf[n] is NEVER read from the file, it's always 1-past.  If we
  102.      * have reached buf[n], we know we are past the read data.
  103.      *
  104.      * We have (left) bytes of the message at the end of the buf.
  105.      * We move them to the front, and read as much more as we can to
  106.      * fill buf back up, leaving it in the same state as if this was
  107.      * the initial read.
  108.      */
  109.     memmove(buf, bp, left);
  110.     cc = Sys::read(fd, buf+left, (sizeof(buf)-1) - left) + left;
  111.     buf[cc] = '';
  112.     bp = &buf[0];
  113. } else {
  114.     triggerEvent(h, bp+sizeof (h));
  115.     bp += h.length;
  116. }
  117.     } else {
  118. /*
  119.  * Break up ''-separated records and strip
  120.  * any trailing 'n' so that "echo mumble>FIFO"
  121.  * works (i.e. echo appends a 'n' character).
  122.  */
  123. char* cp = strchr(bp, '');
  124. /*
  125.  * Handle the case where the buffer was read full.  This means that
  126.  * we have a "partial" message at the end of buf, and the rest in
  127.  * the FIFO.
  128.  *
  129.  * buf[n] is NEVER read from the file, it's always 1-past.  If we
  130.  * have reached buf[n], we know we are past the read data.
  131.  *
  132.  * We have (cp - bp) bytes of the message at the end of the buf.
  133.  * We move them to the front, and read as much more as we can to
  134.  * fill buf back up, leaving it in the same state as if this was
  135.  * the initial read.
  136.  */
  137. if (cp == &buf[sizeof(buf)-1])
  138. {
  139.     memmove(buf, bp, cp-bp);
  140.     cc = Sys::read(fd, buf+(cp-bp), (sizeof(buf)-1) - (cp-bp)) + (cp-bp);
  141.     buf[cc] = '';
  142.     bp = &buf[0];
  143.     cp = strchr(bp, '');
  144. }
  145. if (cp > bp) {
  146.     if (cp[-1] == 'n') {
  147. cp[-1] = '';
  148. FIFOMessage(bp, &cp[-1]-bp);
  149.     } else
  150. FIFOMessage(bp, cp-bp);
  151. }
  152. bp = cp+1;
  153.     }
  154. } while (bp < &buf[cc]);
  155.     }
  156.     return (0);
  157. }
  158. void
  159. HylaFAXServer::FIFOMessage(const char* cp, u_int)
  160. {
  161.     if (IS(WAITFIFO)) {
  162. /*
  163.  * Someone is waiting for a response
  164.  * from the server.  Stash the response
  165.  * and notify them by marking the
  166.  * response as arrived.
  167.  */
  168. fifoResponse = cp;
  169. state &= ~S_WAITFIFO;
  170. return;
  171.     }
  172.     switch (cp[0]) {
  173.     case 'H': // HELLO when queuer restarts
  174. if (faxqFd >= 0)
  175.     Sys::close(faxqFd), faxqFd = -1;
  176. if (trigSpec != "") { // reload trigger
  177.     fxStr emsg;
  178.     (void) loadTrigger(emsg);
  179. }
  180. break;
  181.     }
  182. }
  183. /*
  184.  * Send a message to the central queuer process.
  185.  */
  186. bool
  187. HylaFAXServer::sendQueuerMsg(fxStr& emsg, const fxStr& msg)
  188. {
  189.     bool retry = false;
  190. again:
  191.     if (faxqFd == -1) {
  192. #ifdef FIFOSELECTBUG
  193. /*
  194.  * We try multiple times to open the appropriate FIFO
  195.  * file because the system has a kernel bug that forces
  196.  * the server to close+reopen the FIFO file descriptors
  197.  * for each message received on the FIFO (yech!).
  198.  */
  199. int tries = 0;
  200. do {
  201.     if (tries > 0)
  202. sleep(1);
  203.     faxqFd = Sys::open(faxqFIFOName, O_WRONLY|O_NDELAY);
  204. } while (faxqFd == -1 && errno == ENXIO && ++tries < 5);
  205. #else
  206. faxqFd = Sys::open(faxqFIFOName, O_WRONLY|O_NDELAY);
  207. #endif
  208. if (faxqFd == -1) {
  209.     emsg = fxStr::format("Unable to open scheduler FIFO: %s",
  210. strerror(errno));
  211.     return (false);
  212. }
  213. /*
  214.  * Turn off O_NDELAY so that write will block if FIFO is full.
  215.  */
  216. if (fcntl(faxqFd, F_SETFL, fcntl(faxqFd, F_GETFL, 0) &~ O_NDELAY) < 0)
  217.     logError("fcntl: %m");
  218.     }
  219.     ssize_t len = msg.length()+1;
  220.     if (Sys::write(faxqFd, msg, len) != len) {
  221. if (errno == EBADF || errno == EPIPE) {
  222.     /*
  223.      * The queuer process is gone.  Try again
  224.      * once in case it has been restarted.
  225.      */
  226.     Sys::close(faxqFd), faxqFd = -1;
  227.     if (!retry) {
  228. retry = true;
  229. goto again;
  230.     }
  231. }
  232. emsg = fxStr::format("FIFO write failed: %s", strerror(errno));
  233. logError(emsg);
  234. return (false);
  235.     } else
  236. return (true);
  237. }
  238. /*
  239.  * Send a message to the central queuer process.
  240.  */
  241. bool
  242. HylaFAXServer::sendQueuer(fxStr& emsg, const char* fmt ...)
  243. {
  244.     va_list ap;
  245.     va_start(ap, fmt);
  246.     bool ok = sendQueuerMsg(emsg, fxStr::vformat(fmt, ap));
  247.     va_end(ap);
  248.     return (ok);
  249. }
  250. /*
  251.  * Send a message to the central queuer process
  252.  * and wait for a response on our client FIFO.
  253.  */
  254. bool
  255. HylaFAXServer::sendQueuerACK(fxStr& emsg, const char* fmt, ...)
  256. {
  257.     va_list ap;
  258.     va_start(ap, fmt);
  259.     bool b = vsendQueuerACK(emsg, fmt, ap);
  260.     va_end(ap);
  261.     return (b);
  262. }
  263. bool
  264. HylaFAXServer::vsendQueuerACK(fxStr& emsg, const char* fmt, va_list ap)
  265. {
  266.     if (clientFd == -1) {
  267. emsg = "Bad server state, client FIFO is not open";
  268. return (false);
  269.     }
  270.     fxStr msg = fxStr::vformat(fmt, ap);
  271.     if (msg.length() < 2) { // sanity check
  272. emsg = "Bad FIFO message, too short to be valid";
  273. return (false);
  274.     }
  275.     msg.insert(clientFIFOName | ":", 1); // insert FIFO name for reply 
  276.     bool ok = sendQueuerMsg(emsg, msg);
  277.     if (ok) {
  278. Dispatcher& disp = Dispatcher::instance();
  279. for (state |= S_WAITFIFO; IS(WAITFIFO); disp.dispatch())
  280.     ;
  281. if (fifoResponse.length() < 2) { // too short to be valid
  282.     emsg = "Unexpected response from scheduler: "" |fifoResponse| """;
  283.     ok = false;
  284. } else if (fifoResponse[0] == msg[0]) { // response to our request
  285.     ok = (fifoResponse[1] == '*');
  286.     if (!ok)
  287. emsg = "Unspecified reason (scheduler NAK'd request)";
  288. } else // user abort
  289.     ok = false;
  290.     }
  291.     return (ok);
  292. }
  293. /*
  294.  * Send a message to a modem process via the per-modem FIFO.
  295.  */
  296. bool
  297. HylaFAXServer::sendModem(const char* modem, fxStr& emsg, const char* fmt ...)
  298. {
  299.     fxStr fifoName(modem);
  300.     canonDevID(fifoName); // convert pathname -> devid
  301.     fifoName.insert("/" FAX_FIFO "."); // prepend /FIFO. string
  302. #ifdef FIFOSELECTBUG
  303.     /*
  304.      * We try multiple times to open the appropriate FIFO
  305.      * file because the system has a kernel bug that forces
  306.      * the server to close+reopen the FIFO file descriptors
  307.      * for each message received on the FIFO (yech!).
  308.      */
  309.     int fd;
  310.     int tries = 0;
  311.     do {
  312. if (tries > 0)
  313.     sleep(1);
  314. fd = Sys::open(fifoName, O_WRONLY|O_NDELAY);
  315.     } while (fd == -1 && errno == ENXIO && ++tries < 5);
  316. #else
  317.     int fd = Sys::open(fifoName, O_WRONLY|O_NDELAY);
  318. #endif
  319.     if (fd == -1) {
  320. emsg = fxStr::format("Unable to open %s: %s",
  321.     (const char*) fifoName, strerror(errno));
  322. return (false);
  323.     }
  324.     va_list ap;
  325.     va_start(ap, fmt);
  326.     fxStr msg = fxStr::vformat(fmt, ap);
  327.     va_end(ap);
  328.     ssize_t len = msg.length()+1;
  329.     if (Sys::write(fd, msg, len) != len) {
  330. emsg = fxStr::format("write to %s failed: %s",
  331.     (const char*) fifoName, strerror(errno));
  332. logError(emsg);
  333. return (false);
  334.     } else
  335. return (true);
  336. }