reworked path parse engine

This commit is contained in:
hsn 2003-11-20 22:35:15 +00:00
parent 488c23e932
commit 5cc1497967
17 changed files with 254 additions and 92 deletions

View File

@ -1,3 +1,27 @@
Version NEXT
PROTOCOL updated. Made rules about breaking directory header on
packet boundary more clear. Previous text was from fspd code comment
and was bad.
fixed tests/mklargefile.py
log uploads to wuftpd logfile also
PROTOCOL file updated. Added required commands section.
PROTOCOL file updated. Added recommended delay management section.
default delay in clients adjusted from 1.5 to 1.34 sec as recommended
in PROTOCOL
support for MIN_DELAY, MAX_DELAY and DEFAULT_DELAY in source
path parsing moved to separate file server/path.c
new test tool parsecheck
reworked parse path: separate error messages for high bit chars,
control chars
do not segfault when parsing password protected files. Looks like
nobody used password protected files for a long time. This means
that in future version of FSP I can change protocol definition
without worry about breaking anything
path with trailing / or starting / is now parsed correctly
pathes with dot after slash are now detected at parse level (side
effect of prev. fix)
tests moved from server/ into tests/ directory
Version 2.8.1b17 -- 17 Nov 2003
Allow filenames with spaces inside
check for fork() and setsid() in configure.ac

5
TODO
View File

@ -59,7 +59,7 @@ bind-ip-address for server (and client via FSP_LOCAL_IP)
report number of clients connected, size of hostable in new command
CC_INFO command
special defence against rapid/double fire clients
new common log format
common log format - replace custom fspd log
:midle:may not be in 2.8.2
Native Supports for symbolic links (needed for mirroring Debian)
@ -80,6 +80,7 @@ PERFORMANCE:
host hashtable shrinking sometimes
stat cache pro FSP_STAT a ostatni
background time() alarm() caller
Current performance 1925648b/s
MAN:
update FAQ - urgent!!
@ -93,4 +94,4 @@ FSP plugin do Netscape/MSIE
FSP library for Java
Transfer HTTP over fsp transport
FSP backend for APT
FSP support to lftp
FSP support to lftp,wget,curl

View File

