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

传真(Fax)编程

开发平台:

C/C++

  1. /* $Id: InetFaxServer.c++,v 1.8 2009/09/08 00:24:46 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 "port.h"
  27. #include "Dispatcher.h"
  28. #include "InetFaxServer.h"
  29. #include "Sys.h"
  30. #include "Socket.h"
  31. #include "config.h"
  32. #include <string.h>
  33. #include <netdb.h>
  34. #include <ctype.h>
  35. extern "C" {
  36. #include <arpa/inet.h>
  37. #include <netinet/in_systm.h>
  38. #include <netinet/ip.h>
  39. }
  40. InetSuperServer::InetSuperServer(const char* p, int bl)
  41.     : SuperServer("INET", bl)
  42.     , port(p)
  43. {
  44.     bindaddress = NULL;
  45. }
  46. InetSuperServer::~InetSuperServer() {}
  47. void
  48. InetSuperServer::setBindAddress(const char *bindaddr)
  49. {
  50.     bindaddress = bindaddr;
  51. }
  52. void
  53. InetSuperServer::setAddressFamily(const char *addrfamily)
  54. {
  55.     addressfamily = addrfamily;
  56. }
  57. bool
  58. InetSuperServer::startServer(void)
  59. {
  60.     Socket::Address addr;
  61.     struct addrinfo hints, *ai;
  62.     memset(&hints, 0, sizeof(hints));
  63.     /*
  64.      * Most BSDs seem to have some complications when using IPv6.  Since
  65.      * most users will not be using IPv6 the default is then IPv4-only.
  66.      */
  67.     hints.ai_family = AF_INET; // default
  68.     if (addressfamily) {
  69. if (strncmp(addressfamily, "IPv6", 4) == 0) hints.ai_family = AF_INET6;
  70. else if (strncmp(addressfamily, "IPv4", 4) == 0) hints.ai_family = AF_INET;
  71. else if (strncmp(addressfamily, "all", 3) == 0) hints.ai_family = AF_UNSPEC;
  72.     }
  73.     hints.ai_flags = AI_PASSIVE;
  74. #ifdef AI_ADDRCONFIG
  75.     hints.ai_flags |= AI_ADDRCONFIG;
  76. #endif
  77.     hints.ai_socktype = SOCK_STREAM;
  78.     struct protoent* pp = getprotobyname(FAX_PROTONAME);
  79.     if (pp)
  80. hints.ai_protocol = pp->p_proto;
  81.     if (getaddrinfo(bindaddress, port, &hints, &ai) == 0)  {
  82. memcpy(&addr, ai->ai_addr, ai->ai_addrlen);
  83. freeaddrinfo(ai);
  84.     } else {
  85. logDebug("Couldn't get address information for port "%s"",
  86. (const char*) port);
  87. /*
  88.  * Somethings broken here, let's pick some conservative defaults
  89.  */
  90. memset(&addr, 0, sizeof(addr));
  91. Socket::family(addr) = AF_INET;
  92. addr.in.sin_port = htons(FAX_DEFPORT);
  93.     }
  94.     int s = socket(Socket::family(addr), SOCK_STREAM, 0);
  95.     if (s >= 0) {
  96. int on = 1;
  97. if (Socket::setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) >= 0) {
  98.     if (Socket::bind(s, &addr, Socket::socklen(addr)) >= 0) {
  99. (void) listen(s, getBacklog());
  100. Dispatcher::instance().link(s, Dispatcher::ReadMask, this);
  101. return (true); // success
  102.     }
  103. }
  104. Sys::close(s);
  105. logError("HylaFAX %s: bind (port %u): %m",
  106.     getKind(), ntohs(Socket::port(addr)));
  107.     } else
  108. logError("HylaFAX %s: socket: %m", getKind());
  109.     return (false);
  110. }
  111. HylaFAXServer* InetSuperServer::newChild(void) { return new InetFaxServer; }
  112. InetFaxServer* InetFaxServer::_instance = NULL;
  113. InetFaxServer::InetFaxServer()
  114. {
  115.     usedefault = true;
  116.     swaitmax = 90; // wait at most 90 seconds
  117.     swaitint = 5; // interval between retries
  118.     memset(&data_dest, 0, sizeof (data_dest));
  119.     Socket::family(data_dest) = AF_INET6; // We'll allow AF_INET6 by default.
  120.     hostent* hp = Socket::gethostbyname(hostname);
  121.     if (hp != NULL)
  122.     {
  123. hostname = hp->h_name;
  124.         struct in_addr in;
  125.         memcpy(&in, hp->h_addr, sizeof (in));
  126.         hostaddr = inet_ntoa(in);
  127.     }
  128.     fxAssert(_instance == NULL,
  129. "Cannot create multiple InetFaxServer instances");
  130.     _instance = this;
  131. }
  132. InetFaxServer::~InetFaxServer() {}
  133. InetFaxServer& InetFaxServer::instance() { return *_instance; }
  134. void
  135. InetFaxServer::initServer(void)
  136. {
  137.     HylaFAXServer::initServer();
  138.     usedefault = true;
  139. }
  140. void
  141. InetFaxServer::open(void)
  142. {
  143.     setupNetwork(STDIN_FILENO);
  144.     HylaFAXServer::open();
  145.     if (TRACE(CONNECT))
  146.         logInfo("HylaFAX INET connection from %s [%s]",
  147.     (const char*) remotehost, (const char*) remoteaddr);
  148. }
  149. static const char*
  150. topDomain(const fxStr& h)
  151. {
  152.     int dots = 0;
  153.     u_int l = h.length();
  154.     if(l <= 0) return(NULL);  // out early
  155.     for (;;) {
  156. l = h.nextR(l, '.');
  157. if (l == 0)
  158.     return (&h[0]);  // return whole string
  159. if (++dots == 2)
  160.     return (&h[l]);
  161. l -=1;    //back over the dot
  162.     }
  163. }
  164. /*
  165.  * Check whether host h is in our local domain,
  166.  * defined as sharing the last two components of the domain part,
  167.  * or the entire domain part if the local domain has only one component.
  168.  * If either name is unqualified (contains no '.'),
  169.  * assume that the host is local, as it will be
  170.  * interpreted as such.
  171.  */
  172. bool
  173. InetFaxServer::isLocalDomain(const fxStr& h)
  174. {
  175.     const char* p1 = topDomain(hostname);
  176.     const char* p2 = topDomain(h);
  177.     return (p1 == NULL || p2 == NULL || strcasecmp(p1, p2) == 0);
  178. }
  179. /*
  180.  * Check host identity returned by getnameinfo to
  181.  * weed out clients trying to spoof us (this is mostly
  182.  * a sanity check; if they have full control of DNS
  183.  * they can still spoof)
  184.  * Look up the name and check that the peer's address
  185.  * corresponds to the host name.
  186.  */
  187. bool
  188. InetFaxServer::checkHostIdentity(const char*name)
  189. {
  190.     struct addrinfo hints, *ai;
  191.     memset(&hints, 0, sizeof(hints));
  192.     hints.ai_flags = AI_CANONNAME;
  193.     hints.ai_socktype = SOCK_STREAM;
  194.     if (getaddrinfo(name, NULL, &hints, &ai) == 0) {
  195. for (struct addrinfo *aip = ai; aip != NULL; aip = aip->ai_next) {
  196.     Socket::Address *addr = (Socket::Address*)aip->ai_addr;
  197.     if (aip->ai_family != Socket::family(peer_addr))
  198. continue;
  199.     if ( (aip->ai_family == AF_INET6 &&
  200.      memcmp(&addr->in6.sin6_addr, &peer_addr.in6.sin6_addr, sizeof(struct in6_addr)) ==0)
  201.  ||(aip->ai_family == AF_INET &&
  202.      memcmp(&addr->in.sin_addr, &peer_addr.in.sin_addr, sizeof(struct in_addr)) ==0)
  203.        ) {
  204. freeaddrinfo(ai);
  205. return true;
  206.     }
  207. }
  208. reply(130, "Warning, client address "%s" is not listed for host name "%s".",
  209.     (const char*) remoteaddr, name);
  210. freeaddrinfo(ai);
  211.     } else
  212. reply(130, "Warning, no inverse address mapping for client host name "%s".",
  213.     (const char*) name);
  214.     return (false);
  215. }
  216. void
  217. InetFaxServer::setupNetwork(int fd)
  218. {
  219.     socklen_t addrlen;
  220.     addrlen = sizeof (peer_addr);
  221.     if (Socket::getpeername(fd, &peer_addr, &addrlen) < 0) {
  222.         logError("getpeername: %m (incorrect hfaxd invocation?)");
  223.         dologout(-1);
  224.     }
  225.     addrlen = sizeof (ctrl_addr);
  226.     if (Socket::getsockname(fd, &ctrl_addr, &addrlen) < 0) {
  227.         logError("getsockname: %m");
  228.         dologout(-1);
  229.     }
  230. #if defined(IPTOS_LOWDELAY)
  231.     { int tos = IPTOS_LOWDELAY;
  232.       if (Socket::setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof (tos)) < 0)
  233.           logWarning("setsockopt (IP_TOS): %m");
  234.     }
  235. #endif
  236. #if defined(SO_LINGER) && !defined(__linux__)
  237.     { struct linger opt;
  238.       opt.l_onoff = 1;
  239.       opt.l_linger = 60;
  240.       if (Socket::setsockopt(fd, SOL_SOCKET, SO_LINGER, &opt, sizeof (opt)) < 0)
  241. logWarning("setsockopt (SO_LINGER): %m");
  242.     }
  243. #endif
  244.     /* anchor socket to avoid multi-homing problems */
  245.     data_source = ctrl_addr;
  246.     Socket::port(data_source) = htons(ntohs(Socket::port(ctrl_addr)-1));
  247. #ifdef  F_SETOWN
  248.     if (fcntl(fd, F_SETOWN, getpid()) == -1)
  249.         logError("fcntl (F_SETOWN): %m");
  250. #endif
  251. #if defined(SO_OOBINLINE)
  252.     /* handle urgent data inline */
  253.     { int on = 1;
  254.       if (Socket::setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &on, sizeof (on)) < 0)
  255.         logError("setsockopt (SO_OOBINLINE): %m");
  256.     }
  257. #endif
  258. #ifdef SIGURG
  259.     /*
  260.      * XXX This is #ifdef'd for ISC but indicates a problem
  261.      * XXX in the underlying system.  Without support for
  262.      * XXX urgent data clients will not be able to abort an
  263.      * XXX ongoing operation such as a file transfer.
  264.      */
  265.     signal(SIGURG, fxSIGHANDLER(sigURG));
  266. #endif
  267.     signal(SIGPIPE, fxSIGHANDLER(sigPIPE));
  268.     char hostbuf[128];
  269.     remoteaddr = inet_ntop(Socket::family(peer_addr), Socket::addr(peer_addr), hostbuf, sizeof(hostbuf));
  270.     getnameinfo((struct sockaddr*)&peer_addr, Socket::socklen(peer_addr),
  271.     hostbuf, sizeof(hostbuf), NULL, 0, 0);
  272.     if (remoteaddr == "0.0.0.0")
  273.         remotehost = "localhost";
  274.     else if (checkHostIdentity(hostbuf))
  275. remotehost = hostbuf;
  276.     else
  277. remotehost =  remoteaddr;
  278.     Dispatcher::instance().link(STDIN_FILENO, Dispatcher::ReadMask, this);
  279. }
  280. void
  281. InetFaxServer::handleUrgentData(void)
  282. {
  283.     /*
  284.      * Only process the urgent data is we are expecting it.
  285.      * Specifically, if a file transfer, synchronous job
  286.      * wait, or other potentially long-running operation is
  287.      * taking place we do a setjmp and set a flag so that
  288.      * if the client requests an abort operation (ABOR) then
  289.      * we longjmp below to break out of the op.
  290.      */
  291.     if ((state & (S_TRANSFER|S_WAITTRIG)) == 0) {
  292. if (IS(WAITFIFO)) {
  293.     fifoResponse = "User aborted operation";
  294.     state &= ~S_WAITFIFO;
  295. }
  296.         return;
  297.     }
  298.     char line[8];
  299.     if (!getCmdLine(line, sizeof (line))) {
  300.         reply(221, "You could at least say goodbye.");
  301.         dologout(0);
  302.     } else if (strcasecmp(line, "ABORn") == 0) {
  303. /*
  304.  * Abort the operation in progress.  Two reply
  305.  * codes are sent on the control channel; one
  306.  * for the outstanding operation and one for the
  307.  * abort command.
  308.  */
  309.         reply(426, "Operation aborted. Data connection closed.");
  310.         reply(226, "Abort successful");
  311.         longjmp(urgcatch, 1); // XXX potential memory leak
  312.     } else if (strcasecmp(line, "STATn") == 0) {
  313.         if (file_size != (off_t) -1)
  314.             reply(213, "Status: %lu of %lu bytes transferred",
  315.                   byte_count, file_size);
  316.         else
  317.             reply(213, "Status: %lu bytes transferred", byte_count);
  318.     } else
  319. pushCmdData(line, strlen(line));
  320. }
  321. void
  322. InetFaxServer::sigURG(int)
  323. {
  324.     int old_errno = errno;
  325.     InetFaxServer::instance().handleUrgentData();
  326.     errno = old_errno;
  327. }
  328. void
  329. InetFaxServer::lostConnection(void)
  330. {
  331.     if (TRACE(PROTOCOL))
  332.         logDebug("Lost connection to %s [%s]",
  333.     (const char*) remotehost, (const char*) remoteaddr);
  334.     dologout(-1);
  335. }
  336. void
  337. InetFaxServer::sigPIPE(int)
  338. {
  339.     int old_errno = errno;
  340.     InetFaxServer::instance().lostConnection();
  341.     errno = old_errno;
  342. }
  343. static bool
  344. setupPassiveDataSocket(int pdata, Socket::Address& pasv_addr)
  345. {
  346.     socklen_t len = Socket::socklen(pasv_addr);
  347.     return (
  348. Socket::bind(pdata, (struct sockaddr*)&pasv_addr, len) >= 0 &&
  349.         Socket::getsockname(pdata, (struct sockaddr*)&pasv_addr, &len) >= 0 &&
  350. listen(pdata, 1) >= 0
  351.     );
  352. }
  353. #define UC(b) (((int) b) & 0xff)
  354. /*
  355.  * Note: a response of 425 is not mentioned as a possible response to the
  356.  * PASV command in RFC959. However, it has been blessed as a legitimate
  357.  * response by Jon Postel in a telephone conversation with Rick Adams on 25
  358.  * Jan 89.
  359.  */
  360. void
  361. InetFaxServer::passiveCmd(void)
  362. {
  363.     if (tokenBody[0] == 'E') {
  364. pasv_addr = ctrl_addr;
  365. logDebug("Extended passive requested for family %d", Socket::family(pasv_addr));
  366. pdata = socket(Socket::family(pasv_addr), SOCK_STREAM, 0);
  367. if (pdata >= 0) {
  368.     Socket::port(pasv_addr) = 0;
  369.     if (!setupPassiveDataSocket(pdata, pasv_addr))
  370. (void) Sys::close(pdata), pdata = -1;
  371. }
  372. if (pdata >= 0) {
  373.     reply(229, "Entering Extended Passive Mode (|||%u|)",
  374.     ntohs(Socket::port(pasv_addr)));
  375. } else
  376.     perror_reply(425, "Cannot setup extended passive connection", errno);
  377. return;
  378.     }
  379.     if (Socket::family(ctrl_addr) != AF_INET) {
  380. reply(500, "Cannot use PASV with IPv6 connections");
  381. return;
  382.     }
  383.     if (pdata < 0) {
  384. pdata = socket(AF_INET, SOCK_STREAM, 0);
  385. if (pdata >= 0) {
  386.     pasv_addr = ctrl_addr;
  387.     pasv_addr.in.sin_port = 0;
  388.     if (!setupPassiveDataSocket(pdata, pasv_addr))
  389. (void) Sys::close(pdata), pdata = -1;
  390. }
  391.     }
  392.     if (pdata >= 0) {
  393. const u_char* a = (const u_char*) &pasv_addr.in.sin_addr;
  394. const u_char* p = (const u_char*) &pasv_addr.in.sin_port;
  395. reply(227, "Entering passive mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
  396.       UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
  397.     } else
  398. perror_reply(425, "Cannot setup passive connection", errno);
  399. }
  400. void
  401. InetFaxServer::printaddr(FILE* fd, const char* leader, const struct sockaddr_in& sin)
  402. {
  403.     const u_char* a = (const u_char *) &sin.sin_addr;
  404.     const u_char* p = (const u_char *) &sin.sin_port;
  405.     fprintf(fd, "%s (%d,%d,%d,%d,%d,%d)rn", leader,
  406.        UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
  407. }
  408. void
  409. InetFaxServer::netStatus(FILE* fd)
  410. {
  411.     if (data != -1)
  412.         fprintf(fd, "    Client data connection openrn");
  413.     else if (pdata != -1)
  414.         printaddr(fd, "    In passive mode", pasv_addr);
  415.     else if (!usedefault)
  416.         printaddr(fd, "    PORT", data_dest);
  417.     else
  418.         fprintf(fd, "    No client data connectionrn");
  419. }
  420. /*
  421.  * Creat a socket for a data transfer.
  422.  */
  423. FILE*
  424. InetFaxServer::getDataSocket(const char* mode)
  425. {
  426.     if (data >= 0)
  427.         return (fdopen(data, mode));
  428.     int s = socket(Socket::family(data_dest), SOCK_STREAM, 0);
  429.     if (s < 0)
  430.         goto bad;
  431.     { int on = 1;
  432.       if (Socket::setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
  433.         goto bad;
  434.     }
  435.     { int ntry; // XXX for __GNUC__
  436.       for (ntry = 1;; ntry++) {
  437.         if (Socket::bind(s, &data_source, Socket::socklen(data_source)) >= 0)
  438.             break;
  439.         if (errno != EADDRINUSE || ntry > 10)
  440.             goto bad;
  441.         sleep(ntry);
  442.       }
  443.     }
  444. #ifdef IPTOS_THROUGHPUT
  445.     { int on = IPTOS_THROUGHPUT;
  446.       if (Socket::setsockopt(s, IPPROTO_IP, IP_TOS, &on, sizeof (on)) < 0)
  447.           logWarning("setsockopt (IP_TOS): %m");
  448.     }
  449. #endif
  450.     return (fdopen(s, mode));
  451. bad:
  452.     (void) Sys::close(s);
  453.     return (NULL);
  454. }
  455. bool
  456. InetFaxServer::dataConnect(void)
  457. {
  458.     return Socket::connect(data, &data_dest, Socket::socklen(data_dest)) >= 0;
  459. }
  460. /*
  461.  * Establish a data connection for a file transfer operation.
  462.  */
  463. FILE*
  464. InetFaxServer::openDataConn(const char* mode, int& code)
  465. {
  466.     byte_count = 0;
  467.     if (pdata >= 0) { // passive mode, wait for connection
  468.         struct sockaddr_in from;
  469.         socklen_t fromlen = sizeof (from);
  470. // XXX don't block, select....????
  471.         int s = Socket::accept(pdata, (struct sockaddr*) &from, &fromlen);
  472.         if (s < 0) {
  473.             reply(425, "Cannot open data connection.");
  474.             (void) Sys::close(pdata);
  475.             pdata = -1;
  476.             return (NULL);
  477.         }
  478. // XXX verify peer address???
  479.         (void) Sys::close(pdata);
  480.         pdata = s;
  481. #ifdef IPTOS_LOWDELAY
  482.         int tos = IPTOS_LOWDELAY;
  483.         (void) Socket::setsockopt(s, IPPROTO_IP, IP_TOS, &tos, sizeof (tos));
  484. #endif
  485. code = 150;
  486.         return (fdopen(pdata, mode));
  487.     }
  488.     if (data >= 0) {
  489. code = 125;
  490.         usedefault = 1;
  491.         return (fdopen(data, mode));
  492.     }
  493.     if (usedefault)
  494.         data_dest = peer_addr;
  495.     usedefault = 1;
  496.     FILE* file = getDataSocket(mode);
  497.     if (file == NULL) {
  498.         reply(425, "Cannot create data socket (%s,%d): %s.",
  499.               inet_ntoa(data_source.in.sin_addr),
  500.               ntohs(data_source.in.sin_port), strerror(errno));
  501. return (NULL);
  502.     }
  503.     data = fileno(file);
  504.     for (int swait = 0; !dataConnect(); swait += swaitint) {
  505. if (!(errno == EADDRINUSE || errno == EINTR) || swait >= swaitmax) {
  506.     perror_reply(425, "Cannot build data connection", errno);
  507.     fclose(file);
  508.     data = -1;
  509.     return (NULL);
  510. }
  511. sleep(swaitint);
  512.     }
  513.     code = 150;
  514.     return (file);
  515. }
  516. bool
  517. InetFaxServer::hostPort()
  518. {
  519.     logDebug("Parsing hostPort(): "%s"", (const char*)tokenBody);
  520.     if (tokenBody[0] == 'E')
  521.     {
  522. fxStr s;
  523. if (! STRING(s))
  524. {
  525.     logDebug("Couldn't get string: "%s"", (const char*)tokenBody);
  526.     syntaxError("EPRT |family|address|port|");
  527.     return false;
  528. }
  529. logDebug("Parsing "%s"", (const char*)s);
  530. /*
  531.  * Minimual length for EPRT is: 9
  532.  *       |X|X::|X|
  533.  */
  534. char c = s[0];
  535. logDebug(" `-> s.length() = %d", s.length());
  536. logDebug(" `-> s[0] = '%c'", s[0]);
  537. logDebug(" `-> s[2] = '%c'", s[2]);
  538. logDebug(" `-> s[%d] = '%c'", s.length()-1, s[s.length()-1]);
  539. if (s.length() > 9
  540. && c == s[0] && (s[1] == '1' || s[1] == '2') && c == s[2]
  541. && c == s[s.length()-1]) {
  542.     logDebug("Looks like extended syntax: "%s" [%X: %c]", (const char*)s, c&0xFF, c);
  543.     u_int pos = 3;
  544.     fxStr a = s.token(pos, c);
  545.     logDebug("`-> Got a: %s[%u]", (const char*)a, pos);
  546.     fxStr p = s.token(pos, c);
  547.     logDebug("`-> Got a: %s[%u]", (const char*)p, pos);
  548.     if (pos != s.length() )
  549.     {
  550. logDebug("Parsing EPRT style failed");
  551. syntaxError("EPRT |family|address|port|");
  552. return false;
  553.     }
  554.     logDebug("Parsed: Family %c Address %s Port %s", s[1], (const char*)a, (const char*)p);
  555.     struct addrinfo hints, *ai;
  556.     memset(&hints, 0, sizeof(hints));
  557. #ifdef AI_NUMERICHOST
  558.     hints.ai_flags |= AI_NUMERICHOST;
  559. #endif
  560. #ifdef AI_NUMERICSERV
  561.     hints.ai_flags |= AI_NUMERICSERV;
  562. #endif
  563.     hints.ai_socktype = SOCK_STREAM;
  564.     switch (s[1])
  565.     {
  566. case '1':
  567.     hints.ai_family = AF_INET;
  568.     break;
  569. case '2':
  570.     hints.ai_family = AF_INET6;
  571.     break;
  572. default:
  573.     reply(500, "EPRT: Invalid family "%c"", s[1]);
  574.     }
  575.     if (getaddrinfo(a, p, &hints, &ai) != 0) {
  576.     reply(500, "EPRT couldn't parse family "%c" address "%s" port "%s"",
  577. s[1], (const char*)a, (const char*)p);
  578.     return false;
  579.     }
  580.     memcpy(&data_dest, ai->ai_addr, ai->ai_addrlen);
  581.     freeaddrinfo(ai);
  582.     return true;
  583. }
  584. logDebug("Couldn't parse "%s"", (const char*)s);
  585. syntaxError("Couldn't parse extended port");
  586. return false;
  587.     }
  588.     long a0, a1, a2, a3;
  589.     long p0, p1;
  590.     bool syntaxOK = 
  591.       NUMBER(a0)
  592. && COMMA() && NUMBER(a1)
  593. && COMMA() && NUMBER(a2)
  594. && COMMA() && NUMBER(a3)
  595. && COMMA() && NUMBER(p0)
  596. && COMMA() && NUMBER(p1)
  597. ;
  598.     if (syntaxOK) {
  599. data_dest.in.sin_family = AF_INET;
  600. u_char* a = (u_char*) &data_dest.in.sin_addr;
  601. u_char* p = (u_char*) &data_dest.in.sin_port;
  602. a[0] = UC(a0); a[1] = UC(a1); a[2] = UC(a2); a[3] = UC(a3);
  603. p[0] = UC(p0); p[1] = UC(p1);
  604. return (true);
  605.     }
  606.     return false;
  607. }
  608. void
  609. InetFaxServer::portCmd(Token t)
  610. {
  611.     if (t == T_EPRT)
  612. logcmd(T_EPRT, "|%d|%s|%u|", 1, inet_ntoa(data_dest.in.sin_addr), data_dest.in.sin_port);
  613.     else
  614. logcmd(T_PORT, "%s;%u", inet_ntoa(data_dest.in.sin_addr), data_dest.in.sin_port);
  615.     usedefault = false;
  616.     if (pdata >= 0)
  617.        (void) Sys::close(pdata), pdata = -1;
  618.     if (t == T_EPRT)
  619. ack(200, cmdToken(T_EPRT));
  620.     else
  621. ack(200, cmdToken(T_PORT));
  622. }