From: teodor Date: Wed, 22 Sep 2004 10:59:48 +0000 (+0000) Subject: Initial revision X-Git-Tag: start~1 X-Git-Url: http://www.sigaev.ru/git/gitweb.cgi?a=commitdiff_plain;h=04db7ca7ed3bfb4df76d3df4b418f9a7c3d97ab2;p=tedtools.git Initial revision --- 04db7ca7ed3bfb4df76d3df4b418f9a7c3d97ab2 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; +} + +