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

传真(Fax)编程

开发平台:

C/C++

  1. /* $Id: InetTransport.c++,v 1.5 2009/05/25 20:20:10 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 "config.h"
  27. #include "FaxClient.h"
  28. #include "InetTransport.h"
  29. #include "Sys.h"
  30. InetTransport::InetTransport(FaxClient& c) : Transport(c) {}
  31. InetTransport::~InetTransport(){}
  32. bool
  33. InetTransport::isA(const char*)
  34. {
  35.      return (true); // XXX are there checks we can make?
  36. }
  37. #if CONFIG_INETTRANSPORT
  38. #include "Socket.h"
  39. #include <sys/types.h>
  40. extern "C" {
  41. #include <arpa/inet.h>
  42. #include <arpa/telnet.h>
  43. #include <netinet/in.h>
  44. #include <netinet/in_systm.h>
  45. #include <netinet/ip.h>
  46. #include <netdb.h>
  47. }
  48. #include <ctype.h>
  49. #include <errno.h>
  50. /*
  51.  *  References for IPv6:
  52.  *   http://people.redhat.com/drepper/userapi-ipv6.html
  53.  *   http://www.ietf.org/rfc/rfc2428.txt
  54.  */
  55. bool
  56. InetTransport::callServer(fxStr& emsg)
  57. {
  58.     fxStr service(FAX_SERVICE);
  59.     fxStr proto(client.getProtoName());
  60.     int protocol = 0;
  61.     struct addrinfo hints, *ai;
  62.     if (client.getPort() != -1)
  63. service = fxStr::format("%d", client.getPort());
  64.     else {
  65. char* cp;
  66. if ((cp = getenv("FAXSERVICE")) && *cp != '') {
  67.     fxStr s(cp);
  68.     u_int l = s.next(0,'/');
  69.     service = s.head(l);
  70.     if (l < s.length())
  71. proto = s.tail(s.length()-(l+1));
  72. }
  73.     }
  74.     const char* cproto = proto; // XXX for busted include files
  75.     struct protoent* pp = getprotobyname(cproto);
  76.     if (!pp) {
  77. client.printWarning("%s: No protocol definition, using default.",
  78.     cproto);
  79.     } else
  80. protocol = pp->p_proto;
  81.     memset (&hints, '', sizeof (hints));
  82.     hints.ai_flags = AI_CANONNAME;
  83. #ifdef AI_NUMERICHOST
  84.     hints.ai_flags |= AI_NUMERICHOST;
  85. #endif
  86. #ifdef AI_ADDRCONFIG
  87.     hints.ai_flags |= AI_ADDRCONFIG;
  88. #endif
  89.     hints.ai_socktype = SOCK_STREAM;
  90.     hints.ai_protocol = protocol;
  91.     int err = getaddrinfo (client.getHost(), service, &hints, &ai);
  92. #ifdef AI_NUMERICHOST
  93.     if (err == EAI_NONAME) {
  94. hints.ai_flags &= ~AI_NUMERICHOST;
  95. err = getaddrinfo (client.getHost(), service, &hints, &ai);
  96.     }
  97. #endif
  98.     if (err != 0) {
  99. client.printWarning("getaddrinfo failed with %d: %s", err, gai_strerror(err));
  100. return false;
  101.     }
  102.     for (struct addrinfo *aip = ai; aip != NULL; aip = aip->ai_next)
  103.     {
  104. Socket::Address *addr = (Socket::Address*)aip->ai_addr;
  105. char buf[256];                          // For inet_ntop use
  106. fxAssert(aip->ai_family == Socket::family(*addr), "addrinfo ai_family doesn't match in_addr->ai_info");
  107. if (client.getVerbose())
  108.     client.traceServer("Trying %s [%d] (%s) at port %u...",
  109.     (const char*)client.getHost(), Socket::family(*addr),
  110.     inet_ntop(Socket::family(*addr), Socket::addr(*addr), buf, sizeof(buf)),
  111.     ntohs(Socket::port(*addr)));
  112. int fd = socket (aip->ai_family, aip->ai_socktype, aip->ai_protocol);
  113. if (fd != -1 && ( connect(fd, aip->ai_addr, aip->ai_addrlen) == 0))
  114. {
  115.     if (client.getVerbose())
  116. client.traceServer("Connected to %s.", aip->ai_canonname);
  117.     /*  Free the addrinfo chain before we leave*/
  118.     freeaddrinfo(ai);
  119. #if defined(IP_TOS) && defined(IPTOS_LOWDELAY)
  120.     int tos = IPTOS_LOWDELAY;
  121.     if (Socket::setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof (tos)) < 0)
  122. client.printWarning("setsockopt(TOS): %s (ignored)",
  123.     strerror(errno));
  124. #endif
  125. #ifdef SO_OOBINLINE
  126.     int on = 1;
  127.     if (Socket::setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &on, sizeof (on)) < 0)
  128. client.printWarning("setsockopt(OOBLINE): %s (ignored)",
  129.     strerror(errno));
  130. #endif
  131.     /*
  132.      * NB: We dup the descriptor because some systems
  133.      * that emulate sockets with TLI incorrectly handle
  134.      * things if we use the same descriptor for both
  135.      * input and output (sigh).
  136.      */
  137.     client.setCtrlFds(fd, dup(fd));
  138.     return (true);
  139. }
  140. Sys::close(fd), fd = -1;
  141.     }
  142.     emsg = fxStr::format("Can not reach service %s at host "%s".",
  143. (const char*)service, (const char*) client.getHost());
  144.     freeaddrinfo(ai);
  145.     return (false);
  146. }
  147. bool
  148. InetTransport::initDataConn(fxStr& emsg)
  149. {
  150.     struct sockaddr data_addr;
  151.     socklen_t dlen = sizeof (data_addr);
  152.     if (Socket::getsockname(fileno(client.getCtrlFd()), &data_addr, &dlen) < 0) {
  153. emsg = fxStr::format("getsockname(ctrl): %s", strerror(errno));
  154. return (false);
  155.     }
  156.     return initDataConnV6(emsg);
  157. }
  158. bool
  159. InetTransport::initDataConnV4(fxStr& emsg)
  160. {
  161.     struct sockaddr_in data_addr;
  162.     socklen_t dlen = sizeof (data_addr);
  163.     if (client.isPassive()) {
  164. if (client.command("PASV") != FaxClient::COMPLETE)
  165.     return (false);
  166. char *cp = (char*) strchr(client.getLastResponse(), '(');
  167. if (!cp) return (false);
  168. cp++;
  169. unsigned int v[6];
  170. int n = sscanf(cp, "%u,%u,%u,%u,%u,%u", &v[2],&v[3],&v[4],&v[5],&v[0],&v[1]);
  171. if (n != 6) return (false);
  172. if (!inet_aton(fxStr::format("%u.%u.%u.%u", v[2],v[3],v[4],v[5]), &data_addr.sin_addr)) {
  173.     return (false);
  174. }
  175. data_addr.sin_port = htons((v[0]<<8)+v[1]);
  176. data_addr.sin_family = AF_INET;
  177.     } else {
  178. if (Socket::getsockname(fileno(client.getCtrlFd()), &data_addr, &dlen) < 0) {
  179.     emsg = fxStr::format("getsockname(ctrl): %s", strerror(errno));
  180.     return (false);
  181. }
  182. data_addr.sin_port = 0; // let system allocate port
  183.     }
  184.     int fd = socket(AF_INET, SOCK_STREAM, 0);
  185.     if (fd < 0) {
  186. emsg = fxStr::format("socket: %s", strerror(errno));
  187. return (false);
  188.     }
  189.     if (client.isPassive()) {
  190. if (Socket::connect(fd, &data_addr, sizeof (data_addr)) >= 0) {
  191.     if (client.getVerbose())
  192. client.traceServer("Connected to %s at port %u.", 
  193. inet_ntoa(data_addr.sin_addr), ntohs(data_addr.sin_port));
  194. } else {
  195.     emsg = fxStr::format("Can not reach server at %s at port %u (%s).",
  196. inet_ntoa(data_addr.sin_addr), ntohs(data_addr.sin_port), strerror(errno));
  197.     goto bad;
  198. }
  199.     } else {
  200. if (Socket::bind(fd, &data_addr, sizeof (data_addr)) < 0) {
  201.     emsg = fxStr::format("bind: %s", strerror(errno));
  202.     goto bad;
  203. }
  204. dlen = sizeof (data_addr);
  205. if (Socket::getsockname(fd, &data_addr, &dlen) < 0) {
  206.     emsg = fxStr::format("getsockname: %s", strerror(errno));
  207.     goto bad;
  208. }
  209. if (listen(fd, 1) < 0) {
  210.     emsg = fxStr::format("listen: %s", strerror(errno));
  211.     goto bad;
  212. }
  213. const char* a; a = (const char*) &data_addr.sin_addr; // XXX for __GNUC__
  214. const char* p; p = (const char*) &data_addr.sin_port; // XXX for __GNUC__
  215. #define UC(b) (((int) b) & 0xff)
  216. if (client.command("PORT %u,%u,%u,%u,%u,%u",
  217.     UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
  218.     UC(p[0]), UC(p[1])) != FaxClient::COMPLETE)
  219.     return (false);
  220. #undef UC
  221.     }
  222.     client.setDataFd(fd);
  223.     return (true);
  224. bad:
  225.     Sys::close(fd), fd = -1;
  226.     return (false);
  227. }
  228. bool
  229. InetTransport::initDataConnV6(fxStr& emsg)
  230. {
  231.     /*
  232.      *  IPv6 extensions to FTP
  233.      *    http://www.ietf.org/rfc/rfc2428.txt
  234.      */
  235.     char buf[1024];
  236.     Socket::Address data_addr;
  237.     socklen_t dlen = sizeof(data_addr);
  238.     if (client.isPassive()) {
  239. if (Socket::getpeername(fileno(client.getCtrlFd()), &data_addr, &dlen) < 0) {
  240.     emsg = fxStr::format("getsockname(ctrl): %s", strerror(errno));
  241.     return (false);
  242. }
  243. int err = client.command("EPSV");
  244. if (err == FaxClient::COMPLETE) {
  245.     u_int s = client.getLastResponse().next(0, '(');
  246.     u_int e = client.getLastResponse().next(s, ')');
  247.     if (s++ < e && e < client.getLastResponse().length()) {
  248. fxStr p = client.getLastResponse().extract(s, e-s);
  249. char c = p[0];
  250. if (p[0] == c && p[1] == c && p[2] == c && p[p.length()-1] == c)
  251.     Socket::port(data_addr) = htons(p.extract(3, p.length()-4));
  252. else {
  253.     client.printWarning("Couldn't parse last response "%s"", (const char*)client.getLastResponse());
  254.     return(false);
  255. }
  256.     } else {
  257. client.printWarning("Couldn't parse last response "%s"", (const char*)client.getLastResponse());
  258. return(false);
  259.     }
  260. } else if (err == FaxClient::ERROR && Socket::family(data_addr) == AF_INET) {
  261.     client.printWarning("EPSV not supported, trying PASV since we're AF_INETn");
  262.     if (client.command("PASV") != FaxClient::COMPLETE)
  263. return false;
  264.     const char *cp = strchr(client.getLastResponse(), '(');
  265.     if (!cp) {
  266. client.printWarning("Couldn't parse last response "%s"", (const char*)client.getLastResponse());
  267. return (false);
  268.     }
  269.     cp++;
  270.     unsigned int v[6];
  271.     int n = sscanf(cp, "%u,%u,%u,%u,%u,%u", &v[2],&v[3],&v[4],&v[5],&v[0],&v[1]);
  272.     if (n != 6) return (false);
  273.     if (!inet_aton(fxStr::format("%u.%u.%u.%u", v[2],v[3],v[4],v[5]), &data_addr.in.sin_addr)) {
  274. return (false);
  275.     }
  276.     data_addr.in.sin_port = htons((v[0]<<8)+v[1]);
  277.     data_addr.in.sin_family = AF_INET;
  278.     dlen = sizeof(data_addr.in);
  279. }
  280.     } else {
  281. if (Socket::getsockname(fileno(client.getCtrlFd()), &data_addr, &dlen) < 0) {
  282.     emsg = fxStr::format("getsockname(ctrl): %s", strerror(errno));
  283.     return (false);
  284. }
  285. Socket::port(data_addr) = 0; // let system allocate port
  286.     }
  287.     int fd = socket(Socket::family(data_addr), SOCK_STREAM, IPPROTO_TCP);
  288.     if (fd < 0) {
  289. emsg = fxStr::format("socket: %s", strerror(errno));
  290. return (false);
  291.     }
  292.     if (client.isPassive()) {
  293. if (Socket::connect(fd, &data_addr.in, Socket::socklen(data_addr)) >= 0) {
  294.     if (client.getVerbose())
  295. client.traceServer("Connected to %s at port %u.",
  296. inet_ntop(Socket::family(data_addr), Socket::addr(data_addr), buf, sizeof(buf)), ntohs(Socket::port(data_addr)));
  297. } else {
  298.     emsg = fxStr::format("Can not reach server at %s at port %u (%s).",
  299. inet_ntop(Socket::family(data_addr), Socket::addr(data_addr), buf, sizeof(buf)), ntohs(Socket::port(data_addr)), strerror(errno));
  300.     goto bad;
  301. }
  302.     } else {
  303. if (Socket::bind(fd, &data_addr, dlen) < 0) {
  304.     emsg = fxStr::format("bind: %s", strerror(errno));
  305.     goto bad;
  306. }
  307. dlen = sizeof (data_addr);
  308. if (Socket::getsockname(fd, &data_addr, &dlen) < 0) {
  309.     emsg = fxStr::format("getsockname: %s", strerror(errno));
  310.     goto bad;
  311. }
  312. if (listen(fd, 1) < 0) {
  313.     emsg = fxStr::format("listen: %s", strerror(errno));
  314.     goto bad;
  315. }
  316. char hostbuf[128];
  317. char portbuf[64];
  318. getnameinfo((struct sockaddr*)&data_addr, dlen,
  319. hostbuf, sizeof(hostbuf), portbuf, sizeof(portbuf),
  320. NI_NUMERICHOST | NI_NUMERICSERV);
  321. int err = client.command("EPRT |%d|%s|%s|",
  322. (Socket::family(data_addr) == AF_INET6 ? 2 : 1),
  323. hostbuf, portbuf);
  324. if (err == FaxClient::ERROR && Socket::family(data_addr) == AF_INET)
  325. {
  326.     if (client.getVerbose())
  327.     client.printWarning("EPRT not supported, trying PORT");
  328.     const char* a; a = (const char*)&data_addr.in.sin_addr; // XXX for __GNUC__
  329.     const char* p; p = (const char*)&data_addr.in.sin_port; // XXX for __GNUC__
  330. #define UC(b) (((int) b) & 0xff)
  331.     err = client.command("PORT %u,%u,%u,%u,%u,%u",
  332. UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
  333. UC(p[0]), UC(p[1]));
  334. #undef UC
  335. }
  336. if (err != FaxClient::COMPLETE)
  337.     return false;
  338.     }
  339.     client.setDataFd(fd);
  340.     return (true);
  341. bad:
  342.     Sys::close(fd), fd = -1;
  343.     return (false);
  344. }
  345. bool
  346. InetTransport::openDataConn(fxStr& emsg)
  347. {
  348.     if (client.isPassive()) {
  349. return (client.getDataFd() > 0);
  350.     }
  351.     int s = Socket::accept(client.getDataFd(), NULL, NULL);
  352.     if (s >= 0) {
  353. client.setDataFd(s);
  354. #if defined(IP_TOS) && defined(IPTOS_THROUGHPUT)
  355. int tos = IPTOS_THROUGHPUT;
  356. if (Socket::setsockopt(s, IPPROTO_IP, IP_TOS, &tos, sizeof (tos)) < 0)
  357.     client.printWarning("setsockopt(IP_TOS): %s", strerror(errno));
  358. #endif
  359. return (true);
  360.     } else {
  361. emsg = fxStr::format("accept: %s", strerror(errno));
  362. return (false);
  363.     }
  364. }
  365. /*
  366.  * Send an abort request to terminate an operation.
  367.  * The initial interrupt is sent as urgent data to
  368.  * cause the server to process the subsequent ABOR
  369.  * command immediately.  We send IAC in urgent mode
  370.  * instead of DM because 4.3BSD place the out-of-band
  371.  * mark in the data stream after the urgent byte
  372.  * rather than before as done by most contemporary
  373.  * TCP implementations.
  374.  */
  375. bool
  376. InetTransport::abortCmd(fxStr& emsg)
  377. {
  378.     static const u_char msg[] =
  379. { IAC, IP, IAC, DM, 'A', 'B', 'O', 'R', 'r', 'n' };
  380.     int s = fileno(client.getCtrlFd());
  381.     if (send(s, msg, 3, MSG_OOB) != 3) {
  382. emsg = fxStr::format("send(MSG_OOB): %s", strerror(errno));
  383. return (false);
  384.     }
  385.     if (send(s, msg+3, sizeof (msg)-3, 0) != sizeof (msg)-3) {
  386. emsg = fxStr::format("send(<DM>ABOR\r\n): %s", strerror(errno));
  387. return (false);
  388.     }
  389.     return (true);
  390. }
  391. #else
  392. bool InetTransport::callServer(fxStr& emsg)
  393.     { notConfigured("TCP/IP", emsg); return (false); }
  394. bool InetTransport::initDataConn(fxStr& emsg)
  395.     { notConfigured("TCP/IP", emsg); return (false); }
  396. bool InetTransport::openDataConn(fxStr& emsg)
  397.     { notConfigured("TCP/IP", emsg); return (false); }
  398. bool InetTransport::abortDataConn(fxStr& emsg)
  399.     { notConfigured("TCP/IP", emsg); return (false); }
  400. #endif