@ -26,9 +26,9 @@ static unsigned short key;
int client_trace = 0;
int client_intr_state = 0;
unsigned long target_delay = MIN_DELAY; /* expected max delay */
unsigned long busy_delay = MIN_DELAY; /* busy retransmit timer */
unsigned long idle_delay = MIN_DELAY; /* idle retransmit timer */
unsigned long target_delay = DEFAULT_DELAY; /* expected max delay */
unsigned long busy_delay = DEFAULT_DELAY; /* busy retransmit timer */
unsigned long idle_delay = DEFAULT_DELAY; /* idle retransmit timer */
unsigned long udp_sent_time;
UBUF *client_interact PROTO6(unsigned char, cmd, unsigned long, pos,
@ -79,7 +79,8 @@ UBUF *client_interact PROTO6(unsigned char, cmd, unsigned long, pos,
case 1:
busy_delay = busy_delay * 3 / 2;
w_delay = busy_delay;
if(client_trace) write(2,"R",1); break;
if(client_trace) write(2,"R",1);
break;
default:
#ifdef CLIENT_TIMEOUT

View File

@ -448,6 +448,7 @@ static void util_get_env PROTO0((void))
if( (p = getenv("FSP_DELAY")) ) target_delay = atol(p);
if(target_delay < MIN_DELAY) target_delay = MIN_DELAY;
if(target_delay > MAX_DELAY) target_delay = MAX_DELAY;
if(!(env_local_dir = getenv("FSP_LOCAL_DIR"))) env_local_dir=".";

View File

@ -1,6 +1,6 @@
dnl Process this file with autoconf to produce a working configure script.
dnl tested with autoconf 2.57
AC_INIT(fsp,2.8.1b17,hsn@cybermail.net)
AC_INIT(fsp,2.8.1b17+cvs,hsn@cybermail.net)
AC_CONFIG_SRCDIR(server/main.c)
AM_INIT_AUTOMAKE([dist-bzip2])
AM_MAINTAINER_MODE
@ -53,10 +53,10 @@ then
-Wimplicit -Wsequence-point -Wreturn-type \
-Wfloat-equal $addopts \
-Wno-system-headers -Wredundant-decls \
-Wmissing-noreturn -Wconversion -pedantic \
-Wmissing-noreturn -pedantic \
-Wlong-long -Wundef -Winline \
-Wno-unused-parameter
# -Wunreachable-code
# -Wunreachable-code -Wconversion
do
if $CC $i $ac_cv_prog_gcc_flags -c configure-dummy.c >/dev/null 2>&1
then ac_cv_prog_gcc_flags="$ac_cv_prog_gcc_flags $i"

View File

@ -1,8 +1,8 @@
File Service Protocol (FSP)
definition
File Service Protocol version 2
specification
Document version 0.8
Last updated 29 Sep 2003
Document version 0.9
Last updated 18 Nov 2003
Also known as
File Slurping Protocol,
@ -73,6 +73,9 @@ TIMEOUTS
Resends:
Server will accept resent message from client with old KEY after 3 seconds.
Client MUST wait at least 1 second before resending a message.
It is recommended to use initial delay of 1.34 second and after each
unsuccessfull resend multiply delay time by 1.5. Maximum recommended delay
time is 300 seconds.
Session:
Server will accept message with bad key after 60 seconds. Clients should
sent CC_BYE at end of their session, CC_BYE terminates a session.
@ -82,7 +85,7 @@ SEQUENCE
Similarly, the server's message to client contains a SEQUENCE value
that is the same as the SEQUENCE value of the previous message from the client.
Client can choose any SEQUENCE number and can use it for detection of lost
packets (increase sequence number on retry).
packets (increase sequence number on message resend).
DATA_LENGTH
Size of DATA field in packet. Packet can also contain XTRA DATA field but
@ -96,6 +99,16 @@ data.
FSP COMMANDS
============
REQUIRED COMMANDS
FSP File servers MUST supports following commands:
- sending error messages back to client with CC_ERR
- directory listings CC_GET_DIR
- file transfer CC_GET_FILE
- file status CC_STAT
- information about directory flags CC_GET_PRO
- terminate session CC_BYE
CC_VERSION 0x10 - Get server version string and setup
request
@ -157,7 +170,7 @@ boundary, then two possible things will happen:
1) if the HEADER fits between this entry and the 1k boundary,
a complete header will be filled in with a 'type' set to RDTYPE_SKIP.
And then enough bytes to pad to 1k boundary.
Repeat this step as neceseary until no HEADER fits.
2) if the HEADER does not fit, then simply pad to the 1k boundary.
This will make sure that messages carrying directory information carry only

View File

