From 04db7ca7ed3bfb4df76d3df4b418f9a7c3d97ab2 Mon Sep 17 00:00:00 2001 From: teodor Date: Wed, 22 Sep 2004 10:59:48 +0000 Subject: [PATCH 1/1] Initial revision --- Makefile | 36 +++ connection.h | 157 ++++++++++ connpool.c | 80 +++++ hextest.c | 54 ++++ inftest.c | 55 ++++ kilter.c | 308 ++++++++++++++++++++ prs_hmap.c | 150 ++++++++++ prs_hmap.h | 41 +++ prs_inf.c | 330 +++++++++++++++++++++ prs_inf.h | 52 ++++ regis.c | 177 +++++++++++ regis.h | 63 ++++ res | 9 + sfxstr.c | 806 +++++++++++++++++++++++++++++++++++++++++++++++++++ sfxstr.h | 220 ++++++++++++++ sfxtest.c | 346 ++++++++++++++++++++++ shmem.c | 129 +++++++++ shmem.h | 40 +++ tcp.c | 444 ++++++++++++++++++++++++++++ test.inf | 23 ++ tlog.c | 142 +++++++++ tlog.h | 58 ++++ tmalloc.c | 119 ++++++++ tmalloc.h | 45 +++ tools.c | 102 +++++++ tools.h | 42 +++ udp.c | 156 ++++++++++ 27 files changed, 4184 insertions(+) create mode 100644 Makefile create mode 100644 connection.h create mode 100644 connpool.c create mode 100644 hextest.c create mode 100644 inftest.c create mode 100644 kilter.c create mode 100644 prs_hmap.c create mode 100644 prs_hmap.h create mode 100644 prs_inf.c create mode 100644 prs_inf.h create mode 100644 regis.c create mode 100644 regis.h create mode 100644 res create mode 100644 sfxstr.c create mode 100644 sfxstr.h create mode 100644 sfxtest.c create mode 100644 shmem.c create mode 100644 shmem.h create mode 100644 tcp.c create mode 100644 test.inf create mode 100644 tlog.c create mode 100644 tlog.h create mode 100644 tmalloc.c create mode 100644 tmalloc.h create mode 100644 tools.c create mode 100644 tools.h create mode 100644 udp.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..cdd4683 --- /dev/null +++ b/Makefile @@ -0,0 +1,36 @@ +CC=gcc +AR=ar rcv +RANLIB=ranlib +LD=ld -x -shared + +INCLUDE=-I. +CFLAGS=-Wall -g -O2 -pedantic -ansi -DASSERT_CORE -D_GNU_SOURCE -DHAVE_POLL_H -DHAVE_SYS_POLL_H -DHAVE_HSTRERROR +LIB=-L. -ltedtools + +OBJS=tlog.o tmalloc.o tools.o prs_hmap.o sfxstr.o \ + regis.o prs_inf.o shmem.o tcp.o udp.o connpool.o +PROGS=sfxtest hextest inftest kilter + +.SUFFIXES: .o.c + +all: libtedtools.a $(PROGS) + +$(PROGS): %: %.o + $(CC) -o $@ $< $(LIB) + +$(PROGS): libtedtools.a + +libtedtools.a: $(OBJS) + $(AR) $@ $? + $(RANLIB) $@ + +.c.o: + $(CC) $(CFLAGS) $(INCLUDE) -c $< + +clean: + rm -rf $(OBJS) + rm -rf $(PROGS) *.o + rm -rf libtedtools.a + rm -rf *core *gmon* nohup.out + rm -rf sfxtest.log + diff --git a/connection.h b/connection.h new file mode 100644 index 0000000..2bc936d --- /dev/null +++ b/connection.h @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2004 Teodor Sigaev + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __CONNECTION_H__ +#define __CONNECTION_H__ + +#include +#include +#include +#include +#include + + + +#define CS_OK 0 +#define CS_INPROCESS 1 +#define CS_CONNECTED 2 +#define CS_READ 3 +#define CS_SEND 4 +#define CS_WAIT 5 +#define CS_ERROR 6 +#define CS_FINISHSEND 7 +#define CS_FINISHREAD 8 +#define CS_TIMEOUT 9 +#define CS_CLOSED 10 +#define CS_NOTINITED 11 +#define CS_AGAIN 12 +#define CS_FINISH 13 + + +#define READ_INCRIMENT_BUFSIZ 1024 + +typedef struct { + /* I/O buffer */ + u_int32_t len; + char *buf; + char *ptr; + + /* internal fields */ + int fd; + u_int32_t + readyio:1, + state:29; + struct sockaddr_in serv_addr; + + /* external link */ + void* data; +} TC_Connection; + +#define TCCONNHDRSZ ( sizeof(TC_Connection) - sizeof(void*) ) + +TC_Connection *TC_fillConnection( TC_Connection *cs, char *name, u_int32_t port ); +TC_Connection* TC_AcceptTcp(TC_Connection *cs); +u_int32_t TC_ClientInitConnection(TC_Connection *cs, char *name, u_int32_t port); +u_int32_t TC_ServerInitConnect( TC_Connection *cs ); +u_int32_t TC_ServerConnect( TC_Connection *cs ); +u_int32_t TC_Send( TC_Connection *cs ); +u_int32_t TC_Read( TC_Connection *cs ); +u_int32_t TC_Talk( TC_Connection *cs ); +void TC_FreeConnection( TC_Connection *cs ); +int TC_ReadyIO( TC_Connection **cs, int number, int timeout ); + +typedef struct { + u_int32_t len; + u_int32_t type; + char data[1]; +} TCMsg; + +#define TCMSGHDRSZ (2*sizeof(u_int32_t)) + + +/* udp */ +typedef struct { + char *host; + u_int32_t port; + TCMsg *msg; + + /* private members */ + int sockfd; + struct sockaddr_in host_addr; +} Msg; + +/* + * Udp server loop: + * TC_Connection conn,*connptr; + * conn.fd = TC_AcceptUdp("127.0.0.1", 5432); + * conn.state = CS_READ; + * connptr = &conn; + * while(1) { + * if ( TC_ReadyIO( &connptr, 1, 100 ) ) { + * Msg m; + * if ( TC_getMsg(conn.fd, &m) == CS_OK ) { + * //do something + * } + * } + * } + * close(conn.fd); + * + * Udp client send: + * Msg msg; + * msg.host = "127.0.0.1"; + * msg.port = 5432; + * msg.sockfd =-1; + * msg.msg = GOTFILLEDPMSG(); + * if ( TC_sendMsg(&msg)!=CS_OK ) { + * //Very bad + * } + * msg.msg = GOTFILLEDPMSG(); + * if ( TC_sendMsg(&msg)!=CS_OK ) { + * //Very bad + * } + * TC_closefd(&msg); + */ + +int TC_AcceptUdp(char *host, int port); +u_int32_t TC_getMsg( int sockfd, Msg *msg ); +u_int32_t TC_sendMsg( Msg *msg ); +void TC_closefd( Msg *msg ); + +typedef struct { + u_int32_t len; + u_int32_t number; + TC_Connection **conn; +} PoolConnection; + +void TC_addConnection(PoolConnection *pool, TC_Connection *c); +void TC_deleteConnectionByN(PoolConnection *pool, int n); +void TC_deleteConnectionByC(PoolConnection *pool, TC_Connection *c); + +#endif + diff --git a/connpool.c b/connpool.c new file mode 100644 index 0000000..c91a384 --- /dev/null +++ b/connpool.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2004 Teodor Sigaev + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include "connection.h" +#include "tlog.h" +#include "tmalloc.h" + + +void +TC_addConnection(PoolConnection *pool, TC_Connection *c) { + if (!c) + return; + if ( pool->number >= pool->len ) { + if ( pool->len == 0 ) { + pool->len = 8; + pool->conn = (TC_Connection**)tmalloc( sizeof(TC_Connection*) * pool->len ); + } else { + pool->len *= 2; + pool->conn = (TC_Connection**)trealloc( pool->conn, sizeof(TC_Connection*) * pool->len ); + } + } + pool->conn[ pool->number ] = c; + pool->number++; +} + +void +TC_deleteConnectionByN(PoolConnection *pool, int n) { + if ( n<0 || n>=pool->number || pool->len<=0 ) + return; + + TC_FreeConnection( pool->conn[ n ] ); + free( pool->conn[ n ] ); + if ( n==pool->number-1 ) { + pool->number--; + return; + } + + memcpy( &( pool->conn[ n ] ), &( pool->conn[ n+1 ] ), sizeof(TC_Connection*) * ( pool->number - n - 1 )); + pool->number--; + return; +} + +void +TC_deleteConnectionByC(PoolConnection *pool, TC_Connection *c) { + int i; + for(i=0;inumber;i++) + if ( pool->conn[ i ] == c ) { + TC_deleteConnectionByN(pool, i); + break; + } +} diff --git a/hextest.c b/hextest.c new file mode 100644 index 0000000..6003a5b --- /dev/null +++ b/hextest.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2004 Teodor Sigaev + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +#include "tools.h" +#include "tmalloc.h" +#include "tlog.h" + + +int +main(int argn, char *argv[]) { + int i; + + for(i=0;i<20;i++) { + u_int32_t orig = (u_int32_t) ( (random()%2) ? random() : rand() ); + u_int32_t new = atox( xtostr(orig) ); + char buf[10]; + printf("ORIG:%d\tORIGHEX:%x\txtostr:%s\tatox(xtostr):%d\n", orig, orig, xtostr(orig), new); + tassert( orig==new ); + sprintf(buf,"%x", orig); + tassert( strcmp(buf, strlower(xtostr(orig)))==0 ); + } + + return 0; +} diff --git a/inftest.c b/inftest.c new file mode 100644 index 0000000..9f76304 --- /dev/null +++ b/inftest.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2004 Teodor Sigaev + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "prs_inf.h" + +int +main(int argn, char *argv[] ) { + InfMap *map, *ptr; + + if ( argn!=2 ) { + puts("Usage:"); + puts("./inftest inffile"); + return 1; + } + + map=ptr=INFParse(argv[1]); + while(ptr&&ptr->section) { + printf("S:'%s' K:'%s' V:'%s'\n", + ptr->section, + (ptr->key) ? ptr->key : "(NULL)", + (ptr->value) ? ptr->value : "(NULL)" + ); + ptr++; + } + INFFree(map); + return 0; +} diff --git a/kilter.c b/kilter.c new file mode 100644 index 0000000..78866a1 --- /dev/null +++ b/kilter.c @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2004 Teodor Sigaev + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tlog.h" +#include "tmalloc.h" + +static int exitAfterLastSignal=0; +static int kilterDebug=0; + +static void +usage() { + puts("Copyright (c) 2004 Teodor Sigaev . All rights reserved."); + puts("Usage:"); + puts("kilter [-d] [-e] -SIGNAL [+]TIMEOUT [-SIGNAL [+]TIMEOUT [...]] COMMAND"); + puts(" -d - debug mode"); + puts(" -e - don't wait child exit after last signal sended"); + puts(" +TIMEOUT - means related time to previous"); + + exit(1); +} + +typedef struct { + char *name; + unsigned int sign; +} SigName; + +static SigName signalname[]={ + { "HUP", SIGHUP }, + { "INT", SIGINT }, + { "QUIT", SIGQUIT }, + { "ILL", SIGILL }, + { "TRAP", SIGTRAP }, + { "ABRT", SIGABRT }, +/* { "EMT", SIGEMT }, */ + { "FPE", SIGFPE }, + { "KILL", SIGKILL }, + { "BUS", SIGBUS }, + { "SEGV", SIGSEGV }, + { "SYS", SIGSYS }, + { "PIPE", SIGPIPE }, + { "ALRM", SIGALRM }, + { "TERM", SIGTERM }, + { "URG", SIGURG }, + { "STOP", SIGSTOP }, + { "TSTP", SIGTSTP }, + { "CONT", SIGCONT }, + { "CHLD", SIGCHLD }, + { "TTIN", SIGTTIN }, + { "TTOU", SIGTTOU }, + { "IO", SIGIO }, + { "XCPU", SIGXCPU }, + { "XFSZ", SIGXFSZ }, + { "VTALRM", SIGVTALRM }, + { "PROF", SIGPROF }, + { "WINCH", SIGWINCH }, + /* { "INFO", SIGINFO }, */ + { "USR1", SIGUSR1 }, + { "USR2", SIGUSR2 }, + { NULL, 0 } +}; + +static unsigned int +name2sign(char *name) { + SigName *ptr = signalname; + + /*strupper(name);*/ + if ( strncmp(name,"sig",3)==0 ) + name+=3; + + while( ptr && ptr->name ) { + if ( strcmp(name, ptr->name)==0 ) + return ptr->sign; + ptr++; + } + + return 0; +} + + +static char sbuf[16]; + +static char* +sign2name(unsigned int sign) { + SigName *ptr = signalname; + + while( ptr && ptr->name ) { + if (sign==ptr->sign) { + strcpy(sbuf,"SIG"); + strcpy(sbuf+3,ptr->name); + return sbuf; + } + ptr++; + } + return NULL; +} + +typedef struct ChildAction { + unsigned int sign; + int timeout; + struct ChildAction *next; +} ChildAction; + +#define PCL_WAITOPTION 0 +#define PCL_OPTION 1 +#define PCL_OPTIONVAL 2 + + +int +parsecmdline(int argn, char *argv[], ChildAction **ca) { + int i; + int state=PCL_WAITOPTION; + ChildAction *captr=NULL,*caend=NULL,*caprev=NULL; + + *ca=NULL; + + for(i=0;inext=captr; + caend=captr; + } else { + *ca=caend=captr; + } + captr->sign=atoi(ptr); + if ( !sign2name(captr->sign) ) + tlog(TL_ALARM|TL_EXIT,"Unknown signal value: %d", captr->sign); + } else if (isalpha(*ptr)) { + if ( strcmp(ptr,"h")==0 ) { + usage(); + } else if ( strcmp(ptr,"d")==0 ) { + kilterDebug=1; + state = PCL_WAITOPTION; + break; + } else if ( strcmp(ptr,"e")==0 ) { + exitAfterLastSignal=1; + state = PCL_WAITOPTION; + break; + } else { + captr = t0malloc(sizeof(ChildAction)); + if ( *ca ) { + caprev=caend; + caend->next=captr; + caend=captr; + } else { + *ca=caend=captr; + } + captr->sign=name2sign(ptr); + if (!captr->sign) + tlog(TL_ALARM|TL_EXIT,"Unknown signal name: %s", ptr); + } + } else + tlog(TL_ALARM|TL_EXIT,"Unknown option: %s", ptr); + state = PCL_OPTIONVAL; + break; + } else if ( state == PCL_OPTIONVAL ) { + tassert(captr!=NULL); + if (isdigit(*ptr) || *ptr=='+' ) { + captr->timeout = atoi(ptr); + if ( captr->timeout==0 ) + tlog(TL_ALARM|TL_EXIT,"Wrong timeout: %s", ptr); + if (*ptr!='+' && caprev) { + if ( captr->timeout<=caprev->timeout ) + tlog(TL_ALARM|TL_EXIT,"Wrong absolute timeout: %d", captr->timeout); + captr->timeout -= caprev->timeout; + } + state = PCL_WAITOPTION; + } else + tlog(TL_ALARM|TL_EXIT,"Wrong timeout: %s", ptr); + break; + } else + tlog(TL_CRIT|TL_EXIT,"parsecmdline: Wrong state: %d", state); + ptr++; + } + } + + usage(); + + return 0; +} + +static int wasSIGCHILD=0; + +static void +handlerSIGCHILD(int s) { + wasSIGCHILD=1; +} + + +int +main(int argn, char *argv[]) { + ChildAction *ca,*ptr; + int skip=0, status; + pid_t child; + int elapsedtime=0; + + if ( argn<2 ) + usage(); + + skip=parsecmdline(argn-1, argv+1, &ca)+1; + if ( skip==1 ) usage(); + + argn-=skip; + argv+=skip; + + if ( kilterDebug ) + opentlog( TL_OPEN_STDERR, TL_DEBUG, NULL); + else + opentlog( TL_OPEN_SYSLOG, TL_INFO, NULL); + + if ( signal(SIGCHLD, handlerSIGCHILD)==SIG_ERR ) + tlog(TL_CRIT|TL_EXIT,"signal call failed: %s", strerror(errno)); + + + if ( (child=fork()) == 0 ) { + /* child */ + if (execvp(*argv, argv)==-1) + tlog(TL_CRIT|TL_EXIT,"Exec error: %s", strerror(errno)); + } + if (child==-1) + tlog(TL_CRIT|TL_EXIT,"Can't fork: %s", strerror(errno)); + + while(ca) { + elapsedtime=(wasSIGCHILD) ? ca->timeout : sleep(ca->timeout); + if ( elapsedtime > 0 || wasSIGCHILD ) { + wasSIGCHILD=0; + if ( waitpid(child, &status, WNOHANG) == -1 ) + tlog(TL_CRIT|TL_EXIT,"waitpid for %d process failed: %s", child, strerror(errno)); + if ( WIFEXITED(status) ) { + tlog(TL_INFO, "Child %d was exited with status %d", child, WEXITSTATUS(status)); + return 0; + } else if ( WIFSIGNALED(status) ) { + tlog(TL_INFO, "Child %d was exited with signal %d(%s)", child, WTERMSIG(status), + ( sign2name(WTERMSIG(status)) ) ? sign2name(WTERMSIG(status)) : "unknown"); + return 0; + } + ca->timeout = elapsedtime; + } else { + if ( kill(child, ca->sign) != 0 ) + tlog(TL_CRIT|TL_EXIT,"kill %d process failed: %s", child, strerror(errno)); + tlog(TL_INFO,"%s'ed process %d", sign2name(ca->sign), child); + ptr=ca->next; + tfree(ca); + ca=ptr; + } + } + + if ( exitAfterLastSignal==0 ) { + if ( waitpid(child, &status, 0) == -1 ) + tlog(TL_CRIT|TL_EXIT,"waitpid for %d process failed: %s", child, strerror(errno)); + if ( WIFEXITED(status) ) + tlog(TL_INFO, "Child %d was exited with status %d", child, WEXITSTATUS(status)); + else if ( WIFSIGNALED(status) ) + tlog(TL_INFO, "Child %d was exited with signal %d(%s)", child, WTERMSIG(status), + ( sign2name(WTERMSIG(status)) ) ? sign2name(WTERMSIG(status)) : "unknown"); + else + tlog(TL_INFO, "Child %d wasn't exited",child); + } else + tlog(TL_DEBUG, "Exit, don't wait a process %d", child); + + return 0; +} diff --git a/prs_hmap.c b/prs_hmap.c new file mode 100644 index 0000000..76e0769 --- /dev/null +++ b/prs_hmap.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2004 Teodor Sigaev + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +#include "tlog.h" +#include "tmalloc.h" +#include "prs_hmap.h" + + + +#define CS_WAITKEY 0 +#define CS_INKEY 1 +#define CS_WAITEQ 2 +#define CS_WAITVALUE 3 +#define CS_INVALUE 4 +#define CS_IN2VALUE 5 +#define CS_WAITDELIM 6 +#define CS_INESC 7 +#define CS_IN2ESC 8 + +static char * +nstrdup(char *ptr, int len) { + char *res = tmalloc(len + 1), + *cptr; + + memcpy(res, ptr, len); + res[len] = '\0'; + cptr = ptr = res; + while (*ptr) { + if (*ptr == '\\') + ptr++; + *cptr = *ptr; + ptr++; + cptr++; + } + *cptr = '\0'; + + return res; +} + +void +parse_hmap(char *in, HMap ** m) { + HMap *mptr; + char *ptr = in, + *begin = NULL; + char num = 0; + int state = CS_WAITKEY; + + while (*ptr) + { + if (*ptr == ',') + num++; + ptr++; + } + + *m = mptr = (HMap *) t0malloc(sizeof(HMap) * (num + 2)); + ptr = in; + while (*ptr) { + if (state == CS_WAITKEY) { + if (isalpha((unsigned char) *ptr)) { + begin = ptr; + state = CS_INKEY; + } else if (!isspace((unsigned char) *ptr)) + tlog(TL_ALARM|TL_EXIT,"parse_hmap: Syntax error in position %d near \"%c\"\n", (int) (ptr - in), *ptr); + } else if (state == CS_INKEY) { + if (isspace((unsigned char) *ptr)) { + mptr->key = nstrdup(begin, ptr - begin); + state = CS_WAITEQ; + } else if (*ptr == '=') { + mptr->key = nstrdup(begin, ptr - begin); + state = CS_WAITVALUE; + } else if (!isalpha((unsigned char) *ptr)) + tlog(TL_ALARM|TL_EXIT,"parse_hmap: Syntax error in position %d near \"%c\"\n", (int) (ptr - in), *ptr); + } else if (state == CS_WAITEQ) { + if (*ptr == '=') + state = CS_WAITVALUE; + else if (!isspace((unsigned char) *ptr)) + tlog(TL_ALARM|TL_EXIT,"parse_hmap: Syntax error in position %d near \"%c\"\n", (int) (ptr - in), *ptr); + } else if (state == CS_WAITVALUE) { + if (*ptr == '"') { + begin = ptr + 1; + state = CS_INVALUE; + } else if (!isspace((unsigned char) *ptr)) { + begin = ptr; + state = CS_IN2VALUE; + } + } else if (state == CS_INVALUE) { + if (*ptr == '"') { + mptr->value = nstrdup(begin, ptr - begin); + mptr++; + state = CS_WAITDELIM; + } else if (*ptr == '\\') + state = CS_INESC; + } else if (state == CS_IN2VALUE) { + if (isspace((unsigned char) *ptr) || *ptr == ',') { + mptr->value = nstrdup(begin, ptr - begin); + mptr++; + state = (*ptr == ',') ? CS_WAITKEY : CS_WAITDELIM; + } else if (*ptr == '\\') + state = CS_INESC; + } else if (state == CS_WAITDELIM) { + if (*ptr == ',') + state = CS_WAITKEY; + else if (!isspace((unsigned char) *ptr)) + tlog(TL_ALARM|TL_EXIT,"parse_hmap: Syntax error in position %d near \"%c\"\n", (int) (ptr - in), *ptr); + } else if (state == CS_INESC) + state = CS_INVALUE; + else if (state == CS_IN2ESC) + state = CS_IN2VALUE; + else + tlog(TL_CRIT|TL_EXIT,"parse_hmap: Bad parser state %d at position %d near \"%c\"\n", state, (int) (ptr - in), *ptr); + ptr++; + } + + if (state == CS_IN2VALUE) { + mptr->value = nstrdup(begin, ptr - begin); + mptr++; + } + else if (!(state == CS_WAITDELIM || state == CS_WAITKEY)) + tlog(TL_ALARM|TL_EXIT,"parse_hmap: unexpected end of line\n"); +} diff --git a/prs_hmap.h b/prs_hmap.h new file mode 100644 index 0000000..1363070 --- /dev/null +++ b/prs_hmap.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2004 Teodor Sigaev + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __PRS_HMAP_H__ +#define __PRS_HMAP_H__ + +/* simple parser of cfg string */ +typedef struct { + char *key; + char *value; +} HMap; + +void parse_hmap(char *in, HMap ** m); + +#endif diff --git a/prs_inf.c b/prs_inf.c new file mode 100644 index 0000000..5651e33 --- /dev/null +++ b/prs_inf.c @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2004 Teodor Sigaev + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +#include "tlog.h" +#include "tmalloc.h" +#include "prs_inf.h" + +#define INF_WAIT 1 +#define INF_COMMENT 2 +#define INF_SECTION 3 +#define INF_KEY 4 +#define INF_WAITVAL 5 +#define INF_INQVAL 6 +#define INF_INVAL 7 +#define INF_QESCAPE 8 +#define INF_ESCAPE 9 +#define INF_WAITDELIM 10 + + +#define CHECKBUF do { \ + if (bufptr-buf+1>=buflen) { \ + int diff = bufptr-buf; \ + buflen*=2; \ + buf=trealloc(buf,buflen); \ + bufptr=buf+diff; \ + } \ +} while(0) + +#define CHECKMAP do { \ + if (mapptr-map+1>=maplen) { \ + int diff = mapptr-map; \ + maplen*=2; \ + map=trealloc(map,maplen); \ + mapptr=map+diff; \ + } \ +} while(0) + +#define ISKEYNAME(c) ( (c)=='_' || isalnum(c) ) + +static void +clrbackspace(char *ptr, char *buf) { + while(ptr>=buf && (*ptr==' '||*ptr=='\t') ) { + *ptr='\0'; + ptr--; + } +} + +InfMap* +INFParse(char *file) { + FILE *in; + int maplen=32, buflen=32; + InfMap *mapptr,*map; + int state=INF_WAIT, c; + char *buf,*bufptr; + int lineno=1; + + if ( (in=fopen(file,"r"))==NULL ) + tlog(TL_ALARM|TL_EXIT,"Can't open inf file '%s': %s", file, strerror(errno)); + + map=mapptr=(InfMap*)tmalloc(sizeof(InfMap)*maplen); + buf = bufptr = (char*)tmalloc(buflen); + mapptr->section=NULL; + + while( (c=fgetc(in))!=EOF ) { + CHECKBUF; + CHECKMAP; + if (c=='\r') + continue; + + if ( state==INF_WAIT ) { + if ( c=='\n' ) + lineno++; + else if ( c=='[' ) { + bufptr=buf; + state=INF_SECTION; + } else if ( c=='#' ) + state=INF_COMMENT; + else if ( ISKEYNAME(c) ) { + if ( mapptr->section==NULL ) + tlog(TL_ALARM|TL_EXIT, "Undefined section name at line %d, file %s", lineno, file); + bufptr=buf; + *bufptr=c; + bufptr++; + state=INF_KEY; + } + } else if ( state==INF_SECTION ) { + if ( c==']' ) { + if ( bufptr==buf ) { + tlog(TL_ALARM|TL_EXIT, + "Void section name at line %d, file %s", lineno, file); + } else { + if ( mapptr->section ) tfree(mapptr->section); + *bufptr='\0'; + mapptr->section = tstrdup(buf); + bufptr=buf; + } + state=INF_WAIT; + } else if ( ISKEYNAME(c) ) { + *bufptr=c; + bufptr++; + } else + tlog( TL_ALARM|TL_EXIT,"Syntax error at line %d, file %s", lineno, file); + } else if ( state==INF_COMMENT ) { + if (c=='\n') { + lineno++; + state=INF_WAIT; + } + } else if ( state==INF_KEY ) { + if (ISKEYNAME(c)) { + *bufptr=c; + bufptr++; + } else if (c=='=') { + *bufptr='\0'; + mapptr->key = tstrdup(buf); + bufptr=buf; + state=INF_WAITVAL; + } else if (c==' ' || c=='\t') { + *bufptr='\0'; + mapptr->key = tstrdup(buf); + bufptr=buf; + state=INF_WAITDELIM; + } else + tlog( TL_ALARM|TL_EXIT,"Syntax error at line %d, file %s", lineno, file); + } else if ( state==INF_WAITDELIM ) { + if (c=='=') + state=INF_WAITVAL; + else if (!(c==' ' || c=='\t')) + tlog( TL_ALARM|TL_EXIT,"Syntax error at line %d, file %s", lineno, file); + } else if ( state==INF_WAITVAL ) { + if ( c=='\n' ) { + bufptr=buf; + *bufptr='\0'; + mapptr->value=tstrdup(buf); + mapptr++; + mapptr->section = tstrdup((mapptr-1)->section); + state=INF_WAIT; + lineno++; + } else if ( c=='\\' ) { + bufptr=buf; + state=INF_ESCAPE; + } else if ( c=='"' ) { + bufptr=buf; + state=INF_INQVAL; + } else if ( !(c==' ' || c=='\t') ) { + bufptr=buf; + *bufptr=c; + bufptr++; + state=INF_INVAL; + } + } else if ( state==INF_ESCAPE ) { + *bufptr=c; + bufptr++; + state=INF_INVAL; + if (c=='\n') lineno++; + } else if ( state==INF_QESCAPE ) { + *bufptr=c; + bufptr++; + state=INF_INQVAL; + if (c=='\n') lineno++; + } else if ( state==INF_INVAL ) { + if ( c=='#' ) { + *bufptr=' '; + clrbackspace(bufptr,buf); + mapptr->value=tstrdup(buf); + mapptr++; + mapptr->section = tstrdup((mapptr-1)->section); + bufptr=buf; + state=INF_COMMENT; + } else if (c=='\n') { + *bufptr=' '; + clrbackspace(bufptr,buf); + mapptr->value=tstrdup(buf); + mapptr++; + mapptr->section = tstrdup((mapptr-1)->section); + bufptr=buf; + state=INF_WAIT; + lineno++; + } else if (c=='\\') { + state=INF_ESCAPE; + } else { + *bufptr=c; + bufptr++; + } + } else if ( state==INF_INQVAL ) { + if (c=='\\') { + state=INF_QESCAPE; + } else if ( c=='"' ) { + *bufptr='\0'; + mapptr->value=tstrdup(buf); + mapptr++; + mapptr->section = tstrdup((mapptr-1)->section); + bufptr=buf; + state=INF_WAIT; + } else { + *bufptr=c; + bufptr++; + if (c=='\n') lineno++; + } + } else + tlog( TL_CRIT|TL_EXIT,"INFParse: internal error, unknown state %d", state ); + } + + if ( state==INF_INVAL ) { + *bufptr=' '; + clrbackspace(bufptr,buf); + mapptr->value=tstrdup(buf); + mapptr++; + mapptr->section=NULL; + bufptr=buf; + } else if ( state!=INF_WAIT ) { + tlog( TL_ALARM|TL_EXIT,"Unexpected end of file %s", file); + } else if (mapptr->section) { + tfree(mapptr->section); + mapptr->section=NULL; + } + tfree(buf); + fclose(in); + + return map; +} + +void +INFFree(InfMap *inf) { + InfMap *ptr=inf; + while(ptr && ptr->section) { + tfree(ptr->section); + if (ptr->key) tfree(ptr->key); + if (ptr->value) tfree(ptr->value); + ptr++; + } + tfree(inf); +} + +InfMap* +INFFindInfMap(InfMap *inf, char *sect, char *key) { + while(inf && inf->section) { + if ( + (sect==NULL || strcmp(inf->section,sect)==0) && + (key==NULL || strcmp(inf->key,key)==0) + ) + return inf; + + inf++; + } + return NULL; +} + +int +INFGetInt(InfMap *inf, char *sect, char *key, int *val) { + inf = INFFindInfMap(inf, sect, key); + if (inf) { + *val=atoi(inf->value); + return 0; + } + return 1; +} + +int +INFGetUint(InfMap *inf, char *sect, char *key, u_int32_t *val) { + inf = INFFindInfMap(inf, sect, key); + if (inf) { + *val=strtoul(inf->value, NULL,0); + return 0; + } + return 1; +} + +int +INFGetFloat(InfMap *inf, char *sect, char *key, float *val) { + inf = INFFindInfMap(inf, sect, key); + if (inf) { + *val=strtof(inf->value, NULL); + return 0; + } + return 1; +} + +int +INFGetDouble(InfMap *inf, char *sect, char *key, double *val) { + inf = INFFindInfMap(inf, sect, key); + if (inf) { + *val=strtod(inf->value, NULL); + return 0; + } + return 1; +} + +int +INFGetString(InfMap *inf, char *sect, char *key, char **val) { + inf = INFFindInfMap(inf, sect, key); + if (inf) { + *val=tstrdup(inf->value); + return 0; + } + return 1; +} + + diff --git a/prs_inf.h b/prs_inf.h new file mode 100644 index 0000000..4694cb7 --- /dev/null +++ b/prs_inf.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2004 Teodor Sigaev + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __PRS_INF_H__ +#define __PRS_INF_H__ + +#include + +/* simple parser of cfg string */ +typedef struct { + char *section; + char *key; + char *value; +} InfMap; + +InfMap* INFParse(char *file); +void INFFree(InfMap *inf); + +InfMap* INFFindInfMap(InfMap *inf, char *sect, char *key); +int INFGetInt(InfMap *inf, char *sect, char *key, int *val); +int INFGetUint(InfMap *inf, char *sect, char *key, u_int32_t *val); +int INFGetFloat(InfMap *inf, char *sect, char *key, float *val); +int INFGetDouble(InfMap *inf, char *sect, char *key, double *val); +int INFGetString(InfMap *inf, char *sect, char *key, char **val); + +#endif diff --git a/regis.c b/regis.c new file mode 100644 index 0000000..36df610 --- /dev/null +++ b/regis.c @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2004 Teodor Sigaev + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include "tlog.h" +#include "tmalloc.h" +#include "regis.h" + + +int +RS_isRegis(const char *str) { + unsigned char *ptr=(unsigned char *)str; + + while(ptr && *ptr) + if ( isalpha(*ptr) || *ptr=='[' || *ptr==']' || *ptr=='^') + ptr++; + else + return 0; + return 1; +} + +#define RS_IN_ONEOF 1 +#define RS_IN_ONEOF_IN 2 +#define RS_IN_NONEOF 3 +#define RS_IN_WAIT 4 + +static RegisNode* +newRegisNode(RegisNode *prev, int len) { + RegisNode *ptr; + ptr = (RegisNode*)t0malloc(RNHDRSZ+len+1); + if (prev) + prev->next=ptr; + return ptr; +} + +int +RS_compile(Regis *r, int issuffix, const char *str) { + int i,len = strlen(str); + int state = RS_IN_WAIT; + RegisNode *ptr=NULL; + + memset(r,0,sizeof(Regis)); + r->issuffix = (issuffix) ? 1 : 0; + + for(i=0;inode = newRegisNode(NULL,len); + ptr->data[ 0 ] = c; + ptr->type = RSF_ONEOF; + ptr->len=1; + } else if ( c=='[' ) { + if ( ptr ) + ptr = newRegisNode(ptr,len); + else + ptr = r->node = newRegisNode(NULL,len); + ptr->type = RSF_ONEOF; + state=RS_IN_ONEOF; + } else + tlog(TL_ALARM|TL_EXIT,"Error in regis: %s at pos %d\n", str, i+1); + } else if ( state == RS_IN_ONEOF ) { + if ( c=='^' ) { + ptr->type = RSF_NONEOF; + state=RS_IN_NONEOF; + } else if ( isalpha(c) ) { + ptr->data[ 0 ] = c; + ptr->len=1; + state=RS_IN_ONEOF_IN; + } else + tlog(TL_ALARM|TL_EXIT,"Error in regis: %s at pos %d\n", str, i+1); + } else if ( state == RS_IN_ONEOF_IN || state == RS_IN_NONEOF ) { + if ( isalpha(c) ) { + ptr->data[ ptr->len ] = c; + ptr->len++; + } else if ( c==']' ) { + state=RS_IN_WAIT; + } else + tlog(TL_ALARM|TL_EXIT,"Error in regis: %s at pos %d\n", str, i+1); + } else + tlog(TL_CRIT|TL_EXIT,"Internal error in RS_compile: %d\n", state); + } + + ptr = r->node; + while(ptr) { + r->nchar++; + ptr=ptr->next; + } + + return 0; +} + +void +RS_free(Regis *r) { + RegisNode *ptr=r->node,*tmp; + + while(ptr) { + tmp=ptr->next; + tfree(ptr); + ptr = tmp; + } + + r->node = NULL; +} + +int +RS_execute(Regis *r, const char *str, int len) { + RegisNode *ptr=r->node; + unsigned char *c; + + if (len<0) + len=strlen(str); + + if (lennchar) + return 0; + + if ( r->issuffix ) + c = ((unsigned char*)str) + len - r->nchar; + else + c = (unsigned char*)str; + + while(ptr) { + switch(ptr->type) { + case RSF_ONEOF: + if ( ptr->len==0 ) { + if ( *c != *(ptr->data) ) + return 0; + } else if ( strchr((char*)ptr->data, *c) == NULL ) + return 0; + break; + case RSF_NONEOF: + if ( ptr->len==0 ) { + if ( *c == *(ptr->data) ) + return 0; + } else if ( strchr((char*)ptr->data, *c) != NULL ) + return 0; + break; + default: + tlog(TL_CRIT|TL_EXIT,"RS_execute: Unknown type node: %d\n", ptr->type); + } + ptr=ptr->next; + c++; + } + + return 1; +} diff --git a/regis.h b/regis.h new file mode 100644 index 0000000..c28c619 --- /dev/null +++ b/regis.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2004 Teodor Sigaev + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __REGIS_H__ +#define __REGIS_H__ + +#include + +typedef struct RegisNode { + u_int32_t + type:2, + len:16, + unused:14; + struct RegisNode *next; + unsigned char data[1]; +} RegisNode; + +#define RNHDRSZ (sizeof(u_int32_t)+sizeof(void*)) + +#define RSF_ONEOF 1 +#define RSF_NONEOF 2 + +typedef struct Regis { + RegisNode *node; + u_int32_t + issuffix:1, + nchar:16, + unused:15; +} Regis; + +int RS_isRegis(const char *str); + +int RS_compile(Regis *r, int issuffix, const char *str); +void RS_free(Regis *r); +/*×ÏÚ×ÒÁÝÁÅÔ 1 ÅÓÌÉ ÍÁÔÞÉÔÓÑ */ +int RS_execute(Regis *r, const char *str, int len); +#endif diff --git a/res b/res new file mode 100644 index 0000000..86ee3f4 --- /dev/null +++ b/res @@ -0,0 +1,9 @@ +xor + longread 1-byte 4096-block +noncached 16.330 5.241 5.431 + cached 184.446 8.824 326.961 + +zeon + longread 1-byte 4096-block 1M-block +noncached 39.754 5.838 15.535 24.955 + cached 537.066 8.641 968.662 674.419 diff --git a/sfxstr.c b/sfxstr.c new file mode 100644 index 0000000..e9dd00e --- /dev/null +++ b/sfxstr.c @@ -0,0 +1,806 @@ +/* + * Copyright (c) 2004 Teodor Sigaev + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "tlog.h" +#include "tmalloc.h" +#include "sfxstr.h" + +#define EN_VAL 0x01 +#define EN_CHLD 0x02 +#define EN_DATA 0x04 + +static SFSNode* enlargeNode(SFSTree *info, SFSNode* node, u_int8_t val, int flag, SFSNodeData **nd); +static SFSNode* addRecord(SFSTree *info, SFSNode* node, SFSDataIO *in, int level); + +#define STRNCMP(p1,p2,n) ( ((n)==1) ? ( *((char*)(p1))==*((char*)(p2)) ) : (strncmp((char*)(p1), (char*)(p2), (n))==0) ) + +SFSTree* +SFSInit_dp(SFSTree *info, u_int32_t datasize, SFSDataIO *in) { + if ( datasize % sizeof(u_int32_t) ) + tlog(TL_ALARM|TL_EXIT,"SFSInit_dp: datasize(%d) should be divided by sizeof(u_int32_t)", datasize); + + if (!info) + info=(SFSTree*)tmalloc(sizeof(SFSTree)); + memset(info,0,sizeof(SFSTree)); + + info->datasize = datasize; + + while(in && in->key) { + SFSAdd(info, in); + in++; + } + + return info; +} + +SFSTree* +SFSInit_c(SFSTree *info, char **in) { + char **ptr=in; + SFSDataIO d; + + if (!info) + info=(SFSTree*)tmalloc(sizeof(SFSTree)); + memset(info,0,sizeof(SFSTree)); + + while(ptr && *ptr) { + d.key=*ptr; + d.keylen=0; + SFSAdd(info, &d); + ptr++; + } + + return info; +} + +void* +SFSFindData(SFSTree *info, char *word) { + SFSNode *node = info->node; + SFSNodeData *StopLow, *StopHigh, *StopMiddle; + u_int8_t *ptr =(u_int8_t*)word; + + while( node && *ptr ) { + if ( node->isskip ) { + if ( STRNCMP(ptr, ((char*)node)+node->dataptr, node->nchar) ) { + ptr+=node->nchar; + if ( *ptr=='\0' && node->isword) { + return (void*) ( ((char*)(node->data)) + ((node->haschild) ? sizeof(SFSNode*) : 0) ); + } else if ( node->haschild ) { + node = *(SFSNode**)(node->data); + } else { + return NULL; + } + } else + return NULL; + } else { + StopLow = node->data; + StopHigh = StopLow + node->nchar; + while (StopLow < StopHigh) { + StopMiddle = StopLow + ((StopHigh - StopLow) >> 1); + if ( StopMiddle->val == *ptr ) { + ptr++; + if ( *ptr=='\0' && StopMiddle->isword ) { + return (void*)( ((char*)node) + node->dataptr + info->datasize * StopMiddle->data ); + } else if ( StopMiddle->haschild ) { + node=*(SFSNode**)( ((char*)StopMiddle) + StopMiddle->child ); + } else { + return NULL; + } + break; + } else if ( StopMiddle->val < *ptr ) { + StopLow = StopMiddle + 1; + } else { + StopHigh = StopMiddle; + } + } + if ( StopLow >= StopHigh ) + return NULL; + } + } + return NULL; +} + +static void +freeFSFNode(SFSTree *info, SFSNode *node, void (*freefunc)(void*)) { + u_int32_t i; + + if ( node->isskip ) { + if (node->haschild) + freeFSFNode(info, *(SFSNode**)(node->data), freefunc); + if (freefunc && node->isword && info->datasize) + (*freefunc)( (void*)( ((char*)(node->data))+ (node->haschild) ? sizeof(SFSNode*) : 0 ) ); + } else { + SFSNodeData *nd = node->data; + char *data= ((char*)node) + node->dataptr; + + for(i=0;inchar;i++) { + if (nd->haschild) + freeFSFNode(info, *(SFSNode**)( ((char*)nd) + nd->child ), freefunc); + if (freefunc && nd->isword && info->datasize) { + (*freefunc)( (void*)data ); + data+=info->datasize; + } + nd++; + } + } + + tfree(node); +} + +void +SFSFree(SFSTree *info, void (*freefunc)(void*)) { + SFSNodeStack *s=info->stack; + + if (info->node) freeFSFNode(info, info->node, freefunc); + if (info->buf) tfree(info->buf); + info->buf = NULL; + info->tlen=0; + info->node = NULL; + + while(s) { + info->stack=s->next; + tfree(s); + s=info->stack; + } +} + +static SFSNode* +makeSkipNode(SFSTree *info, SFSDataIO *io, int level) { + u_int32_t len; + int size; + SFSNode *res; + + io->key+=level; + io->keylen-=level; + + len = (io->keylen > 255) ? 255 : io->keylen; + size = SFSNHRDSZ + ((io->keylen > 255) ? sizeof(SFSNode*) : info->datasize) + len; + + res = (SFSNode*)tmalloc(size); + + info->nnodes++; + info->totalen+=size; + + res->isskip=1; + res->nchar=len; + res->dataptr = SFSNHRDSZ + ((io->keylen > 255) ? sizeof(SFSNode*) : info->datasize); + memcpy(((char*)res) + res->dataptr, io->key, len); + + if ( io->keylen > 255 ) { + res->haschild=1; + res->isword=0; + io->key = io->key+len; + io->keylen = io->keylen - len; + *(SFSNode**)(res->data) = makeSkipNode(info, io, 0); + io->key = io->key-len; + io->keylen = io->keylen + len; + } else { + res->haschild=0; + res->isword=1; + if (info->datasize) { + memcpy( res->data, io->data, info->datasize ); + } + } + + io->key-=level; + io->keylen+=level; + + return res; +} + +static SFSNode* +splitSkipNode(SFSTree *info, SFSNode* node, SFSDataIO *io, int level) { + SFSNode *res; + int prefixlen=0; + char *s1,*s2; + SFSNodeData *ndata; + + tassert(node->isskip); + io->key+=level; + io->keylen-=level; + + s1=((char*)node) + node->dataptr; + s2=io->key; + + while( s1 - (((char*)node) + node->dataptr) < node->nchar && s2 - io->key < io->keylen && *s1==*s2) { + s1++; + s2++; + } + + prefixlen = s2 - io->key; + + if ( prefixlen==0 ) { + if ( node->nchar == 1 ) { + int flag = EN_VAL | ((node->isword) ? EN_DATA : 0) | ((node->haschild) ? EN_CHLD : 0); + res = enlargeNode(info, NULL, *(u_int8_t*)(((char*)node) + node->dataptr), flag, &ndata); + if ( node->isword ) { + if ( info->datasize ) + memcpy( + ((char*)res) + res->dataptr + info->datasize * ndata->data, + ((char*)(node->data)) + ((node->haschild) ? sizeof(SFSNode*) : 0), + info->datasize + ); + } + if ( node->haschild ) + *(SFSNode**)( ((char*)ndata) + ndata->child ) = *(SFSNode**)( node->data ); + info->totalen -= SFSNHRDSZ + ((node->isword) ? info->datasize : 0) + + ((node->haschild) ? sizeof(SFSNodeData*) : 0) + node->nchar; + info->nnodes--; + tfree(node); + } else { + res = enlargeNode(info, NULL, *(u_int8_t*)(((char*)node) + node->dataptr), EN_VAL|EN_CHLD, &ndata); + node->nchar--; + memmove( ((char*)node) + node->dataptr, ((char*)node) + node->dataptr + 1, node->nchar); + info->totalen--; + *(SFSNode**)( ((char*)ndata) + ndata->child ) = (SFSNode*)trealloc(node, + SFSNHRDSZ + ((node->haschild) ? sizeof(SFSNode*) : 0) + + ((node->isword) ? info->datasize : 0 )+ node->nchar); + } + res = addRecord(info, res, io, 0); + } else if (prefixlen==io->keylen) { + if (prefixlen==node->nchar) { + if ( node->isword || info->datasize==0) { + if (info->datasize) + memcpy( ((char*)(node->data)) + ((node->haschild) ? sizeof(SFSNodeData*) : 0), + io->data, + info->datasize); + node->isword=1; + res=node; + } else { + int size = SFSNHRDSZ + info->datasize + ((node->haschild) ? sizeof(SFSNodeData*) : 0) + node->nchar; + + info->totalen+=info->datasize; + res=(SFSNode*)trealloc(node,size); + res->dataptr=SFSNHRDSZ + info->datasize + ((res->haschild) ? sizeof(SFSNodeData*) : 0); + res->isword=1; + memmove(((char*)res) + res->dataptr, + ((char*)(res->data)) + ((res->haschild) ? sizeof(SFSNodeData*) : 0), res->nchar); + memcpy(((char*)(res->data)) + ((res->haschild) ? sizeof(SFSNodeData*) : 0), io->data, info->datasize); + } + } else { + int size = SFSNHRDSZ + info->datasize + sizeof(SFSNodeData*) + prefixlen; + info->totalen+=size; + info->nnodes++; + res = (SFSNode*)tmalloc(size); + res->isskip=1; + res->isword=1; + res->haschild=1; + res->nchar = prefixlen; + res->dataptr = SFSNHRDSZ + info->datasize + sizeof(SFSNodeData*); + memcpy(((char*)res)+res->dataptr, io->key, prefixlen); + if (info->datasize) + memcpy(((char*)(res->data)) + sizeof(SFSNodeData*), io->data, info->datasize); + node->nchar-=prefixlen; + memmove( ((char*)node) + node->dataptr, ((char*)node) + node->dataptr + prefixlen, node->nchar); + info->totalen-=prefixlen; + *(SFSNode**)(res->data) = (SFSNode*)trealloc(node, SFSNHRDSZ + ((node->isword) ? info->datasize : 0) + + ((node->haschild) ? sizeof(SFSNodeData*) : 0) + node->nchar); + } + } else if ( prefixlen==node->nchar ) { + int size = SFSNHRDSZ + info->datasize + sizeof(SFSNode*) + node->nchar; + info->totalen+=sizeof(SFSNode*); + res=(SFSNode*)trealloc(node,size); + memmove( ((char*)(res->data)) + sizeof(SFSNode*), res->data, info->datasize + res->nchar); + res->haschild=1; + res->dataptr+=sizeof(SFSNode*); + *(SFSNode**)(res->data) = makeSkipNode(info, io, prefixlen); + } else { + int size = SFSNHRDSZ + sizeof(SFSNodeData*) + prefixlen; + info->totalen+=size; + info->nnodes++; + res = (SFSNode*)tmalloc(size); + res->isskip=1; + res->isword=0; + res->haschild=1; + res->nchar = prefixlen; + res->dataptr = SFSNHRDSZ + sizeof(SFSNodeData*); + memcpy(((char*)res)+res->dataptr, io->key, prefixlen); + + node->nchar-=prefixlen; + memmove( ((char*)node) + node->dataptr, ((char*)node) + node->dataptr + prefixlen, node->nchar); + info->totalen-=prefixlen; + + *(SFSNode**)(res->data) = (SFSNode*)trealloc(node, + SFSNHRDSZ + ((node->isword) ? info->datasize : 0) + + ((node->haschild) ? sizeof(SFSNodeData*) : 0) + node->nchar + ); + *(SFSNode**)(res->data) = splitSkipNode(info, *(SFSNode**)(res->data), io, prefixlen); + + } + + io->key-=level; + io->keylen+=level; + return res; +} + + +static SFSNode* +enlargeNode(SFSTree *info, SFSNode* node, u_int8_t val, int flag, SFSNodeData **nd) { + u_int32_t nchild=0, nchar=0, nfound=0, i; + SFSNode *rs,**chld; + SFSNodeData *data; + int sizenode; + char *dataptr; + + + if ( node ) { + nchar=node->nchar; + nchild=node->nchild; + data=node->data; + + for(i=0;iisword; + data++; + } + } + + if ( node ) + info->totalen -= SFSNHRDSZ+nchar*sizeof(SFSNodeData)+nchild*sizeof(SFSNode*)+nfound*info->datasize; + + if ( flag & EN_VAL ) nchar++; + if ( flag & EN_CHLD ) nchild++; + if ( flag & EN_DATA ) nfound++; + + + sizenode = SFSNHRDSZ+nchar*sizeof(SFSNodeData)+nchild*sizeof(SFSNode*)+nfound*info->datasize; + + info->totalen+=sizenode; + if ( !node ) info->nnodes++; + rs=(SFSNode*)tmalloc(sizenode); + + rs->isskip = 0; + rs->nchar = nchar; + rs->nchild = nchild; + rs->dataptr=SFSNHRDSZ+nchar*sizeof(SFSNodeData)+nchild*sizeof(SFSNode*); + dataptr=((char*)rs) + rs->dataptr; + chld = (SFSNode**)( ((char*)rs)+SFSNHRDSZ+nchar*sizeof(SFSNodeData) ); + data=rs->data; + + if (node) { + SFSNode **ochld=(SFSNode**)( ((char*)node)+SFSNHRDSZ+node->nchar*sizeof(SFSNodeData) ); + SFSNodeData *odata = node->data; + char *odataptr=((char*)node) + node->dataptr; + int wasins=0; + + for(i=0;inchar;i++) { + if ( val > odata->val ) { + *(u_int32_t*)data = *(u_int32_t*)odata; + if ( odata->haschild ) { + *chld=*ochld; + data->child = ((char*)chld) - ((char*)data); + chld++; ochld++; + } + if ( odata->isword && info->datasize ) { + memcpy(dataptr, odataptr, info->datasize); + data->data = ((dataptr - ((char*)rs)) - rs->dataptr)/info->datasize; + dataptr += info->datasize; odataptr += info->datasize; + } + data++; odata++; + } else if ( val == odata->val ) { + tassert ( (flag&EN_VAL)==0 ); + *(u_int32_t*)data = *(u_int32_t*)odata; + wasins=1; + if ( odata->haschild || flag & EN_CHLD ) { + if (odata->haschild) *chld=*ochld; + data->child = ((char*)chld) - ((char*)data); + data->haschild=1; + chld++; if (odata->haschild) ochld++; + } else + data->haschild=0; + if ( odata->isword || flag & EN_DATA ) { + data->isword=1; + if ( info->datasize && odata->isword ) { + memcpy(dataptr, odataptr, info->datasize); + odataptr += info->datasize; + } + data->data = ( info->datasize ) ? ((dataptr - ((char*)rs)) - rs->dataptr)/info->datasize : 0; + dataptr += info->datasize; + } else + data->isword=0; + *nd = data; + data++; odata++; + } else { + if ( wasins==0 ) { + tassert ( flag&EN_VAL ); + data->val = val; + if ( flag & EN_CHLD ) { + data->haschild=1; + data->child = ((char*)chld) - ((char*)data); + chld++; + } else + data->haschild=0; + if ( flag & EN_DATA ) { + data->isword=1; + data->data = ( info->datasize ) ? ((dataptr - ((char*)rs)) - rs->dataptr)/info->datasize : 0; + dataptr += info->datasize; + } else + data->isword=0; + *nd = data; + data++; + wasins=1; + i--; + } else { + *(u_int32_t*)data = *(u_int32_t*)odata; + if ( odata->haschild ) { + *chld=*ochld; + data->child = ((char*)chld) - ((char*)data); + chld++; ochld++; + } + if ( odata->isword && info->datasize ) { + memcpy(dataptr, odataptr, info->datasize); + data->data = ((dataptr - ((char*)rs)) - rs->dataptr)/info->datasize; + dataptr += info->datasize; odataptr += info->datasize; + } + data++; odata++; + } + } + } + if ( wasins==0 ) { + tassert ( flag&EN_VAL ); + data->val = val; + if ( flag & EN_CHLD ) { + data->haschild=1; + data->child = ((char*)chld) - ((char*)data); + chld++; + } else + data->haschild=0; + if ( flag & EN_DATA ) { + data->isword=1; + data->data = ( info->datasize ) ? ((dataptr - ((char*)rs)) - rs->dataptr)/info->datasize : 0; + dataptr += info->datasize; + } else + data->isword=0; + *nd = data; + } + } else { + tassert ( flag & EN_VAL ); + data->val = val; + if ( flag & EN_CHLD ) { + data->haschild=1; + data->child = ((char*)chld) - ((char*)data); + } else + data->haschild=0; + if ( flag & EN_DATA ) { + data->isword=1; + data->data = ( info->datasize ) ? ((dataptr - ((char*)rs)) - rs->dataptr)/info->datasize : 0; + } else + data->isword=0; + *nd = data; + } + if (node) tfree(node); + return rs; +} + +static SFSNode* +addRecord(SFSTree *info, SFSNode* node, SFSDataIO *in, int level) { + SFSNodeData *StopLow, *StopHigh, *StopMiddle; + u_int8_t *ptr = ((u_int8_t*)in->key) + level; + + + if ( node ) { + if ( node->isskip ) { + if ( node->haschild && in->keylen-level > node->nchar && + strncmp(in->key+level, ((char*)node)+node->dataptr, node->nchar)==0 ) + *(SFSNode**)( node->data ) = addRecord(info, *(SFSNode**)( node->data ), in, level+node->nchar); + else + node = splitSkipNode(info, node, in, level); + } else { + StopLow = node->data; + StopHigh = StopLow + node->nchar; + while (StopLow < StopHigh) { + StopMiddle = StopLow + ((StopHigh - StopLow) >> 1); + if ( StopMiddle->val == *ptr ) { + if ( *(ptr+1)=='\0' ) { + if ( StopMiddle->isword ) { + /* already exists */ + if ( info->datasize ) + memcpy(((char*)node) + node->dataptr + info->datasize * StopMiddle->data, + in->data, info->datasize ); + } else { + /* not exist word */ + if (info->datasize) { + node = enlargeNode(info, node, *ptr, EN_DATA, &StopMiddle); + memcpy(((char*)node) + node->dataptr + info->datasize * StopMiddle->data, + in->data, info->datasize ); + } + StopMiddle->isword = 1; + } + } else if ( StopMiddle->haschild ) { + *(SFSNode**)( ((char*)StopMiddle) + StopMiddle->child ) = + addRecord(info, *(SFSNode**)( ((char*)StopMiddle) + StopMiddle->child ), in, level+1); + } else { + node = enlargeNode(info, node, *ptr, EN_CHLD, &StopMiddle); + *(SFSNode**)( ((char*)StopMiddle) + StopMiddle->child ) = + makeSkipNode(info, in, level+1); + } + return node; + } else if ( StopMiddle->val < *ptr ) { + StopLow = StopMiddle + 1; + } else { + StopHigh = StopMiddle; + } + } + if ( *(ptr+1)=='\0' ) { + node = enlargeNode(info, node, *ptr, EN_VAL|EN_DATA, &StopMiddle); + if ( info->datasize ) + memcpy(((char*)node) + node->dataptr + info->datasize * StopMiddle->data, + in->data, info->datasize ); + } else { + node = enlargeNode(info, node, *ptr, EN_VAL|EN_CHLD, &StopMiddle); + *(SFSNode**)( ((char*)StopMiddle) + StopMiddle->child ) = + makeSkipNode(info, in, level+1); + } + } + } else + node = makeSkipNode(info, in, level); + + + return node; + +} + +void +SFSAdd(SFSTree *info, SFSDataIO *in) { + if (in->keylen<=0) + in->keylen=strlen(in->key); + info->node = addRecord(info, info->node, in, 0); +} + +static SFSNodeStack* +pushStack(SFSNodeStack *top, SFSNode *node, int level ) { + SFSNodeStack *r=(SFSNodeStack*)tmalloc(sizeof(SFSNodeStack)); + + r->next = top; + r->node=node; + r->data=node->data; + r->level=level; + r->checkedchild = 0; + r->checkedval = 0; + + return r; +} + +void +SFSIteratorStart(SFSTree *info) { + if ( !info->buf ) { + info->tlen = 32; + info->buf = (char*)tmalloc(info->tlen); + } + info->stack = pushStack(NULL, info->node, 0); + info->hasword=0; +} + +void +SFSPrefixIteratorStart(SFSTree *info, char *word) { + SFSNode *node = info->node; + SFSNodeData *StopLow, *StopHigh, *StopMiddle; + u_int8_t *ptr =(u_int8_t*)word; + int len,wlen=strlen(word); + + if ( wlen+1>=info->tlen ) { + info->tlen = 2*wlen; + info->buf = (info->buf) ? + (char*)trealloc(info->buf,info->tlen) + : + (char*)tmalloc(info->tlen); + } + + info->hasword=0; + while( node && *ptr) { + len = wlen - (((char*)ptr)-word); + if ( node->isskip ) { + if ( STRNCMP(ptr, ((char*)node)+node->dataptr, (lennchar) ? len : node->nchar) ) { + if ( len<=node->nchar ) { + strcpy(info->buf,word); + info->stack = pushStack(NULL, node, ((char*)ptr) - word); + return; + } else if ( node->haschild ) { + ptr+=node->nchar; + node = *(SFSNode**)(node->data); + } else { + return; + } + } else + return; + } else { + StopLow = node->data; + StopHigh = StopLow + node->nchar; + while (StopLow < StopHigh) { + StopMiddle = StopLow + ((StopHigh - StopLow) >> 1); + if ( StopMiddle->val == *ptr ) { + if ( *(ptr+1)=='\0' ) { + len =((char*)ptr)-word+1; + strcpy(info->buf,word); + if ( StopMiddle->isword ) { + info->hasword=1; + info->wdata = (void*)( ((char*)node) + node->dataptr + info->datasize * StopMiddle->data ); + } + if ( StopMiddle->haschild ) + info->stack = pushStack(NULL, *(SFSNode**)( ((char*)StopMiddle) + StopMiddle->child ), len); + return; + } else if ( StopMiddle->haschild ) { + node=*(SFSNode**)( ((char*)StopMiddle) + StopMiddle->child ); + } else { + return; + } + ptr++; + break; + } else if ( StopMiddle->val < *ptr ) { + StopLow = StopMiddle + 1; + } else { + StopHigh = StopMiddle; + } + } + if ( StopLow >= StopHigh ) + break; + } + } + return; +} + +int +SFSIterate(SFSTree *info, SFSDataIO *out) { + SFSNodeStack *s=info->stack; + + if ( info->hasword ) { + out->key = info->buf; + out->keylen = strlen(out->key); + out->data = info->wdata; + info->hasword = 0; + return 1; + } + + if ( s == NULL || s->node == NULL) + return 0; + + while ( s->level + s->node->nchar + 1 >= info->tlen ) { + info->tlen *= 2; + info->buf = (char*)trealloc(info->buf, info->tlen); + } + + if ( s->node->isskip ) { + memcpy( info->buf + s->level, ((char*)s->node) + s->node->dataptr, s->node->nchar ); + if ( s->node->isword && !s->checkedval) { + info->buf[ s->level+s->node->nchar ] = '\0'; + out->key = info->buf; + out->keylen = s->level+s->node->nchar; + out->data =((char*)(s->node->data)) + ((s->node->haschild) ? sizeof(SFSNode*) : 0); + s->checkedval=1; + return 1; + } + if ( s->node->haschild && !s->checkedchild) { + info->stack = pushStack(s, *(SFSNode**)( (char*)(s->node->data) ), s->level+s->node->nchar); + s->checkedchild=1; + if ( SFSIterate(info, out) ) + return 1; + } + } else { + while( s->data - s->node->data < s->node->nchar ) { + info->buf[ s->level ] = (char)s->data->val; + if ( s->checkedval==0 && s->data->isword ) { + info->buf[ s->level+1 ] = '\0'; + out->key = info->buf; + out->keylen = s->level+1; + out->data =((char*)s->node) + s->node->dataptr + info->datasize * s->data->data; + s->checkedval = 1; + return 1; + } + if ( s->checkedchild==0 && s->data->haschild ) { + info->stack = pushStack(s, *(SFSNode**)( ((char*)s->data) + s->data->child ), s->level+1); + s->checkedchild=1; + if ( SFSIterate(info, out) ) + return 1; + } + s->checkedval = s->checkedchild = 0; + s->data++; + } + } + info->stack = s->next; + tfree(s); + + return SFSIterate(info, out); +} + +int +SFSRange(SFSTree *info, char *word, SFSDataIO *f, SFSDataIO *l) { + SFSNodeStack *s=info->stack; + + SFSPrefixIteratorStart(info, word); + s=info->stack; + + if ( SFSIterate(info, f) ) { + SFSNodeStack *sptr = info->stack, *stmp; + while( sptr && sptr!=s ) { + stmp=sptr->next; + tfree(sptr); + sptr=stmp; + } + + if ( s == NULL ) { + memcpy(l,f,sizeof(SFSDataIO)); + return 1; + } + } else + return 0; + + info->stack=NULL; + + while( f->keylen + s->level + 2 >= info->tlen ) { + info->tlen *= 2; + info->buf = (char*)trealloc(info->buf, info->tlen); + } + + f->key = info->buf; + l->key = info->buf + f->keylen + 1; + memcpy(l->key, f->key, f->keylen + 1); + + while(s->node) { + while( f->keylen + 1 + s->level + s->node->nchar + 1 >= info->tlen ) { + info->tlen *= 2; + info->buf = (char*)trealloc(info->buf, info->tlen); + } + if ( s->node->isskip ) { + memcpy(info->buf + f->keylen + 1 + s->level, + ((char*)(s->node))+s->node->dataptr, s->node->nchar); + s->level+=s->node->nchar; + if (s->node->haschild) { + s->node=*(SFSNode**)( s->node->data ); + } else { /* if (s->node->isword) */ + info->buf[ f->keylen + 1 + s->level + 1 ] = '\0'; + l->data = (void*)(s->node->data); + l->keylen = s->level+1; + break; + } + } else { + s->data = s->node->data + s->node->nchar - 1; + while( s->data - s->node->data >= 0 ) { + info->buf[ f->keylen + 1 + s->level ] = (char)s->data->val; + if ( s->data->haschild ) { + s->node = *(SFSNode**)( ((char*)s->data) + s->data->child ); + s->level++; + break; + } + if ( s->data->isword ) { + info->buf[ f->keylen + 1 + s->level+1 ] = '\0'; + l->keylen = s->level+1; + l->data =((char*)s->node) + s->node->dataptr + info->datasize * s->data->data; + s->node=NULL; + break; + } + s->data--; + } + } + } + f->key = info->buf; + l->key = info->buf + f->keylen + 1; + tfree(s); + + return 1; +} diff --git a/sfxstr.h b/sfxstr.h new file mode 100644 index 0000000..5f1be7b --- /dev/null +++ b/sfxstr.h @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2004 Teodor Sigaev + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __SFXSTR_H__ +#define __SFXSTR_H__ + +#include + +/* + * ëÁÖÄÙÊ ÕÚÅÌ ÄÅÒÅ×Á ÍÏÖÅÔ ÂÙÔÔØ ÏÂÎÉÍ ÉÚ Ä×ÕÈ ÔÉÐÏ×: + * SFSNode->isskip = 1 - ÕÚÅÌ "ÐÕÔÅ×ÏÊ ËÏÍÐÒÅÓÉÉ". + * ôÁËÏÊ ÕÚÅÌ ÍÏÖÅÔ ÉÍÅÔØ ÏÄÎÏÇÏ ÒÅÂÅÎËÁ É/ÉÌÉ + * ÏÄÎÏ ÓÌÏ×Ï. + * SFSNode->isskip = 0 - "×ÅÔ×ÑÝÉÊÓÑ ÕÚÅÌ" + * + * "×ÅÔ×ÑÝÉÊÓÑ" ÕÚÅÌ ÄÅÒÅ×Á ÈÒÁÎÉÔØÓÑ × ÐÁÍÑÔÉ ÓÌÅÄÕÀÝÉÍ ÏÂÒÁÚÏÍ: + * ( SFSNHRDSZ ÂÁÊÔÁ ) SFSNode - ÚÁÇÏÌÏ×ÏË ÕÚÌÁ + * ( sizeof(SFSNodeData)*SFSNode->nchar ÂÁÊÔÁ) SFSNodeData[] - ÍÁÓÓÉ× "ÓÉÍ×ÏÌÏ×" + * ( sizeof(SFSNode*)*SFSNode->nchild ÂÁÊÔÁ ) *SFSNode[] - ÍÁÓÓÉ× ÓÓÙÌÏË ÎÁ ÄÏÞÅÒÎÉÅ ÕÚÌÙ + * ( SFSTree->datasize * (ËÏÌÉÞÅÓÔ×Ï ÓÌÏ×, ÚÁËÁÎÞÉ×ÁÀÝÉÈÓÑ × ÜÔÏÍ ÕÚÌÅ) ) - + * ÍÁÓÓÉ× ÚÎÁÞÅÎÉÊ + * + * ÍÁÓÓÉ× "ÓÉÍ×ÏÌÏ×" - ÕÐÏÒÑÄÏÞÅÎ ÐÏ ÓÉÍ×ÏÌÁÍ (SFSNodeData->val), + * ÐÏÒÑÄÏË ÏÓÔÁÌØÎÙÈ ÍÁÓÓÉ×Ï× ÚÁÄÁÅÔÓÑ ÍÁÓÓÉ×ÏÍ "ÓÉÍ×ÏÌÏ×" + * ÕÚÅÌ "ÐÕÔÅ×ÏÊ ËÏÍÐÒÅÓÉÉ" ÈÒÁÎÉÔØÓÑ × ÐÁÍÑÔÉ ÓÌÅÄÕÀÝÉÍ ÏÂÒÁÚÏÍ: + * ( SFSNHRDSZ ÂÁÊÔÁ ) SFSNode - ÚÁÇÏÌÏ×ÏË ÕÚÌÁ + * sizeof(SFSNode*) ÂÁÊÔ - ÓÓÙÌËÁ ÎÁ ÒÅÂÅÎËÁ (ÎÅÏÂÑÚÁÔÅÌØÎÏÅ ÐÏÌÅ) + * SFSTree->datasize ÂÁÊÔ - ÚÎÁÞÅÎÉÅ, ÅÓÌÉ ÚÄÅÓØ ÚÁËÁÎÞÉ×ÁÅÔÓÑ ËÌÀÞ + * (ÎÅÏÂÑÚÁÔÅÌØÎÏÅ ÐÏÌÅ) + * SFSTree->nchar ÂÁÊÔ - "ÓËÏÍÐÒÅÓÓÉÒÏ×ÁÎÎÁÑ" ÞÁÓÔØ ÐÕÔÉ. + */ + +/* ÓÔÒÕËÔÕÒÁ, ÏÐÉÓÙ×ÁÀÝÁÑ "ÓÉÍ×ÏÌ" */ +typedef struct { + u_int32_t + /* ÓÍÅÝÅÎÉÅ ÏÔ ÔÅËÕÝÅÇÏ "ÓÉÍ×ÏÌÁ" ÄÏ ÓÓÙÌËÉ ÎÁ ÄÏÞÅÒÎÉÊ ÕÚÅÌ × ÂÁÊÔÁÈ */ + child:10, + unused:4, + + /* × ÌÀÂÏÍ "ÓÉÍ×ÏÌÏ×" isword + haschild > 0 */ + /* ÚÁËÁÎÞÉ×ÁÅÔÓÑ ÌÉ ÚÄÅÓØ ÓÌÏ×Ï */ + isword:1, + /* ÅÓÔØ ÌÉ ÄÏÞÅÒÎÉÊ ÕÚÅÌ */ + haschild:1, + + /* ÓÍÅÝÅÎÉÅ ÏÔ SFSNode->dataptr ÄÏ ÚÎÁÞÅÎÉÑ × ÅÄÉÎÉÃÁÈ SFSTree->datasize */ + data:8, + /* óÏÂÓÔ×ÅÎÎÏ ÓÉÍ×ÏÌ */ + val:8; +} SFSNodeData; + +/* úÁÇÏÌÏ×ÏË ÕÚÌÁ ÄÅÒÅ×Á */ +typedef struct SFSNode { + u_int32_t + /* ÔÉÐ ÕÚÌÁ */ + isskip:1, + /* ÚÁËÁÎÞÉ×ÁÅÔÓÑ ÌÉ ËÌÀÞ × ÜÔÏÍ ÕÚÌÅ (ÔÏÌØËÏ ÄÌÑ ÕÚÌÁ "ÐÕÔÅ×ÏÊ ËÏÍÐÒÅÓÉÉ, + ÄÌÑ "×ÅÔ×ÑÝÅÇÏÓÑ" - ÎÅÉÓÐÏÌØÚÕÅÔÓÑ) */ + isword:1, + + /* ÅÓÔØ ÌÉ ÒÅÂÅÎÏË ÜÔÏÇÏ ÕÚÌÁ (ÔÏÌØËÏ ÄÌÑ ÕÚÌÁ "ÐÕÔÅ×ÏÊ ËÏÍÐÒÅÓÉÉ, + ÄÌÑ "×ÅÔ×ÑÝÅÇÏÓÑ" - ÎÅÉÓÐÏÌØÚÕÅÔÓÑ) */ + haschild:1, + unused:1, + + /* "ÐÕÔÅ×ÏÊ": ÓÍÅÝÅÎÉÅ × ÂÁÊÔÁÈ ÏÔ ÎÁÞÁÌÁ ÕÚÌÁ ÄÏ ÎÁÞÁÌÁ "ÓËÏÍÐÒÅÓÓÉÒÏ×ÁÎÎÏÊ" ÞÁÓÔÉ ÐÕÔÉ */ + /* "×ÅÔ×ÑÝÉÊÓÑ": ÓÍÅÝÅÎÉÅ × ÂÁÊÔÁÈ ÏÔ ÎÁÞÁÌÁ ÕÚÌÁ ÄÏ ÎÁÞÁÌÁ ÍÁÓÓÉ×Á ÚÎÁÞÅÎÉÊ */ + dataptr:12, + + /* "ÐÕÔÅ×ÏÊ": ÎÅÉÓÐÏÌØÚÕÅÔÓÑ */ + /* "×ÅÔ×ÑÝÉÊÓÑ": ËÏÌ-×Ï ÄÏÞÅÒÎÉÈ ÕÚÌÏ× */ + nchild:8, + + /* "ÐÕÔÅ×ÏÊ": ËÏÌ-×Ï "ÓËÏÍÐÒÅÓÓÏ×ÁÎÎÙÈ" ÕÚÌÏ× */ + /* "×ÅÔ×ÑÝÉÊÓÑ": ËÏÌ-×Ï "ÓÉÍ×ÏÌÏ×" */ + nchar:8; + SFSNodeData data[1]; +} SFSNode; + +#define SFSNHRDSZ (sizeof(u_int32_t)) + + +/* ÓÔÒÕËÔÕÒÁ ÄÌÑ ÏÂÈÏÄÁ ÄÅÒÅ×Á ÉÔÅÒÁÔÏÒÏÍ */ +typedef struct SFSNodeStack { + /* ÕËÁÚÁÔÅÌØ ÎÁ ÕÚÅÌ */ + SFSNode *node; + /* ÕËÁÚÁÔÅÌØ ÎÁ "ÓÉÍ×ÏÌ" ÕÚÌÁ */ + SFSNodeData *data; + u_int32_t + /* ÆÌÁÇ ÐÒÏ×ÅÒËÉ ËÌÀÞÁ */ + checkedval:1, + /* ÆÌÁÇ ÐÒÏ×ÅÒËÉ ÄÏÞÅÒÎÅÇÏ ÕÚÌÁ */ + checkedchild:1, + /* "ÇÌÕÂÉÎÁ" ÕÚÌÁ */ + level:30; + struct SFSNodeStack *next; +} SFSNodeStack; + +typedef struct { + /* óÔÁÔÉÓÔÉÞÅÓËÉÅ ÄÁÎÎÙÅ */ + u_int32_t totalen; /* ÏÂÝÅÅ ËÏÌ-×Ï ÍÁÌÌÏÃÉÒÏ×ÁÎÎÏÊ ÐÁÍÑÔÉ */ + u_int32_t nnodes; /* ÏÂÝÅÅ ËÏÌ-×Ï ÕÚÌÏ× ÄÅÒÅ×Á */ + + u_int32_t datasize; /* ÒÁÚÍÅÒ ÚÎÁÞÅÎÉÑ (ËÒÁÔÅÎ sizeof(u_int32_t))*/ + SFSNode *node; /* ËÏÒÎÅ×ÏÊ ÕÚÅÌ ÄÅÒÅ×Á */ + + /* iterator */ + SFSNodeStack *stack; /* ÓÔÅË ÏÂÈÏÄÁ ÄÅÒÅ×Á */ + char *buf; /* ÂÕÆÅÒ ËÌÀÞÁ */ + int tlen; /* ÅÇÏ ÄÌÉÎÁ */ + + /* addon for prefix iterator */ + int hasword; /* ÅÓÔØ ÌÉ ËÌÀÞ, ÒÁ×ÎÏÅ ÐÒÅÆÉËÓÕ (ÓÌÕÖÅÂÎÏÅ ÐÏÌÅ) */ + void *wdata; /* ÕËÁÚÁÔÅÌØ ÎÁ ÚÎÁÞÅÎÉÅ ËÌÀÞÁ, ÒÁ×ÎÏÇÏ ÐÒÅÆÉËÓÕ (ÓÌÕÖÅÂÎÏÅ ÐÏÌÅ) */ +} SFSTree; + +/* ÓÔÒÕËÔÕÒÁ ××ÏÄÁ - ×Ù×ÏÄÁ ÚÁÐÉÓÅÊ */ +typedef struct { + /* ËÌÀÞ, ÄÏÌÖÅÎ ÚÁËÁÎÞÔÉ×ÁÔØÓÑ ÓÉÍ×ÏÌÏÍ '\0' */ + char *key; + /* ÄÌÉÎÁ ËÌÀÞÁ. ïÐÃÉÏÎÁÌØÎÏÅ ÐÏÌÅ, ÎÅ ÉÓÐÏÌØÚÕÅÔÓÑ × ÐÒÏÃÅÓÓÅ ×ÎÅÓÅÎÉÑ + ÎÏ×ÏÇÏ ËÌÀÞÁ, ÎÏ ÐÒÉ ×Ù×ÏÄÅ ×ÓÅÇÄÁ ÓÏÄÅÒÖÉÔ ÄÌÉÎÕ ËÌÀÞÁ */ + int keylen; + /* ÕËÁÚÁÔÅÌØ ÎÁ ÚÎÁÞÅÎÉÅ */ + void *data; +} SFSDataIO; + +/* + * ëÏÒÒÅËÔÎÏÓÔØ ÆÕÎËÃÉÏÎÉÒÏ×ÁÎÉÑ ËÏÎÔÒÏÌÉÒÕÅÔÓÑ assert'ÏÍ, + * × ÔÏÍ ÞÉÓÌÅ É ËÏÎÔÒÏÌØ ÚÁ malloc/realloc + * ÷ÓÅ Æ-ÃÉÉ ÒÁÓÓÞÉÔÁÎÙ ÎÁ ËÌÀÞÉ, ÚÁËÁÎÞÉ×ÁÀÝÉÍÉÓÑ ÓÉÍ×ÏÌÏÍ '\0' + */ + +/* + * Æ-ÃÉÉ ÉÎÉÃÉÁÌÉÚÁÃÉÉ, datasize - ÒÁÚÍÅÒ × ÂÁÊÔÁÈ + * ÚÎÁÞÅÎÉÑ, ÐÒÉ×ÑÚÁÎÎÏÊ Ë ËÌÀÞÁÍ. + * SFSInit_c ÐÒÅÄÐÏÌÁÇÁÅÔ, ÞÔÏ ÚÎÁÞÅÎÉÑ ÏÔÓÕÔÓÔ×ÕÀÔ. + * òÁÚÍÅÒ ÓÔÒÕËÔÕÒÙ ÄÏÌÖÅÎ ÂÙÔØ ÒÁ×ÅÎ ËÒÁÔÅÎ sizeof(u_int32_t) + */ +SFSTree* SFSInit_dp(SFSTree *info, u_int32_t datasize, SFSDataIO *in); +SFSTree* SFSInit_c(SFSTree *info, char **in); + +/* + * ïÓ×ÏÂÏÖÄÅÎÉÅ ÐÁÍÑÔÉ, ÚÁÎÑÔÏÊ ÄÅÒÅ×ÏÍ. + * åÓÌÉ ÕËÁÚÁÎÁ freefunc, ÔÏ ÏÎÁ ×ÙÚÙ×ÁÅÔÓÑ ÄÌÑ + * ËÁÖÄÏÇÏ ÚÎÁÞÅÎÉÑ , ÐÒÉ×ÑÚÁÎÎÏÇÏ Ë ËÌÀÞÁÍ + */ +void SFSFree(SFSTree *info, void (*freefunc)(void*)); + +/* + * äÏÂÁ×ÌÅÎÉÅ ÐÁÒÙ ËÌÀÞ-ÚÎÁÞÅÎÉÅ + */ +void SFSAdd(SFSTree *info, SFSDataIO *in); + +/* + * ðÏÉÓË ÚÎÁÞÅÎÉÑ ÐÏ ËÌÀÞÕ, × ÓÌÕÞÁÅ ÕÓÐÅÈÁ ×ÏÚ×ÒÁÝÁÅÔ + * ÕËÁÚÁÔÅÌØ ÎÁ ÚÎÁÞÅÎÉÅ, ÉÎÁÞÅ - NULL + */ +void* SFSFindData(SFSTree *info, char *word); + +/* + * éÎÉÃÉÁÌÉÚÁÃÉÑ ÉÔÅÒÁÔÏÒÁ × ÎÁÞÁÌÏ ÄÅÒÅ×Á + */ +void SFSIteratorStart(SFSTree *info); + +/* + * éÎÉÃÉÁÌÉÚÁÃÉÑ ÉÔÅÒÁÔÏÒÁ Ë ËÌÀÞÕ, ÂÏÌØÛÅ ÉÌÉ ÒÁ×ÎÏÍÕ + * word + */ +void SFSPrefixIteratorStart(SFSTree *info, char *word); + +/* + * ïÂÈÏÄ ÉÔÅÒÁÔÏÒÁ, × ÓÌÕÞÁÅ ÕÓÐÅÈÁ ×ÏÚ×ÒÁÝÁÅÔ 1 É ÚÁÐÏÌÎÅÎÎÕÀ + * ÓÔÒÕËÔÕÒÕ SFSDataIO *out, ÉÎÁÞÅ 0 É ÎÅÐÒÅÄÓËÁÚÕÅÍÏ ÚÁÐÏÌÎÅÎÎÕÀ + * ÓÔÒÕËÔÕÒÕ SFSDataIO *out. ÷ ÓÔÒÕËÔÕÒÅ out ÐÏÌÑ key É data + * îå ÄÏÌÖÎÙ ÉÚÍÅÎÑÔØÓÑ ÉÌÉ ÏÓ×ÏÂÏÖÄÁÔØÓÑ ÐÁÍÑÔØ. + * æ-ÃÉÑ ÐÒÅËÒÁÝÁÅÔ ÏÂÈÏÄ: + * 1) ÉÎÉÃÉÁÌÉÚÁÃÉÑ SFSIteratorStart: ×ÙÂÒÁÎÙ ×ÓÅ ËÌÀÞÉ + * 2) -/- SFSPrefixIteratorStart: ×ÙÂÒÁÎÙ ×ÓÅ ËÌÀÞÉ Ó ÚÁÄÁÎÎÙÍ ÐÒÅÆÉËÓÏÍ. + * ëÌÀÞÉ ×ÙÄÁÀÔÓÑ × ÌÅËÓÉËÏÇÒÁÆÉÞÅÓËÏÍ ÐÏÒÑÄËÅ, ÓÏÏÔ×ÅÔÓÔ×ÕÀÝÉÍ + * ASCI ËÏÄÉÒÏ×ËÅ. + */ +int SFSIterate(SFSTree *info, SFSDataIO *out); + +/* + * ðÏÉÓË ÍÉÎÉÍÁÌØÎÏÇÏ É ÍÁËÓÉÍÁÌØÎÏÇÏ ËÌÀÞÅÊ, ÓÏÏÔ×ÅÔÓÔ×ÕÀÝÉÈ + * ÐÒÅÆÉËÓÕ word. ÷ ÓÌÕÞÁÅ ÕÓÐÅÈÁ ×ÏÚ×ÒÁÝÁÅÔ 1 É ÚÁÐÏÌÎÅÎÎÙÅ ÓÔÒÕËÔÕÒÙ f É l, + * byfxt - 0 É "ÍÕÓÏÒ" × f É l. ÷ ÓÔÒÕËÔÕÒÁÈ f É l ÐÏÌÑ key É data + * îå ÄÏÌÖÎÙ ÉÚÍÅÎÑÔØÓÑ ÉÌÉ ÏÓ×ÏÂÏÖÄÁÔØÓÑ ÐÁÍÑÔØ. + */ +int SFSRange(SFSTree *info, char *word, SFSDataIO *f, SFSDataIO *l); + +#endif + diff --git a/sfxtest.c b/sfxtest.c new file mode 100644 index 0000000..f98140d --- /dev/null +++ b/sfxtest.c @@ -0,0 +1,346 @@ +/* + * Copyright (c) 2004 Teodor Sigaev + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#include "tools.h" +#include "tlog.h" +#include "tmalloc.h" +#include "sfxstr.h" + +extern char *optarg; +static int verbose=1; + +static int +STRINGCMP(const void *a, const void *b) { + return strcmp( *(char**)a, *(char**)b ); +} + +static void +usage() { + puts("Usage:"); + puts("./sfxtest -d datafile [-b| [-a addondatafile] [-l | -p | -r | -g] [-n]] [-q]"); + puts("Detailed description:"); + + puts(" Binary search"); + puts(" ./sfxtest -b -d datafile [-q]"); + puts(" -q - quiet (no output)"); + + puts(" Optimal suffix search"); + puts(" ./sfxtest -d datafile [-a addondatafile] [-l | -p | -r | -g] [-n] [-q]"); + puts(" -a addondatafile - addon file data for loading"); + puts(" -g - histogramm mode"); + puts(" -l - listing mode"); + puts(" -p - prefix search mode"); + puts(" -r - range search mode"); + puts(" -n - enumerate entries"); + puts(" -q - quiet (no output)"); + + exit(1); +} + +static void +gistogramm(SFSNode *node, int *gist) { + if ( !node ) + return; + + if ( node->isskip ) { + if ( node->haschild ) { + gist[1]++; + gistogramm( *(SFSNode**)(node->data), gist ); + } else + gist[0]++; + } else { + SFSNodeData *data; + + gist[ node->nchild ]++; + + data=node->data; + while(data - node->data < node->nchar) { + if ( data->haschild ) + gistogramm( *(SFSNode**)( ((char*)data) + data->child ), gist); + data++; + } + } +} + +int +main(int argn, char *argv[]) { + struct timeval begin,end; + char *datafile=NULL; + int i, binary=0; + FILE *in; + char buf[4096]; + double sumtime=0.0; + int structsize=0, list=0, prefix=0, range=0, enumerate=0,gmode=0; + char *addondatafile=NULL; + + int len=4096, curlen=0, checked=0, success=0; + char **data; + void *res; + + while ((i = getopt(argn, argv, "pd:bqha:lrng")) != EOF) { + switch(i) { + case 'a': + addondatafile=optarg; + break; + case 'd': + datafile=optarg; + break; + case 'n': + enumerate=1; + break; + case 'g': + gmode=1; + break; + case 'r': + range=1; + break; + case 'p': + prefix=1; + break; + case 'l': + list=1; + break; + case 'b': + binary=1; + break; + case 'q': + verbose=0; + break; + case 'h': + default: + usage(); + } + } + + if (!datafile) usage(); + + opentlog(TL_OPEN_STDERR|TL_OPEN_SYSLOG|TL_OPEN_FILE, TL_INFO, "./sfxtest.log"); + if ( (in=fopen(datafile,"r"))==NULL ) + tlog(TL_CRIT|TL_EXIT,"Beda with %s", datafile); + + data=(char**)tmalloc(len*sizeof(char*)); + while(fgets(buf,4096,in)) { + structsize+=clrspace(buf)+1; + if ( !*buf ) continue; + if (curlen+2 > len) { + len*=2; + data=(char**)trealloc(data, len*sizeof(char*)); + } + data[curlen]=tstrdup(buf); + curlen++; + } + fclose(in); + data[curlen]=NULL; + structsize+=sizeof(char*)*curlen; + + if ( binary == 1 ) { + gettimeofday( &begin, NULL ); + qsort(data, curlen, sizeof(char**), STRINGCMP); + tlog(TL_INFO,"Init time: %.03f secs", elapsedtime(&begin) ); + tlog(TL_INFO,"Memory allocated: %.2fMb", ((float)structsize)/(1024.0*1024.0)); + + gettimeofday( &begin, NULL ); + while(fgets(buf,4096,stdin)) { + char *ptr=buf; + len = clrspace(buf); + if (!len) continue; + res = bsearch(&ptr, data, curlen, sizeof(char**), STRINGCMP); + + if (verbose) + puts( (res) ? "Y" : "N" ); + + checked++; + if (res) success++; + } + gettimeofday( &end, NULL ); + } else { + SFSTree info; + SFSDataIO n = {NULL,0,NULL}; + n.data = (void*)&enumerate; + + gettimeofday( &begin, NULL ); + if (enumerate) { + char **ptr=data; + + SFSInit_dp(&info,sizeof(enumerate),NULL); + while(*ptr) { + n.key = *ptr; + SFSAdd(&info, &n); + enumerate++; + ptr++; + } + } else + SFSInit_c(&info,data); + tlog(TL_INFO,"Init time: %.03f secs", elapsedtime(&begin) ); + tlog(TL_INFO,"Memory allocated: %.2fMb", ((float)info.totalen)/(1024.0*1024.0)); + tlog(TL_INFO,"Number of nodes: %d", info.nnodes); + + for(i=0;i'); + fputs(out.key, stdout); + printf(" %d\n", *(int*)(out.data)); + } else { + putchar('>'); + puts(out.key); + } + } + success++; + } + checked++; + } + gettimeofday( &end, NULL ); + } else if ( range ) { + SFSDataIO f,l; + + gettimeofday( &begin, NULL ); + while(fgets(buf,4096,stdin)) { + len = clrspace(buf); + if (!len) continue; + + if ( SFSRange(&info,buf,&f,&l) ) { + if (verbose) { + if (enumerate) { + putchar('>'); + fputs(f.key, stdout); + printf(" %d\n", *(int*)(f.data)); + putchar('>'); + fputs(l.key, stdout); + printf(" %d\n", *(int*)(l.data)); + } else { + putchar('>'); puts(f.key); + putchar('>'); puts(l.key); + } + } + success++; + } + checked++; + } + gettimeofday( &end, NULL ); + } else { + gettimeofday( &begin, NULL ); + while(fgets(buf,4096,stdin)) { + len = clrspace(buf); + if (!len) continue; + + res = SFSFindData(&info,buf); + if (verbose) { + if (enumerate && res) + printf("%d\n", *(int*)(res)); + else + puts( (res) ? "Y" : "N" ); + } + + checked++; + if (res) success++; + } + gettimeofday( &end, NULL ); + } + SFSFree(&info,NULL); + } + + sumtime = timediff(&begin,&end); + tlog(TL_INFO,"Total execution time: %.03f secs", sumtime); + tlog(TL_INFO,"Total words in data: %d; Checked: %d; Success: %d", curlen, checked, success); + tlog(TL_INFO,"%.2f words per second", ((double)checked)/sumtime); + + closetlog(); + return 0; +} diff --git a/shmem.c b/shmem.c new file mode 100644 index 0000000..933dc4b --- /dev/null +++ b/shmem.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2004 Teodor Sigaev + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tlog.h" +#include "shmem.h" + +#define KEY 101 +#define PATH "/bin" + +void * +attachSharedMemory(int key, char *path, int size, int rdonly) { + key_t shm_key; + int shm_id, flags=0; + void *shm; + + if ( size>0 && rdonly ) + return NULL; + + shm_key = ftok( (path) ? path : PATH, (key) ? key : KEY); /* Get IPC key */ + if ((int) shm_key == -1) + tlog(TL_CRIT|TL_EXIT, "Ftok error: %s", strerror(errno)); + + if (size > 0) + flags = IPC_CREAT | IPC_EXCL | 0644; + + shm_id = shmget(shm_key, size, flags); /* Get SHM segment */ + if (shm_id == -1) { + if ( errno == EEXIST || errno == ENOENT ) + return NULL; + else + tlog(TL_CRIT|TL_EXIT, "shmget error: %s", strerror(errno)); + } + + flags = ( rdonly ) ? SHM_RDONLY : 0; + + shm = shmat(shm_id, 0, flags); /* Attach SHM segment */ + if ( (int)shm == -1 ) + tlog(TL_CRIT|TL_EXIT, "shmat error: %s", strerror(errno)); + + return shm; +} + +void +detachSharedMemory(void *shm) { + if ( shmdt(shm) == -1 ) + tlog(TL_CRIT, "shmdt error: %s", strerror(errno)); +} + +int +attachSemaphore(int key, char *path) { + key_t shm_key; + int sem_id; + + shm_key = ftok( (path) ? path : PATH, (key) ? key : KEY); /* Get IPC key */ + if ((int) shm_key == -1) + tlog(TL_CRIT|TL_EXIT, "Ftok error: %s", strerror(errno)); + + sem_id = semget(shm_key, 1, 0); + if ( sem_id == -1 ) { + if ( errno == ENOENT ) { /* not exists */ + sem_id = semget(shm_key, 1, IPC_CREAT | IPC_EXCL | 0644); + if ( sem_id == -1 ) + tlog(TL_CRIT|TL_EXIT, "semget error: %s", strerror(errno)); + if ( semctl( sem_id, 0, SETVAL, 1 ) == -1 ) + tlog(TL_CRIT|TL_EXIT, "sysctl error: %s", strerror(errno)); + } else + tlog(TL_CRIT|TL_EXIT, "semget error: %s", strerror(errno)); + } + return sem_id; +} + +void releaseSemaphore(int sem_id) { + struct sembuf sem; + + sem.sem_num = 0; + sem.sem_flg = 0; + sem.sem_op = 1; + + if (semop(sem_id, &sem, 1) == -1) + tlog(TL_CRIT|TL_EXIT, "semop error: %s", strerror(errno)); +} + +void lockSemaphore(int sem_id) { + struct sembuf sem; + + sem.sem_num = 0; + sem.sem_flg = 0; + sem.sem_op = -1; + + if (semop(sem_id, &sem, 1) == -1) + tlog(TL_CRIT|TL_EXIT, "semop error: %s", strerror(errno)); +} + + + diff --git a/shmem.h b/shmem.h new file mode 100644 index 0000000..94721f7 --- /dev/null +++ b/shmem.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2004 Teodor Sigaev + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __T_SHMEM_H__ +#define __T_SHMEM_H__ + +void * attachSharedMemory(int key, char *path, int size, int rdonly); +void detachSharedMemory(void *shm); + +int attachSemaphore(int key, char *path); +void lockSemaphore(int sem_id); +void releaseSemaphore(int sem_id); + +#endif diff --git a/tcp.c b/tcp.c new file mode 100644 index 0000000..0273787 --- /dev/null +++ b/tcp.c @@ -0,0 +1,444 @@ +/* + * Copyright (c) 2004 Teodor Sigaev + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_POLL_H +#include +#else /* HAVE_POLL */ +#ifdef HAVE_SYS_POLL_H +#include +#else +#error Not defined HAVE_POLL_H or HAVE_SYS_POLL_H +#endif /* HAVE_SYS_POLL_H */ +#endif /* HAVE_POLL */ + +#ifdef HAVE_HSTRERROR +#include +#endif + + +#include "connection.h" +#include "tlog.h" +#include "tmalloc.h" + +u_int32_t +TC_ClientInitConnection(TC_Connection *cs, char *name, u_int32_t port) { + int flags; + + cs = TC_fillConnection(cs, name, port); + + cs->state = CS_OK; + if ((cs->fd= socket(AF_INET, SOCK_STREAM, 0)) < 0) + tlog(TL_CRIT|TL_EXIT,"socket4: %s:%d - %s",inet_ntoa(cs->serv_addr.sin_addr), + ntohs(cs->serv_addr.sin_port),strerror(errno)); + + if ((flags=fcntl(cs->fd,F_GETFL,0)) == -1) + tlog(TL_ALARM,"fcntl F_GETFL - %s",strerror(errno)); + if (fcntl(cs->fd,F_SETFL,flags|O_NDELAY) < 0 ) + tlog(TL_ALARM,"fcntl O_NDELAY - %s",strerror(errno)); + + if (bind(cs->fd, (struct sockaddr *) &(cs->serv_addr), sizeof(cs->serv_addr)) < 0) + tlog(TL_CRIT|TL_EXIT, "cannot bind to %s address: %s", + inet_ntoa(cs->serv_addr.sin_addr), strerror(errno)); + + if (listen(cs->fd, 0) < 0) + tlog(TL_CRIT|TL_EXIT, "cannot listen to %s address: %s", + inet_ntoa(cs->serv_addr.sin_addr), strerror(errno)); + + return CS_OK; +} + +TC_Connection* +TC_AcceptTcp(TC_Connection *cs) { + TC_Connection *nc; + struct sockaddr_in cli_addr; + int ret, flags; + socklen_t clilen = sizeof(cli_addr); + + cs->state = CS_READ; + if ( (ret = accept(cs->fd,(struct sockaddr *)&cli_addr, &clilen)) < 0 ) { + if ( errno == EAGAIN || errno == EWOULDBLOCK ) + return NULL; + tlog(TL_ALARM,"TC_AcceptTcp: accept: %s", strerror(errno)); + return NULL; + } + nc = (TC_Connection*)t0malloc(sizeof(TC_Connection)); + + nc->fd = ret; + if ((flags=fcntl(nc->fd,F_GETFL,0)) == -1) + tlog(TL_ALARM,"fcntl F_GETFL - %s",strerror(errno)); + if (fcntl(nc->fd,F_SETFL,flags|O_NDELAY) < 0 ) + tlog(TL_ALARM,"fcntl O_NDELAY - %s",strerror(errno)); + memcpy( &(nc->serv_addr), &cli_addr, clilen ); + nc->state = CS_CONNECTED; + + return nc; +} + +TC_Connection * +TC_fillConnection(TC_Connection *sc, char *name, u_int32_t port) { + if ( !sc ) + sc = (TC_Connection *)t0malloc(sizeof(TC_Connection)); + sc->serv_addr.sin_family = AF_INET; + sc->serv_addr.sin_addr.s_addr = (name) ? inet_addr(name) : htonl(INADDR_ANY); + sc->serv_addr.sin_port = htons(port); + sc->state = CS_NOTINITED; + return sc; +} + +static u_int32_t +setlinger( TC_Connection *cs ) { + struct linger ling; + int val = 0; + socklen_t size = sizeof(val); + + if (getsockopt(cs->fd, SOL_SOCKET,SO_ERROR,&val,&size) == -1) { + tlog(TL_ALARM,"getsockopt: %s:%d - %s(%d)",inet_ntoa(cs->serv_addr.sin_addr), + ntohs(cs->serv_addr.sin_port), strerror(errno), errno); + shutdown(cs->fd,SHUT_RDWR); + close(cs->fd); + cs->fd = 0; + cs->state = CS_ERROR; + return CS_ERROR; + } + + if ( val ) { + tlog(TL_ALARM,"getsockopt return: %s:%d - %s(%d)",inet_ntoa(cs->serv_addr.sin_addr), + ntohs(cs->serv_addr.sin_port), strerror(val), val); + shutdown(cs->fd,SHUT_RDWR); + close(cs->fd); + cs->fd = 0; + cs->state = CS_ERROR; + return CS_ERROR; + } + + + ling.l_onoff = ling.l_linger = 0; + if (setsockopt(cs->fd, SOL_SOCKET,SO_LINGER,(char *)&ling,sizeof(ling))==-1) { + tlog(TL_ALARM,"setsockopt: LINGER %s:%d - %s",inet_ntoa(cs->serv_addr.sin_addr), + strerror(errno)); + shutdown(cs->fd,SHUT_RDWR); + close(cs->fd); + cs->fd = 0; + cs->state = CS_ERROR; + return CS_ERROR; + } + cs->state = CS_CONNECTED; + return CS_CONNECTED; +} + +u_int32_t +TC_ServerInitConnect( TC_Connection *cs ) { + int flags; + + if ( cs->state == CS_ERROR ) + return CS_ERROR; + + if ((cs->fd= socket(AF_INET, SOCK_STREAM, 0)) < 0) { + tlog(TL_CRIT,"socket4: %s:%d - %s",inet_ntoa(cs->serv_addr.sin_addr), + ntohs(cs->serv_addr.sin_port),strerror(errno)); + cs->state = CS_ERROR; + return CS_ERROR; + } + + if ((flags=fcntl(cs->fd,F_GETFL,0)) == -1) + tlog(TL_ALARM,"fcntl F_GETFL - %s",strerror(errno)); + if (fcntl(cs->fd,F_SETFL,flags|O_NDELAY) < 0 ) + tlog(TL_ALARM,"fcntl O_NDELAY - %s",strerror(errno)); + + if ( connect(cs->fd, (struct sockaddr *) &(cs->serv_addr), + sizeof(struct sockaddr_in)) < 0 ) { + if ( errno == EINPROGRESS || errno == EALREADY ) { + cs->state = CS_INPROCESS; + return CS_INPROCESS; + } else if (errno != EISCONN && errno != EALREADY && + errno != EWOULDBLOCK && errno != EAGAIN) { + tlog(TL_DEBUG,"open4: %s:%d - %s", + inet_ntoa(cs->serv_addr.sin_addr), ntohs(cs->serv_addr.sin_port), + strerror(errno)); + shutdown(cs->fd,SHUT_RDWR); + close(cs->fd); + cs->fd = 0; + } else { + tlog(TL_DEBUG,"nonblock connect: %s:%d - %s [%d]", + inet_ntoa(cs->serv_addr.sin_addr), + ntohs(cs->serv_addr.sin_port), + strerror(errno),errno); + } + cs->state = CS_ERROR; + return CS_ERROR; + } + + cs->state = CS_INPROCESS; + return TC_ServerConnect( cs ); +} + + +u_int32_t +TC_ServerConnect( TC_Connection *cs ) { + struct pollfd pfd; + int ret; + + if ( cs->state != CS_INPROCESS ) + return cs->state; + + pfd.fd = cs->fd; + pfd.events = POLLOUT; + pfd.revents = 0; + ret = poll( &pfd, 1, 0 ); + if ( ret<0 ) { + tlog( TL_CRIT, "TC_ServerConnect: poll: %s", + strerror(errno)); + cs->state = CS_ERROR; + return CS_ERROR; + } else if ( ret == 0 ) + return CS_INPROCESS; + + if ( (pfd.revents & (POLLHUP | POLLNVAL | POLLERR)) ) { + tlog( TL_CRIT, "TC_ServerConnect: poll return connect error for %s:%d", + inet_ntoa(cs->serv_addr.sin_addr), ntohs(cs->serv_addr.sin_port)); + cs->state = CS_ERROR; + return CS_ERROR; + } + + if ( ! (pfd.revents & POLLOUT) ) + return CS_INPROCESS; + + + return setlinger( cs ); +} + +int +TC_ReadyIO( TC_Connection **cs, int number, int timeout ) { + struct pollfd *pfd; + int ret,i, fdnum=0; + + if ( number==0 || cs ==NULL ) { + usleep( timeout * 1000.0 ); + return 0; + } + pfd = (struct pollfd*) tmalloc( sizeof(struct pollfd) * number ); + + for(i=0; ifd>0 && (cs[i]->state == CS_READ || cs[i]->state == CS_SEND) ) { + pfd[fdnum].fd = cs[i]->fd; + pfd[fdnum].events = ( cs[i]->state == CS_READ ) ? POLLIN : POLLOUT; + pfd[fdnum].revents = 0; + fdnum++; + } + cs[i]->readyio=0; + } + ret = poll( pfd, fdnum, timeout ); + if ( ret<0 ) { + tlog( TL_CRIT, "TC_ReadyIO: poll: %s", + strerror(errno)); + tfree(pfd); + return 0; + } + + if ( ret == 0 ) { + tfree(pfd); + return 0; + } + + fdnum=0; ret=0; + for(i=0; ifd>0 && (cs[i]->state == CS_READ || cs[i]->state == CS_SEND) ) { + if ( pfd[fdnum].revents & (POLLHUP | POLLNVAL | POLLERR) ) { + tlog( TL_ALARM, "TC_ReadyIO: poll return error for %s:%d", + inet_ntoa(cs[i]->serv_addr.sin_addr), + ntohs(cs[i]->serv_addr.sin_port)); + cs[i]->state = CS_ERROR; + ret = 1; + } else if ( pfd[fdnum].revents & ( ( cs[i]->state == CS_READ ) ? POLLIN : POLLOUT ) ) { + cs[i]->readyio=1; + ret = 1; + } + fdnum++; + } + } + + tfree(pfd); + return ret; +} + +u_int32_t +TC_Send( TC_Connection *cs ) { + int sz; + + if ( cs->state == CS_ERROR ) + return CS_ERROR; + + if ( cs->state != CS_SEND ) { + cs->state = CS_SEND; + cs->ptr = cs->buf; + } + + if ( cs->ptr - cs->buf >= cs->len ) { + cs->state = CS_FINISHSEND; + return CS_FINISHSEND; + } + + if ((sz=write(cs->fd, cs->ptr, cs->len - (cs->ptr - cs->buf)))==0 || + (sz < 0 && (errno == EWOULDBLOCK || errno == EAGAIN))) { + + /* SunOS 4.1.x, are broken and select() says that + * O_NDELAY sockets are always writable even when + * they're actually not. + */ + cs->state = CS_SEND; + return CS_SEND; + } + if ( sz<0 ) { + if (errno != EPIPE && errno != EINVAL) + tlog(TL_ALARM, "write[%s:%d] - %s", + inet_ntoa(cs->serv_addr.sin_addr), + ntohs(cs->serv_addr.sin_port), + strerror(errno)); + cs->state = CS_ERROR; + return CS_ERROR; + } + + cs->ptr += sz; + + if ( cs->ptr - cs->buf >= cs->len ) { + cs->state = CS_FINISHSEND; + return CS_FINISHSEND; + } + + return cs->state; +} + +static void +resizeCS( TC_Connection *cs, int sz ) { + int diff = cs->ptr - cs->buf; + if ( cs->len >= sz ) + return; + cs->len = sz; + cs->buf = (char*)trealloc( (void*)cs->buf, cs->len ); + cs->ptr = cs->buf + diff; +} + +u_int32_t +TC_Read( TC_Connection *cs ) { + int sz, totalread = -1, toread=0, alreadyread; + + if ( cs->state == CS_ERROR ) + return CS_ERROR; + + if (cs->state != CS_READ ) { + cs->state = CS_READ; + cs->ptr = cs->buf; + } + + alreadyread = cs->ptr - cs->buf; + if ( alreadyread < sizeof(u_int32_t) ) { + toread = sizeof(u_int32_t) - alreadyread; + resizeCS(cs, sizeof(u_int32_t)); + } else { + totalread = *(u_int32_t*)(cs->buf); + toread = totalread - alreadyread; + if ( toread == 0 ) { + cs->state = CS_FINISHREAD; + return CS_FINISHREAD; + } + resizeCS(cs, totalread); + } + + if ((sz=read( cs->fd, cs->ptr, toread))<0) { + if (errno == EAGAIN || errno == EINTR) { + cs->state = CS_READ; + return CS_READ; + } + tlog(TL_ALARM,"read: finish - %s",strerror(errno)); + cs->state = CS_ERROR; + return CS_ERROR; + } + + + cs->ptr += sz; + alreadyread += sz; + if ( sz == 0 && alreadyread != totalread ) { + tlog(TL_ALARM,"read: disconnecting"); + cs->state = CS_ERROR; + return CS_ERROR; + } + cs->state = ( alreadyread == totalread ) ? CS_FINISHREAD : CS_READ; + return cs->state; +} + +void +TC_FreeConnection( TC_Connection *cs ) { + if ( cs->state == CS_CLOSED ) + return; + if ( cs->buf ) { + tfree(cs->buf); + cs->buf = NULL; + } + if ( cs->fd && cs->state != CS_NOTINITED ) { + shutdown(cs->fd,SHUT_RDWR); + close(cs->fd); + } + cs->fd = 0; + cs->state = CS_CLOSED; +} + +u_int32_t +TC_Talk( TC_Connection *cs ) { + u_int32_t ret = TC_ServerInitConnect( cs ); + + while( ret == CS_INPROCESS ) { + ret = TC_ServerConnect(cs); + } + + if ( ret != CS_CONNECTED ) + return ret; + + while( ret != CS_FINISHSEND ) { + ret = TC_Send(cs); + if ( ret == CS_ERROR ) return ret; + } + + cs->state = CS_READ; + cs->ptr = cs->buf; + while( cs->state != CS_FINISHREAD ) { + while( !TC_ReadyIO( &cs, 1, 100) ); + if ( ret == CS_ERROR ) return ret; + if ( TC_Read(cs) == CS_ERROR ) return CS_ERROR; + } + + return CS_OK; +} + + diff --git a/test.inf b/test.inf new file mode 100644 index 0000000..c0b254b --- /dev/null +++ b/test.inf @@ -0,0 +1,23 @@ + +[test] +kde= + +kde=v +kde =v +kde = v #WOW +asdfas = \ +HAHA\ + +#wwekljrw +[test2] #sfljkl'sdf +#dfghjkl +t2="qweqwe#asd" +t2="qweqwe#as\"d" #HEH +t5="hsdf +sdf sdf +sdf sdf sdf +sdf sdf +sdf sdfssd f +\\ +sdf sdf sdf +" diff --git a/tlog.c b/tlog.c new file mode 100644 index 0000000..36c4c54 --- /dev/null +++ b/tlog.c @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2004 Teodor Sigaev + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tlog.h" + +static FILE *TL_ErrOut = NULL; +static u_int32_t TL_DebugLevel = TL_INFO; +static u_int32_t tlflag = TL_OPEN_STDERR | TL_OPEN_SYSLOG; + + +static int +TLtoSYS(int level) { + switch(level) { + case TL_CRIT : return LOG_CRIT; + case TL_ALARM: return LOG_ERR; + case TL_WARN : return LOG_WARNING; + case TL_INFO : return LOG_INFO; + case TL_DEBUG: return LOG_DEBUG; + default: return LOG_WARNING; + } + return LOG_ERR; +} + +void +opentlog(u_int32_t flag, u_int32_t level, char *file) { + if (flag==0) + flag=tlflag; + + TL_DebugLevel=level; + + tlflag &= ~TL_OPEN_FILE; + if ( TL_ErrOut ) + fclose(TL_ErrOut); + if ( (flag & TL_OPEN_FILE) && file ) { + if ( (TL_ErrOut=fopen(file,"a")) == NULL ) + tlog(TL_ALARM,"Can't open log file '%s': %s", file, strerror(errno)); + else { + u_int32_t oldflag = tlflag; + tlflag = TL_OPEN_FILE; + tlog(TL_INFO, "Log opened"); + tlflag = oldflag | TL_OPEN_FILE; + } + } + + tlflag &= ~TL_OPEN_SYSLOG; + tlflag |= (flag & TL_OPEN_SYSLOG); + + tlflag &= ~TL_OPEN_STDERR; + tlflag |= (flag & TL_OPEN_STDERR); +} + +void +closetlog() { + if ( TL_ErrOut ) { + if ( tlflag & TL_OPEN_FILE ) { + tlflag = TL_OPEN_FILE; + tlog(TL_INFO,"Log closed"); + } + fclose(TL_ErrOut); + } + TL_ErrOut=NULL; + tlflag = TL_OPEN_STDERR | TL_OPEN_SYSLOG; +} + +void +tlog(u_int32_t level,const char *format, ...) { + va_list args; + + if ( (level & TL_EXIT)==0 ) + if ( (level & ~TL_EXIT) > TL_DebugLevel ) + return; + + if ( tlflag & (TL_OPEN_STDERR | TL_OPEN_FILE) ) { + time_t t; + char buf[64]; + t = time(NULL); + + strftime(buf,64,"%H:%M:%S %d/%m/%Y",localtime(&t)); + if ( tlflag & TL_OPEN_STDERR ) { + fprintf( stderr,"%d %s ", getpid(), buf ); + va_start(args, format); + vfprintf( stderr, format, args); + va_end(args); + fputc('\n', stderr); + } + if ( (tlflag & TL_OPEN_FILE) && TL_ErrOut ) { + fprintf( TL_ErrOut,"%d %s ", getpid(), buf ); + va_start(args, format); + vfprintf( TL_ErrOut, format, args); + va_end(args); + fputc('\n', TL_ErrOut); + } + } + + if ( tlflag & TL_OPEN_SYSLOG ) { + va_start(args, format); + vsyslog( TLtoSYS( (int)(level & ~TL_EXIT) ), format, args ); + va_end(args); + } + + if ( level & TL_EXIT ) { + tlog(level & ~TL_EXIT, "Exitting..."); + closetlog(); + exit(1); + } +} + diff --git a/tlog.h b/tlog.h new file mode 100644 index 0000000..dbe6efd --- /dev/null +++ b/tlog.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2004 Teodor Sigaev + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __TLOG_H__ +#define __TLOG_H__ + +#include +#include +#include + +#define TL_EXIT 0x70000000 +#define TL_CRIT 0 +#define TL_ALARM 1 +#define TL_WARN 2 +#define TL_INFO 3 +#define TL_DEBUG 4 + +#define TL_OPEN_SYSLOG 0x01 +#define TL_OPEN_STDERR 0x02 +#define TL_OPEN_FILE 0x04 + +void opentlog(u_int32_t flag, u_int32_t level, char *file); +void tlog(u_int32_t level,const char *format, ...); +void closetlog(); + +#ifdef ASSERT_CORE +#define tassert(e) ( (e) ? (void)0 : (tlog(TL_CRIT, "Assertion failed: %s, function %s, file %s, line %d.", #e, (__func__) ? __func__ : "UNKNOWN", __FILE__, __LINE__), closetlog(), abort()) ) +#else +#define tassert(e) ( (e) ? (void)0 : (tlog(TL_CRIT|TL_EXIT, "Assertion failed: %s, function %s, file %s, line %d.", #e, (__func__) ? __func__ : "UNKNOWN", __FILE__, __LINE__)) ) +#endif + +#endif diff --git a/tmalloc.c b/tmalloc.c new file mode 100644 index 0000000..953e28f --- /dev/null +++ b/tmalloc.c @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2004 Teodor Sigaev + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +#include "tlog.h" +#include "tmalloc.h" + +void * +tmalloc(size_t size) { + void *ptr = malloc(size); + if (!ptr) + tlog(TL_CRIT|TL_EXIT, "Can't allocate %d bytes", size); + return ptr; +} + +void * +t0malloc(size_t size) { + void *ptr = tmalloc(size); + memset(ptr,0,size); + return ptr; +} + +void * +trealloc(void * ptr, size_t size) { + if (ptr) { + ptr = realloc(ptr,size); + if (!ptr) + tlog(TL_CRIT|TL_EXIT, "Can't reallocate to %d bytes", size); + } else + ptr = tmalloc(size); + return ptr; +} + +void +tfree(void * ptr) { + free(ptr); +} + +char * +tstrdup(char * src) { + char * dest = strdup(src); + if (!dest) + tlog(TL_CRIT|TL_EXIT, "Can't strdup %d bytes", strlen(src)+1); + return dest; +} + +char * +tnstrdup(char *src, int len) { + char *dest=(char*)tmalloc(len+1); + memcpy(dest, src, len); + dest[len]='\0'; + return dest; +} + +char * +strlower(char * src) { + char *ptr = src; + if (!src) return src; + while(*ptr) { + *ptr = tolower(*(unsigned char *) ptr); + ptr++; + } + return src; +} + +char * +strupper(char * src) { + char *ptr = src; + if (!src) return src; + while(*ptr) { + *ptr = toupper(*(unsigned char *) ptr); + ptr++; + } + return src; +} + +int +clrspace(char *buf) { + char *ptr=buf, *ptrc=buf; + while(*ptr) { + if (!isspace(*ptr)) { + *ptrc=*ptr; + ptrc++; + } + ptr++; + } + *ptrc='\0'; + return ptrc - buf; +} + diff --git a/tmalloc.h b/tmalloc.h new file mode 100644 index 0000000..0c3a275 --- /dev/null +++ b/tmalloc.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2004 Teodor Sigaev + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __TMALLOC_H__ +#define __TMALLOC_H__ + +#include + +void * tmalloc(size_t size); +void * trealloc(void * ptr, size_t size); +void * t0malloc(size_t size); +void tfree(void * ptr); + +char * tstrdup(char * src); +char * tnstrdup(char *src, int len); +char * strlower(char * src); +char * strupper(char * src); +int clrspace(char *buf); +#endif diff --git a/tools.c b/tools.c new file mode 100644 index 0000000..a6c0206 --- /dev/null +++ b/tools.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2004 Teodor Sigaev + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include "tmalloc.h" +#include "tlog.h" +#include "tools.h" + +#define isXdigit(c) ( ((c)>='0' && (c)<='9') || ((c)>='A' && (c)<='F') || ((c)>='a' && (c)<='f') ) + +static u_int8_t str2hex[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, + 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +u_int32_t +strtox(char *src, char **end) { + u_int32_t res=0, i=0; + + while(src && *src && isXdigit(*src) && i<8) { + res = res << 4; + res |= str2hex[ *(unsigned char*)src ]; + src++; + i++; + } + + if ( end ) + *end=src; + return res; +} + +static char buf[10]; +static char hex2str[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; + +char* +xtostr(u_int32_t x) { + char *ptr=buf; + int i,wast=0; + for(i=28;i>=0;i-=4) { + *ptr = hex2str[ (x>>i) & 0x0f ]; + if ( wast || *ptr!='0' || i==0 ) { + ptr++; + wast=1; + } + } + *ptr='\0'; + return buf; +} + +double +timediff(struct timeval *begin, struct timeval *end) { + return ((double)( end->tv_sec - begin->tv_sec )) + ( (double)( end->tv_usec-begin->tv_usec ) ) / 1.0e+6; +} + +double +elapsedtime(struct timeval *begin) { + struct timeval end; + gettimeofday(&end,NULL); + return timediff(begin,&end); +} diff --git a/tools.h b/tools.h new file mode 100644 index 0000000..d70d14d --- /dev/null +++ b/tools.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2004 Teodor Sigaev + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __TTOOLS_H__ +#define __TTOOLS_H__ + +#include +#include + +u_int32_t strtox(char *src, char **end); +#define atox(x) strtox((x),NULL) +char* xtostr(u_int32_t x); + +double timediff(struct timeval *begin, struct timeval *end); +double elapsedtime(struct timeval *begin); +#endif diff --git a/udp.c b/udp.c new file mode 100644 index 0000000..c98d4a1 --- /dev/null +++ b/udp.c @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2004 Teodor Sigaev + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#include "connection.h" +#include "tlog.h" +#include "tmalloc.h" + +int +TC_AcceptUdp(char *host, int port) { + struct sockaddr_in serv_addr; + int sockfd, flags; + + if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + tlog(TL_CRIT|TL_EXIT, "udp socket %s", strerror(errno)); + if ((flags=fcntl(sockfd,F_GETFL,0)) == -1) + tlog(TL_ALARM,"fcntl F_GETFL - %s",strerror(errno)); + + if (fcntl(sockfd,F_SETFL,flags|O_NDELAY) < 0 ) + tlog(TL_ALARM,"fcntl O_NDELAY - %s",strerror(errno)); + + memset(&serv_addr, 0, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = inet_addr(host); + serv_addr.sin_port = htons(port); + + if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) + tlog(TL_CRIT|TL_EXIT, "cannot bind to %s address: %s", + inet_ntoa(serv_addr.sin_addr), strerror(errno)); + + return sockfd; +} + +#define MSGMAXSIZE 8192 +char pc_msg_buf[MSGMAXSIZE]; + +u_int32_t +TC_getMsg( int sockfd, Msg *msg ) { + struct sockaddr_in cli_addr; + int n; + socklen_t clilen = sizeof(cli_addr); + TCMsg *pmsg = (TCMsg*)pc_msg_buf; + + n = recvfrom(sockfd, pc_msg_buf, MSGMAXSIZE, 0, (struct sockaddr *)&cli_addr, &clilen); + + if ( n<0 ) { + if ( errno == EAGAIN || errno == EWOULDBLOCK) + return CS_AGAIN; + tlog(TL_ALARM, "recvfrom error: %s", strerror(errno)); + return CS_ERROR; + } + + if ( nlen > MSGMAXSIZE ) { + tlog(TL_ALARM, "Messages (%d bytes) is too big", pmsg->len); + return CS_AGAIN; + } + + if ( pmsg->len != n ) { + tlog(TL_ALARM, "Wrong size of messages (got %d bytes, should be %d bytes)", n, pmsg->len); + return CS_AGAIN; + } + + memcpy( &(msg->host_addr), &cli_addr, clilen ); + msg->msg = pmsg; + + return CS_OK; +} + +/* send */ +u_int32_t +TC_sendMsg( Msg *msg ) { + if ( msg->msg == NULL || msg->msg->len <=0 ) + return CS_OK; + + if ( msg->msg->len > MSGMAXSIZE ) + return CS_ERROR; + + if ( msg->sockfd <=0 ) { + struct sockaddr_in cli_addr; + if ( (msg->sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + tlog(TL_CRIT,"udp socket %s %d: %s", msg->host, msg->port, strerror(errno)); + return CS_ERROR; + } + + memset(&cli_addr, 0, sizeof(cli_addr)); + cli_addr.sin_family = AF_INET; + cli_addr.sin_addr.s_addr = htonl(INADDR_ANY); + cli_addr.sin_port = htons(0); + + if (bind(msg->sockfd, (struct sockaddr *) &cli_addr, sizeof(cli_addr)) < 0) { + tlog(TL_CRIT, "cannot bind to address: %s", strerror(errno)); + close(msg->sockfd); + msg->sockfd=-1; + return CS_ERROR; + } + memset(&(msg->host_addr), 0, sizeof(msg->host_addr)); + msg->host_addr.sin_family = AF_INET; + msg->host_addr.sin_addr.s_addr = inet_addr(msg->host); + msg->host_addr.sin_port = htons(msg->port); + } + + if (sendto(msg->sockfd, (void*)msg->msg, msg->msg->len, 0, (struct sockaddr *) &(msg->host_addr), sizeof(msg->host_addr)) != msg->msg->len) { + tlog(TL_CRIT,"Can't send message to %s:%d : %s", msg->host, msg->port, strerror(errno)); + close(msg->sockfd); + msg->sockfd=-1; + return CS_ERROR; + } + + return CS_OK; +} + +void +TC_closefd( Msg *msg ) { + if ( msg->sockfd > 0 ) + close(msg->sockfd); + msg->sockfd=-1; +} + + -- 2.46.1