data.c
上传用户:pycemail
上传日期:2007-01-04
资源大小:329k
文件大小:13k
源码类别:

Ftp客户端

开发平台:

Unix_Linux

  1. /*
  2.  * ProFTPD - FTP server daemon
  3.  * Copyright (c) 1997, 1998 Public Flood Software
  4.  * Copyright (C) 1999, MacGyver aka Habeeb J. Dihu <macgyver@tos.net>
  5.  *  
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 2 of the License, or
  9.  * (at your option) any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program; if not, write to the Free Software
  18.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
  19.  */
  20.  
  21. /*
  22.  * Data connection management functions
  23.  * $Id: data.c,v 1.5 1999/10/01 07:55:01 macgyver Exp $
  24.  */
  25. #include "conf.h"
  26. #include <signal.h>
  27. #ifdef HAVE_SYS_SENDFILE_H
  28. #include <sys/sendfile.h>
  29. #endif /* HAVE_SYS_SENDFILE_H */
  30. /* local macro */
  31. #define MODE_STRING (session.flags & (SF_ASCII|SF_ASCII_OVERRIDE) ? 
  32.  "ASCII" : "BINARY")
  33. /* internal usage: pointer to current data connection IOFILE in
  34.  * use (may be in either read or write mode)
  35.  */
  36. static IOFILE *curf = NULL;
  37. /* called if the "Stalled" timer goes off
  38.  */
  39. static int stalled_timeout(CALLBACK_FRAME)
  40. {
  41. log_pri(LOG_NOTICE,"Data transfer stall timeout: %d seconds",
  42. TimeoutStalled);
  43. end_login(1);
  44. /* prevent compiler warning */
  45. return 0;
  46. }
  47. /* this signal is raised if we get OOB data on the control connection, and
  48.  * a data transfer is in progress
  49.  */
  50. RETSIGTYPE data_urgent(int sig)
  51. {
  52. if(curf) {
  53. session.flags |= SF_ABORT;
  54. io_abort(curf);
  55. }
  56. signal(SIGURG,data_urgent);
  57. }
  58. static
  59. int _translate_ascii(char **buf, int *bufsize, int *adjlen)
  60. {
  61. char *res = *buf;
  62. int newbufsize = 0;
  63. int thislen = *bufsize;
  64. if(**buf == 'n') {
  65. *--res = 'r';
  66. (*buf)++;
  67. newbufsize = 2;
  68. (*adjlen)++; thislen--;
  69. }
  70. while(thislen-- > 0 && newbufsize < *bufsize && **buf != 'n') {
  71. (*buf)++;
  72. newbufsize++;
  73. }
  74. *bufsize = newbufsize;
  75. *buf = res;
  76. return newbufsize;
  77. }
  78. static
  79. void _data_new_xfer(char *filename, int direction)
  80. {
  81. if(session.xfer.p) {
  82. destroy_pool(session.xfer.p);
  83. bzero(&session.xfer,sizeof(session.xfer));
  84. }
  85. session.xfer.p = make_sub_pool(session.pool);
  86. session.xfer.filename = pstrdup(session.xfer.p,filename);
  87. session.xfer.direction = direction;
  88. session.xfer.bufsize = 1024;
  89. session.xfer.buf = (char*)palloc(session.xfer.p,1025);
  90. session.xfer.buf++; /* leave room for ascii translation */
  91. }
  92. static
  93. int _data_pasv_open(char *reason, unsigned long size)
  94. {
  95. conn_t *c;
  96. int rev;
  97. if(!reason && session.xfer.filename)
  98. reason = session.xfer.filename;
  99. /* Set the "stalled" timer, if any, to prevent the connection
  100.          * open from taking too long
  101.          */
  102. if(TimeoutStalled)
  103. add_timer(TimeoutStalled, TIMER_STALLED,
  104. NULL, stalled_timeout);
  105.         rev = inet_reverse_dns(session.xfer.p,ServerUseReverseDNS);
  106. c = inet_accept(session.xfer.p,session.d,-1,-1,TRUE);
  107. inet_reverse_dns(session.xfer.p,rev);
  108. if(c && c->mode != CM_ERROR) {
  109. inet_close(session.pool,session.d);
  110. inet_setnonblock(session.pool,c);
  111. session.d = c;
  112. if(size)
  113. send_response(R_150,"Opening %s mode data connection for %s (%lu bytes).",
  114. MODE_STRING,reason,size);
  115. else
  116. send_response(R_150,"Opening %s mode data connection for %s",
  117. MODE_STRING,reason);
  118. return 0;
  119. }
  120. /* Check for error conditions.
  121.  * - MacGyver
  122.  */
  123. if(c && c->mode == CM_ERROR) {
  124.   log_pri(LOG_ERR,
  125.   "Error: unable to accept an incoming data connection (%s)",
  126.   strerror(c->xerrno));
  127. }
  128. add_response_err(R_425,"Can't build data connection: %s",
  129. strerror(session.d->xerrno));
  130.         destroy_pool(session.d->pool);
  131.         session.d = NULL;
  132. return -1;
  133. }
  134. static
  135. int _data_active_open(char *reason, unsigned long size)
  136. {
  137. conn_t *c;
  138.         int rev;
  139. if(!reason && session.xfer.filename)
  140. reason = session.xfer.filename;
  141. session.d = inet_create_connection(session.pool,NULL,-1,
  142. session.c->local_ipaddr,
  143. session.c->local_port-1,TRUE);
  144. /* Set the "stalled" timer, if any, to prevent the connection
  145.          * open from taking too long
  146.          */
  147. if(TimeoutStalled)
  148. add_timer(TimeoutStalled, TIMER_STALLED, 
  149. NULL, stalled_timeout);
  150. rev = inet_reverse_dns(session.pool,ServerUseReverseDNS);
  151. if(inet_connect(session.d->pool,session.d,&session.data_addr,
  152. session.data_port) == -1) {
  153. add_response_err(R_425,"Can't build data connection: %s",
  154. strerror(session.d->xerrno));
  155. destroy_pool(session.d->pool);
  156.          session.d = NULL;
  157. return -1;
  158. }
  159. c = inet_openrw(session.pool,session.d,NULL,session.d->listen_fd,
  160. -1,-1,TRUE);
  161.         inet_reverse_dns(session.pool,rev);
  162. if(c) {
  163. log_debug(DEBUG4,"active data connection opened - local  : %s:%d",
  164. inet_ntoa(*session.d->local_ipaddr),
  165. session.d->local_port);
  166. log_debug(DEBUG4,"active data connection opened - remote : %s:%d",
  167. inet_ntoa(*session.d->remote_ipaddr),
  168. session.d->remote_port);
  169. if(size)
  170. send_response(R_150,
  171. "Opening %s mode data connection for %s (%lu bytes).",
  172. MODE_STRING,reason,size);
  173. else
  174. send_response(R_150,
  175. "Opening %s mode data connection for %s.",
  176. MODE_STRING,reason);
  177. inet_close(session.pool,session.d);
  178. inet_setnonblock(session.pool,session.d);
  179. session.d = c;
  180. return 0;
  181. }
  182.         
  183. add_response_err(R_425,"Can't build data connection: %s",
  184. strerror(session.d->xerrno));
  185. destroy_pool(session.d->pool);
  186.         session.d = NULL;
  187. return -1;
  188. }
  189. void data_reset()
  190. {
  191. if(session.d && session.d->pool)
  192. destroy_pool(session.d->pool);
  193. session.d = NULL;
  194. session.flags &= (SF_ALL^(SF_ABORT|SF_XFER|SF_PASSIVE|SF_ASCII_OVERRIDE));
  195. }
  196. void data_init(char *filename, int direction)
  197. {
  198. if(!session.xfer.p)
  199. _data_new_xfer(filename,direction);
  200. else {
  201. if(!(session.flags & SF_PASSIVE))
  202. log_debug(DEBUG0,"data_init oddity: session.xfer exists in non-PASV mode.");
  203. session.xfer.direction = direction;
  204. }
  205. }
  206. int data_open(char *filename, char *reason, int direction, unsigned long size)
  207. {
  208. struct sigaction act;
  209. int ret = 0;
  210. if(!session.xfer.p)
  211. _data_new_xfer(filename,direction);
  212. else
  213. session.xfer.direction = direction;
  214. if(!reason)
  215. reason = filename;
  216. if(session.flags & SF_PASSIVE) {
  217. if(!session.d) {
  218. log_pri(LOG_ERR,"Internal error: PASV mode set, but no data connection listening.");
  219. end_login(1);
  220. }
  221. ret = _data_pasv_open(reason,size);
  222. } else { /* active mode */
  223. if(session.d) {
  224. log_pri(LOG_ERR,"Internal error: non-PASV mode, yet data connection already exists?!?");
  225. end_login(1);
  226. }
  227. ret = _data_active_open(reason,size);
  228. }
  229. if(ret >= 0) {
  230. gettimeofday(&session.xfer.start_time,NULL);
  231. if(session.xfer.direction == IO_READ) {
  232. inet_setoptions(session.d->pool,session.d,
  233.         (main_server->tcp_rwin_override ?
  234.                                  main_server->tcp_rwin : 0),0);
  235. inet_set_proto_options(session.pool,session.d,0,0,1,1);
  236. curf = session.d->inf;
  237. } else {
  238. inet_setoptions(session.d->pool,session.d,0,
  239.                                 (main_server->tcp_swin_override ?
  240.                                  main_server->tcp_swin : 0));
  241. inet_set_proto_options(session.pool,session.d,0,0,1,1);
  242. curf = session.d->outf;
  243. }
  244. session.flags |= SF_XFER;
  245. if(TimeoutNoXfer)
  246. reset_timer(TIMER_NOXFER,ANY_MODULE);
  247. /* allow aborts */
  248. /* set curf to allow interrupted syscalls, so our
  249.                  * SIGURG handler can interrupt it
  250.  */
  251. io_set_poll_sleep(curf,1); /* 1 second sleep in select() */
  252. /* PORTABILITY: sigaction is used here to allow us
  253.  * to indicate (w/ POSIX at least) that we want
  254.                  * SIGURG to interrupt syscalls.  Put in whatever
  255.                  * is necessary for your arch here (probably not necessary
  256.                  * as the only _important_ interrupted syscall is select()),
  257.  * which on any sensible system is interrupted.
  258.  */
  259. act.sa_handler = data_urgent;
  260. sigemptyset(&act.sa_mask);
  261. act.sa_flags = 0;
  262. #ifdef SA_INTERRUPT
  263. act.sa_flags |= SA_INTERRUPT;
  264. #endif
  265. sigaction(SIGURG, &act, NULL);
  266. #ifdef HAVE_SIGINTERRUPT
  267. /* this is the BSD way of ensuring interruption.
  268.                  * Linux uses it too (??)
  269.                  */
  270.                 siginterrupt(SIGURG, 1);
  271. #endif
  272. }
  273. return ret;
  274. }
  275. /* close == successful transfer */
  276. void data_close(int quiet)
  277. {
  278. curf = NULL;
  279. if(session.d) {
  280. inet_close(session.pool,session.d);
  281. session.d = NULL;
  282. }
  283. #if 0
  284. if(session.xfer.p)
  285. destroy_pool(session.xfer.p);
  286. bzero(&session.xfer,sizeof(session.xfer));
  287. #endif
  288. session.data_port = session.c->remote_port - 1;
  289. /* aborts no longer necessary */
  290. signal(SIGURG,SIG_IGN);
  291. if(TimeoutNoXfer)
  292. reset_timer(TIMER_NOXFER,ANY_MODULE);
  293. if(TimeoutStalled)
  294. remove_timer(TIMER_STALLED,ANY_MODULE);
  295. session.flags &= (SF_ALL^SF_PASSIVE);
  296. session.flags &= (SF_ALL^(SF_ABORT|SF_XFER|SF_PASSIVE|SF_ASCII_OVERRIDE));
  297. main_set_idle();
  298. if(!quiet)
  299. add_response(R_226,"Transfer complete.");
  300. }
  301. /* Note: true_abort may be false in real abort situations, because
  302.  * some ftp clients close the data connection at the same time as they
  303.  * send the OOB byte (which results in a broken pipe on our
  304.  * end).  Thus, it's a race between the OOB data and the tcp close
  305.  * finishing.  Either way, it's ok (client will see either "Broken pipe"
  306.  * error or "Aborted").  cmd_abor in mod_xfer cleans up the session
  307.  * flags in any case.  session flags will end up have SF_POST_ABORT
  308.  * set if the OOB byte won the race.
  309.  */
  310. void data_cleanup()
  311. {
  312. if(session.xfer.p)
  313. destroy_pool(session.xfer.p);
  314. bzero(&session.xfer,sizeof(session.xfer));
  315. }
  316. void data_abort(int err, int quiet)
  317. {
  318. int true_abort = XFER_ABORTED;
  319. curf = NULL;
  320. if(session.d) {
  321. inet_close(session.pool,session.d);
  322. session.d = NULL;
  323. }
  324. if(session.xfer.p)
  325. destroy_pool(session.xfer.p);
  326. bzero(&session.xfer,sizeof(session.xfer));
  327. session.data_port = session.c->remote_port - 1;
  328. if(TimeoutNoXfer)
  329. reset_timer(TIMER_NOXFER,ANY_MODULE);
  330. if(TimeoutStalled)
  331. remove_timer(TIMER_STALLED,ANY_MODULE);
  332. session.flags &= (SF_ALL^SF_PASSIVE);
  333. session.flags &= (SF_ALL^(SF_XFER|SF_PASSIVE|SF_ASCII_OVERRIDE));
  334. main_set_idle();
  335. /* aborts no longer necessary */
  336. signal(SIGURG,SIG_IGN);
  337. if(TimeoutNoXfer)
  338. reset_timer(TIMER_NOXFER,ANY_MODULE);
  339. if(!quiet) {
  340. if(err)
  341. add_response_err(R_425,"Data connection error: %s",
  342. strerror(err));
  343. else
  344. add_response_err(R_426,"Transfer aborted. Data connection closed.");
  345. }
  346. if(true_abort)
  347. session.flags |= SF_POST_ABORT;
  348. }
  349. /* data_xfer actually transfers the data on the data connection ..
  350.  * ascii translation is performed if necessary.  direction set
  351.  * when data connection was opened determine if the client buffer
  352.  * is read from or written to.  return 0 if reading and data connection
  353.  * closes, or -1 if error
  354.  */
  355. int data_xfer(char *cl_buf, int cl_size)
  356. {
  357. char *buf = session.xfer.buf;
  358. int len = 0;
  359. int total = 0;
  360. if(session.xfer.direction == IO_READ) {
  361. if((len = io_read(session.d->inf,cl_buf,cl_size, 1)) > 0) {
  362. if(TimeoutStalled)
  363. reset_timer(TIMER_STALLED, ANY_MODULE);
  364. if(session.flags & (SF_ASCII|SF_ASCII_OVERRIDE)) {
  365. char *cp = cl_buf, *dest = cl_buf;
  366. register int i = len;
  367. while(i--)
  368. if(*cp != 'r')
  369. *dest++ = *cp++;
  370. else {
  371. len--; total++;
  372. cp++;
  373. }
  374. }
  375. total += len;
  376. }
  377. } else { /* IO_WRITE */
  378. /* copy client buffer to internal buffer, and
  379.  * xlate ascii as necessary
  380.  */
  381. while(cl_size) {
  382. int o_size,size = cl_size;
  383. int wsize,adjlen;
  384. char *wb;
  385. if(size > 1024)
  386. size = 1024;
  387. o_size = size;
  388. bcopy(cl_buf,buf,size);
  389. while(size) {
  390. wb = buf; wsize = size; adjlen = 0;
  391. if(session.flags & (SF_ASCII|SF_ASCII_OVERRIDE))
  392. _translate_ascii(&wb,&wsize,&adjlen);
  393. if(io_write(session.d->outf,wb,wsize) == -1)
  394. return -1;
  395. if(TimeoutStalled)
  396. reset_timer(TIMER_STALLED, ANY_MODULE);
  397. total += wsize;
  398. size -= (wsize - adjlen);
  399. if(size) {
  400. wb = buf + (wsize - adjlen);
  401. bcopy(wb,buf,size);
  402. }
  403. }
  404. cl_size -= o_size;
  405. cl_buf += o_size;
  406. }
  407. len = total;
  408. }
  409. if(total && TimeoutIdle)
  410. reset_timer(TIMER_IDLE,ANY_MODULE);
  411. session.xfer.total_bytes += total;
  412. session.total_bytes += total;
  413. return len;
  414. }
  415. #ifdef HAVE_SENDFILE
  416. /* data_sendfile actually transfers the data on the data connection.
  417.  * ascii translation is not performed.
  418.  * return 0 if reading and data connection closes, or -1 if error
  419.  */
  420. int data_sendfile(int retr_fd, off_t *offset, size_t count)
  421. {
  422.   int flags, error, len = 0;
  423.   
  424.   if(session.xfer.direction == IO_READ)
  425.     return -1;
  426.   
  427.   if((flags = fcntl(session.d->outf->fd, F_GETFL)) == -1)
  428.     return -1;
  429.   
  430.   /* set fd to blocking-mode for sendfile() */
  431.   if (flags & O_NONBLOCK)
  432.     if(fcntl(session.d->outf->fd, F_SETFL, flags ^ O_NONBLOCK) == -1)
  433.       return -1;
  434.   
  435.   log_pri(LOG_ERR, "data_sendfile(%d,%d,%d)", retr_fd, *offset, count);
  436.   
  437.   if ((len = sendfile(session.d->outf->fd, retr_fd, offset, count)) == -1) {
  438.     error = errno;
  439.     fcntl(session.d->outf->fd, F_SETFL, flags);
  440.     errno = error;
  441.     
  442.     return -1;
  443.   }
  444.   
  445.   log_pri(LOG_ERR, "data_sendfile: %d", len);
  446.   
  447.   if (flags & O_NONBLOCK)
  448.     fcntl(session.d->outf->fd, F_SETFL, flags);
  449.   
  450.   if(TimeoutStalled)
  451.     reset_timer(TIMER_STALLED, ANY_MODULE);
  452.   
  453.   if(TimeoutIdle)
  454.     reset_timer(TIMER_IDLE, ANY_MODULE);
  455.   
  456.   session.xfer.total_bytes += len;
  457.   session.total_bytes += len;
  458.   
  459.   return len;
  460. }
  461. #endif /* HAVE_SENDFILE */