@ -167,6 +167,8 @@ typedef struct RDIRENT { unsigned char bb_time[4];
#define NULLP ((char *) 0)
#define MIN_DELAY 1500L
#define MIN_DELAY 1000L
#define DEFAULT_DELAY 1340L
#define MAX_DELAY 300000L
#endif /* _FSP_COMMON_DEF_H_ */

View File

@ -25,6 +25,7 @@ int init_caches PROTO0((void));
void shutdown_caches PROTO0((void));
void stat_caches PROTO1(FILE *,fp);
const char *validate_path PROTO0((char *, unsigned, PPATH *,DIRINFO **, int));
const char *parse_path PROTO3(char *, fullp, unsigned int, len, PPATH *, pp);
const char *server_get_dir PROTO0((DIRLISTING **,const DIRINFO *));
const char *server_del_file PROTO0((PPATH *, DIRINFO *));
const char *server_del_dir PROTO2(PPATH *, pp, DIRINFO *,di);

View File

@ -1,15 +1,10 @@
## Process this file with automake to produce Makefile.in
bin_PROGRAMS=fspd
if MAINTAINER_MODE
noinst_PROGRAMS=cachecheck
endif
fspd_SOURCES=file.c host.c main.c conf.c filecache.c server.c fifocache.c \
log.c iprange.c acl.c
log.c iprange.c acl.c path.c
fspd_CFLAGS=-DSYSCONFDIR="\"@sysconfdir@\"" $(AM_CFLAGS)
fspd_LDADD=-L../common -lcommon
cachecheck_SOURCES=fifocache.c cachecheck.c
noinst_HEADERS=fifocache.h

View File

@ -227,72 +227,6 @@ void shutdown_caches PROTO0((void))
f_cache_destroy(fpcache);
}
/*****************************************************************************
* Routine to parse a path string given by the client.
* Will replace null string by ".".
* In case of error, returns the error string.
*
* The PPATH structure is filled in by the function check_path when given a
* path string. The elements are filled in as such:
*
* fullp pointer to a string containing the full path name
* f_ptr pointer to begining of the last component of the path
* f_len length of the last component of the path
* d_ptr pointer to begining of the directory part of path
* d_len length of the directory part of the path
* passwd ptr to password
*
* fullp is a null-terminated full path string.
* f_ptr is always a null-terminated sub-string of fullp.
* d_ptr is generally not null-terminated.
*****************************************************************************/
static const char *parse_path PROTO3(char *, fullp, unsigned int, len, PPATH *, pp)
{
char *s;
int state;
if(len < 1) return("Path must have non-zero length");
if(fullp[len-1]) return("Path not null terminated");
pp->d_ptr = "."; pp->d_len = 1; /* initial dir part ---> root */
pp->passwd = NULL; /* default, no password */
if(len == 1 && fullp[0] == 0) { /* null path --> root */
pp->fullp = pp->f_ptr = ".";
pp->f_len = 1;
return(NULLP);
}
for(s = pp->fullp = pp->f_ptr = fullp, state = 0; *s; s++) {
if(*s == '\n') {
pp->passwd = s+1;
*s = '\0';
if(dbug) fprintf(stderr,"parse_path: found password field %s\n", s+1);
}
else if(*s < ' ' || *s >= '~') return("Path contains illegal chars");
switch(*s) {
case '\\':
case '.':
if(state==0) return("Path can't begin with '.' or '\\'");
break;
case '/':
if(state!=0)
{
pp->d_ptr=fullp;
pp->d_len=s-fullp;
pp->f_ptr=s+1;
}
default:
state = 1;
break;
}
}
pp->f_len = s - pp->f_ptr;
return(NULLP);
}
/*****************************************************************************

119
server/path.c Normal file
View File

@ -0,0 +1,119 @@
/*********************************************************************\
* Copyright (c) 2003 by Radim Kolar (hsn@cybermail.net) *
* Copyright (c) 1991 by Wen-King Su (wen-king@vlsi.cs.caltech.edu) *
* *
* You may copy or modify this file in any manner you wish, provided *
* that this notice is always included, and that you hold the author *
* harmless for any loss or damage resulting from the installation or *
* use of this software. *
\*********************************************************************/
#include "tweak.h"
#include "server_def.h"
#include "s_extern.h"
/*****************************************************************************
* Routine to parse a path string given by the client.
* input: fullp - pointer to path for parsing
* len - length of the path for parsing
* Will replace null string by ".".
* In case of error, returns the error string.
*
* The PPATH structure is filled in by the function check_path when given a
* path string. The elements are filled in as such:
*
* fullp pointer to a string containing the full path name
* f_ptr pointer to begining of the last component of the path
* f_len length of the last component of the path
* d_ptr pointer to begining of the directory part of path
* d_len length of the directory part of the path
* passwd ptr to password
*
* fullp is a null-terminated full path string.
* f_ptr is always a null-terminated sub-string of fullp.
* d_ptr is generally not null-terminated.
*****************************************************************************/
const char *parse_path PROTO3(char *, fullp, unsigned int, len, PPATH *, pp)
{
char *s;
int state;
if(len < 1) return("Path must have non-zero length");
if(fullp[len-1]) return("Path not null terminated");
pp->passwd = NULL; /* default, no password */
pp->d_len = 0;
if(len == 1 && fullp[0] == 0)
{
/* null path --> root */
pp->fullp = pp->f_ptr = pp->d_ptr = ".";
pp->f_len = pp->d_len = 1;
return(NULLP);
}
for(s = pp->fullp = pp->f_ptr = pp->d_ptr = fullp, state = 0; *s; s++)
{
if(*s == '\n')
{
pp->passwd = s+1;
*s = '\0';
if(dbug) fprintf(stderr,"parse_path: found password field %s\n", s+1);
break;
}
else
if(*s < ' ') return("Path contains control chars");
else
if(*s >= '~') return("Path contains high chars");
switch(*s)
{
case '\\':
case '.':
if(state==0) return("Path can't begin with '.' or '\\'");
if(state==2) return("Files can't begin with '.'");
default:
state = 1;
break;
case '/':
pp->f_ptr=s+1;
switch(state)
{
case 0:
/* state 0: front slashes */
pp->fullp=s+1;
pp->d_ptr=s+1;
pp->d_len=0;
break;
case 1:
/* state 1: slash after nonslash */
pp->d_len= s-pp->fullp;
state=2;
break;
case 2:
break;
}
}
}
/* pp->d_len = pp->f_ptr - pp->fullp; */
/* turn empty directory into "." */
if(pp->d_len == 0)
{
pp->d_ptr = ".";
pp->d_len = 1;
}
pp->f_len = s - pp->f_ptr;
/* turn empty file into "." */
if(pp->f_len == 0)
{
pp->f_ptr = ".";
pp->f_len = 1;
}
return(NULLP);
}

