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

传真(Fax)编程

开发平台:

C/C++

  1. /* $Id: HylaClient.c++,v 1.1.1.1 2005/11/11 21:32:02 faxguy Exp $ */
  2. /*
  3.  * Copyright (c) 1995-1996 Sam Leffler
  4.  * Copyright (c) 1995-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 "faxApp.h"
  27. #include "HylaClient.h"
  28. #include "Sys.h"
  29. #include "Dispatcher.h"
  30. #include "Trigger.h"
  31. #include "config.h"
  32. #include <errno.h>
  33. fxIMPLEMENT_StrKeyPtrValueDictionary(HylaClientDict, HylaClient*)
  34. tseq_t HylaClient::lruseq = 0;
  35. HylaClientDict HylaClient::clients;
  36. HylaClient::SchedReaper HylaClient::schedReaper;
  37. HylaClient::HylaClient(const fxStr& fn) : fifoName(fn)
  38. {
  39.     fifo = -1;
  40.     refs = 0;
  41.     seqnum = 0;
  42.     lrunum = lruseq;
  43.     reap = false;
  44.     clients[fn] = this;
  45. }
  46. HylaClient::~HylaClient()
  47. {
  48.     if (refs != 0)
  49. logError("Client deleted with %u refs; FIFO " | fifoName, refs);
  50.     if (fifo != -1)
  51. Sys::close(fifo);
  52.     clients.remove(fifoName);
  53. }
  54. /*
  55.  * Return a HylaClient for the process listening on
  56.  * the specified FIFO name. 
  57.  */
  58. HylaClient&
  59. HylaClient::getClient(const fxStr& name)
  60. {
  61.     HylaClient* hc = clients[name];
  62.     return (hc ? *hc : *new HylaClient(name));
  63. }
  64. /*
  65.  * Send a message to the process listening on the
  66.  * client's FIFO.  If an error is encountered the
  67.  * client is scheduled to be purged at the next
  68.  * opportune time.
  69.  */
  70. bool
  71. HylaClient::send(const char* msg, u_int msgLen)
  72. {
  73.      if (reap) // ignore if marked for reaping
  74. return (false);
  75.      seqnum++; // count message
  76. again:
  77.     if (fifo < 0) {
  78. #ifdef FIFOSELECTBUG
  79. /*
  80.  * We try multiple times to open the appropriate FIFO
  81.  * file because the system has a kernel bug that forces
  82.  * the server to close+reopen the FIFO file descriptors
  83.  * for each message received on the FIFO (yech!).
  84.  */
  85. int tries = 0;
  86. do {
  87.     if (tries > 0)
  88. sleep(1);
  89.     fifo = Sys::open(fifoName, O_WRONLY|O_NDELAY);
  90. } while (fifo == -1 && errno == ENXIO && ++tries < 5);
  91. #else
  92. fifo = Sys::open(fifoName, O_WRONLY|O_NDELAY);
  93. #endif
  94. if (fifo < 0) {
  95.     if (errno == EMFILE && reapFIFO())
  96. goto again;
  97.     logError("HylaClient::send: %s: Cannot open FIFO: %m",
  98. (const char*) fifoName);
  99.     schedReap();
  100.     return (false);
  101. }
  102. /*
  103.  * NB: We mark the descriptor for non-blocking i/o; this
  104.  *     is important to avoid potential deadlocks caused by
  105.  *     clients that block waiting to write a message into
  106.  *     our FIFO while we block trying to write into theirs.
  107.  *     We expect our FIFO to always be more full than theirs
  108.  *     and in addition it is critical that we never block
  109.  *     for any long period of time.
  110.  */
  111.     }
  112.     if (fifo >= 0) {
  113. int n = Sys::write(fifo, msg, msgLen);
  114. if (n == -1 && (errno == EBADF || errno == EPIPE)) {
  115.     Sys::close(fifo), fifo = -1;
  116.     schedReap();
  117.     return (false);
  118. }
  119. if ((unsigned) n != msgLen)
  120.     logError(
  121. "HylaClient::send: %s: write failed (return %d, seq# %u, %m)",
  122. (const char*) fifoName, seqnum, n);
  123. lrunum = lruseq++; // update last use seqnum
  124.     }
  125.     return (true);
  126. }
  127. /*
  128.  * Out of file descriptors for sending notification
  129.  * messages; search the collection of triggers for
  130.  * the oldest trigger with an open descriptor and
  131.  * reclaim it.
  132.  */
  133. bool
  134. HylaClient::reapFIFO()
  135. {
  136.     HylaClient* cand = NULL;
  137.     u_int candage = 0;
  138.     for (HylaClientDictIter iter(clients); iter.notDone(); iter++) {
  139. HylaClient* hc = iter.value();
  140. if (hc->fifo != -1) {
  141.     struct stat sb;
  142.     // cleanup deadwood while we're at it
  143.     if (Sys::fstat(hc->fifo, sb) != -1) {
  144. u_int age = lruseq - hc->lrunum;
  145. if (!cand || age > candage) {
  146.     candage = age;
  147.     cand = hc;
  148. }
  149.     } else
  150. hc->schedReap();
  151. }
  152.     }
  153.     if (cand) {
  154. Sys::close(cand->fifo);
  155. cand->fifo = -1;
  156. return (true);
  157.     } else
  158. return (false);
  159. }
  160. void
  161. HylaClient::purge()
  162. {
  163.     for (HylaClientDictIter iter(clients); iter.notDone(); iter++) {
  164. struct stat sb;
  165. HylaClient* hc = iter.value();
  166. if (hc->fifo != -1 && Sys::stat(hc->fifoName, sb) == -1) {
  167.     if (hc->refs > 0)
  168. Trigger::purgeClient(hc);
  169.     else
  170. delete hc;
  171. }
  172.     }
  173. }
  174. void
  175. HylaClient::schedReap()
  176. {
  177.     reap = true;
  178.     schedReaper.start();
  179. }
  180. /*
  181.  * Trigger Reaper Support; this class is used to
  182.  * delete instances when the application is idle;
  183.  * this is necesarry because we sometimes recognize
  184.  * a client has gone away at a point where we cannot
  185.  * "delete this".
  186.  */
  187. HylaClient::SchedReaper::SchedReaper() { started = false; }
  188. HylaClient::SchedReaper::~SchedReaper() {}
  189. void
  190. HylaClient::SchedReaper::timerExpired(long, long)
  191. {
  192.     started = false;
  193.     /*
  194.      * Reclaim clients that have gone away.
  195.      *
  196.      * NB: the explicit reference to clients is required for the
  197.      *     AIX compiler (XXX)
  198.      */
  199.     for (HylaClientDictIter iter(HylaClient::clients); iter.notDone(); iter++) {
  200. HylaClient* hc = iter.value();
  201. if (hc->reap) {
  202.     if (hc->refs > 0)
  203. Trigger::purgeClient(hc);
  204.     else
  205. delete hc;
  206. }
  207.     }
  208. }
  209. /*
  210.  * Set a timeout so that the reaper runs the
  211.  * next time the dispatcher is invoked.
  212.  */
  213. void
  214. HylaClient::SchedReaper::start()
  215. {
  216.     if (!started) {
  217. Dispatcher::instance().startTimer(0,1, this);
  218. started = true;
  219.     }
  220. }