1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
|
/* respond.c - twoftpd routines for responding to clients
* Copyright (C) 2008 Bruce Guenter <bruce@untroubled.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <errno.h>
#include <string.h>
#include <iobuf/iobuf.h>
#include <systime.h>
#include "twoftpd.h"
#include "log.h"
extern int errno;
int log_responses = 0;
int respond_start(unsigned code, int final)
{
const char* sep = final ? " " : "-";
if (log_responses) {
log_start();
log_uint(code);
log_str(sep);
}
return obuf_putu(&outbuf, code) && obuf_puts(&outbuf, sep);
}
int respond_end(void)
{
if (log_responses) log_end();
return obuf_putsflush(&outbuf, "\r\n");
}
int respond_str(const char* str)
{
if (log_responses) log_str(str);
/* Translate LF to NUL and \377 to \377\377 on output */
for (; *str; ++str)
switch (*str) {
case LF:
if (!obuf_putc(&outbuf, 0)) return 0;
break;
case '\377':
if (!obuf_putc(&outbuf, '\377')) return 0;
/* Fall through and output the \377 again */
default:
if (!obuf_putc(&outbuf, *str)) return 0;
}
return 1;
}
int respond_uint(unsigned long num)
{
if (log_responses) log_uint(num);
return obuf_putu(&outbuf, num);
}
int respond_syserr(unsigned code, const char *msg)
{
return respond_start(code, 1) &&
respond_str(msg) &&
respond_str(": ") &&
respond_str(strerror(errno)) &&
respond_end();
}
int respond(unsigned code, int final, const char* msg)
{
return respond_start(code, final) &&
respond_str(msg) &&
respond_end();
}
static struct timeval start;
void respond_start_xfer(void)
{
gettimeofday(&start, 0);
}
static const char* scales[] = { "", "k", "M", "G", "T", 0 };
static int respond_bytes(unsigned code,
const char* msg, unsigned long bytes, int sent)
{
struct timeval end;
unsigned long rate;
int scaleno;
gettimeofday(&end, 0);
rate = bytes / (end.tv_sec-start.tv_sec +
(end.tv_usec-start.tv_usec)/1000000.0);
for (scaleno = 0;
rate > 10000 && scales[scaleno+1] != 0;
++scaleno, rate /= 1024)
;
return respond_start(code, 1) &&
respond_str(msg) &&
respond_str(" (") &&
respond_uint(bytes) &&
respond_str(sent ? " bytes sent, " : " bytes received, ") &&
respond_uint(rate) &&
respond_str(scales[scaleno]) &&
respond_str("B/s).") &&
respond_end();
}
int respond_xferresult(unsigned result, unsigned long bytes, int sent)
{
switch (result) {
case 0:
return respond_bytes(226, "Transfer completed", bytes, sent);
case 1:
return respond_bytes(426, "Transfer timed out", bytes, sent);
case 2:
return respond_bytes(426, "Transfer interrupted", bytes, sent);
default:
return respond_bytes(451, "Transfer failed", bytes, sent);
}
}
|