View File

@ -701,6 +701,8 @@ static void server_process_packet PROTO5(unsigned, bytes, UBUF *, ub, int, old,
return;
}
ACTIONOK(L_INSTALL);
FSP_STAT(pp.fullp,&sd); /* log filesizes */
xferlog('i',pp.fullp,sd.st_size,inetstr);
}
server_reply(from,ub,0,0);
return;

View File

@ -2,3 +2,5 @@
Makefile
Makefile.in
mklargefile
cachecheck
parsecheck

View File

@ -1,2 +1,7 @@
noinst_PROGRAMS=mklargefile
noinst_PROGRAMS=mklargefile cachecheck parsecheck
extra_DIST=mklargefile.py
cachecheck_SOURCES=../server/fifocache.c cachecheck.c
parsecheck_SOURCES=parsecheck.c ../server/path.c

View File

@ -7,7 +7,7 @@
#include <assert.h>
#include <stdlib.h>
#include "tweak.h"
#include "fifocache.h"
#include "../server/fifocache.h"
static int intcompare(const int *i1,const int *i2)
{

View File

@ -7,6 +7,6 @@ if __name__ == '__main__':
else:
GB=1024*1024*1024
f=open(sys.argv[1],'w')
f.seek(long(sys.argv[2])*GB)
f.seek(long(float(sys.argv[2])*GB))
f.write('!')
f.close();

62
tests/parsecheck.c Normal file
View File

@ -0,0 +1,62 @@
#include "tweak.h"
#include "server_def.h"
#include "s_extern.h"
#ifdef STDC_HEADERS
#include <stdlib.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "my-string.h"
int dbug=0;
const char *testcases[]={ "", ".","filename","/filename","//filename","//dirname/filename","//dirname//filename","dirname//dir3name//","filename\npasswd",
"file/.dir","directory.ext/filename.",
NULL};
static void print_path(PPATH *pp)
{
printf("fullpath: %s ",pp->fullp);
if(strcmp(pp->fullp,pp->d_ptr))
{
printf("d_ptr: %s (%d) ",pp->d_ptr,pp->d_len);
} else
printf("(%d) ",pp->d_len);
printf("f_ptr: %s (%d) ",pp->f_ptr,pp->f_len);
if(pp->passwd)
printf("passwd: %s",pp->passwd);
}
static void runtestcase(void)
{
int i=0;
PPATH pp;
const char *err;
const char *test;
for(;testcases[i];i++)
{
test=strdup(testcases[i]);
err=parse_path(test,strlen(test)+1,&pp);
printf("parsing: '%s'",test);
if(err)
{
printf(" err: %s\n",err);
free(test);
continue;
} else
printf(" okay.\n");
printf(" ");
print_path(&pp);
printf("\n");
free(test);
}
}
int main(int argc,const char *argv[])
{
runtestcase();
return 0;
}