From 86fd197a95f72d09e5cccbc059829ff5f6b03b87 Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Tue, 19 Aug 2008 19:46:10 +0400 Subject: [PATCH] * Add initial implementation of rspamd XS module --- Makefile.in | 7 +++- configure | 20 +++++++-- main.h | 13 ++++++ perl/Makefile.PL.in | 9 ++++ perl/rspamd.pm | 30 +++++++++++++ perl/rspamd.xs | 100 ++++++++++++++++++++++++++++++++++++++++++++ perl/typemap | 3 ++ worker.c | 21 +++++++++- 8 files changed, 197 insertions(+), 6 deletions(-) create mode 100644 perl/Makefile.PL.in create mode 100644 perl/rspamd.pm create mode 100644 perl/rspamd.xs create mode 100644 perl/typemap diff --git a/Makefile.in b/Makefile.in index aa9112e70..65cd1a405 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,5 +1,8 @@ -all: $(TARGETS) +all: perl $(TARGETS) + +perl: + cd perl && make && cd .. memctest: upstream.c memcached.c memcached-test.c $(CC) $(OPT_FLAGS) $(CFLAGS) $(PTHREAD_CFLAGS) -c upstream.c @@ -17,11 +20,13 @@ install: $(EXEC) clean: rm -f *.o $(EXEC) *.core rm -f cfg_lex.c cfg_yacc.c cfg_yacc.h + cd perl && make clean && cd .. dist-clean: clean rm -f Makefile rm -f config.log rm -f md5.h md5.c strlcpy.h strlcpy.c queue.h config.h modules.c + cd perl && rm -f Makefile.old && rm -f Makefile.PL && cd .. creategroup: @echo "Create group $(RSPAMD_GROUP) before installing!" diff --git a/configure b/configure index 1a822576d..776c15e1c 100755 --- a/configure +++ b/configure @@ -40,6 +40,9 @@ MANPATH="${PREFIX}/share/man" MAKEFILE="Makefile" MAKEFILE_IN="Makefile.in" +PERL_MAKEFILE="perl/Makefile.PL.in" +PERLCFLAGS="" +PERLLDFLAGS="" TARGETS="${EXEC}" @@ -339,8 +342,6 @@ check_perl() $GCC $CFLAGS $PERLCFLAGS $PTHREAD_CFLAGS -o autotest $LDFLAGS $LIBS $PERLLDFLAGS $PTHREAD_LDFLAGS autotest.c >>config.log 2>&1 if [ $? -eq 0 ] ; then echo "found" - LIBS="$LIBS $PERLLDFLAGS" - CFLAGS="$CFLAGS $PERLCFLAGS" cleanup echo "-> OK" >> config.log return 0 @@ -424,9 +425,21 @@ write_result() echo "#define MODULES_NUM $modules_num" >> $CONFIG SOURCES="$SOURCES modules.c" OBJECTS=`echo $SOURCES | sed -e 's/\.c/\.o/g'` + # Write to perl Makefile + sed -e "s|%%libs%%|${LDFLAGS} ${LIBS}|" < $PERL_MAKEFILE > .pl_tmp + sed -e "s|%%include%%|${CFLAGS}|" < .pl_tmp > .pl2_tmp + PERL_MAKEFILE=`echo ${PERL_MAKEFILE} | sed -e 's|.in$||'` + mv .pl2_tmp $PERL_MAKEFILE + rm -f .pl_tmp .pl2_tmp + CURDIR=`pwd` + cd `dirname ${PERL_MAKEFILE}` + $PERL Makefile.PL + cd $CURDIR # Make CFLAGS more readable + CFLAGS="$CFLAGS $PERLCFLAGS" + LIBS="$LIBS $PERLLDFLAGS" CFLAGS=`echo $CFLAGS | tr [:space:] \\\n | sed -e 's/$/ \\\/' | sed -e '$,$s/\\\//' | sort -r -k2 | uniq` - LDFLAGS=`echo $LDLAGS | tr [:space:] \\\n | sed -e 's/$/ \\\/' | sed -e '$,$s/\\\//' | sort -r -k2 | uniq` + LDFLAGS=`echo $LDFLAGS | tr [:space:] \\\n | sed -e 's/$/ \\\/' | sed -e '$,$s/\\\//' | sort -r -k2 | uniq` LIBS=`echo $LIBS | tr [:space:] \\\n | sed -e 's/$/ \\\/' | sed -e '$,$s/\\\//' | sort -r -k2 | uniq` cat > $MAKEFILE << END # This is ${EXEC} Makefile @@ -497,7 +510,6 @@ ${LEX_OUTPUT}: cfg_file.h ${LEX_SRC} ${YACC_OUTPUT} ${YACC_OUTPUT}: cfg_file.h ${YACC_SRC} \$(YACC) -d -o ${YACC_OUTPUT} ${YACC_SRC} END - } diff --git a/main.h b/main.h index e263b9521..b2441bbe7 100644 --- a/main.h +++ b/main.h @@ -22,6 +22,9 @@ #include "fstring.h" #include "url.h" +#include +#include + /* Default values */ #define FIXED_CONFIG_FILE "./rspamd.conf" /* Time in seconds to exit for old worker */ @@ -74,6 +77,12 @@ struct filter_result { TAILQ_ENTRY (filter_result) next; }; +struct mime_part { + GMimeContentType *type; + GByteArray *content; + TAILQ_ENTRY (mime_part) next; +}; + struct worker_task { struct rspamd_worker *worker; enum { @@ -93,6 +102,10 @@ struct worker_task { struct bufferevent *bev; /* Number of mime parts */ int parts_count; + /* Headers */ + GMimeMessage *message; + /* All parts of message */ + TAILQ_HEAD (mime_partq, mime_part) parts; /* URLs extracted from message */ TAILQ_HEAD (uriq, uri) urls; /* List of filter results */ diff --git a/perl/Makefile.PL.in b/perl/Makefile.PL.in new file mode 100644 index 000000000..9b436f12f --- /dev/null +++ b/perl/Makefile.PL.in @@ -0,0 +1,9 @@ +use ExtUtils::MakeMaker; +WriteMakefile( + NAME => 'rspamd', + VERSION_FROM => 'rspamd.pm', # finds $VERSION + LIBS => ['%%libs%%'], # e.g., '-lm' + DEFINE => '', + INC => '%%include%%', +); + diff --git a/perl/rspamd.pm b/perl/rspamd.pm new file mode 100644 index 000000000..99e0e4908 --- /dev/null +++ b/perl/rspamd.pm @@ -0,0 +1,30 @@ +package rspamd; + +use 5.006001; +use strict; +use warnings; + +require Exporter; + +our @ISA = qw(Exporter); + +our $VERSION = '0.0.1'; + +require XSLoader; +XSLoader::load('rspamd', $VERSION); +1; +__END__ + +=head1 NAME + +rspamd - Perl interface to the rspamd API + +=head1 SYNOPSIS + + use rpspamd; + +=head1 DESCRIPTION + +TODO: Not ready yet + +=cut diff --git a/perl/rspamd.xs b/perl/rspamd.xs new file mode 100644 index 000000000..ada7a5997 --- /dev/null +++ b/perl/rspamd.xs @@ -0,0 +1,100 @@ +/* + * Perl XS module for interacting with rspamd + * + * vi:ts=4 + */ + +#include +#include +#include "../config.h" +#include "../main.h" + +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" + +#define perl_set_session(r) \ + r = INT2PTR(struct worker_task *, SvIV((SV *) SvRV(ST(0)))) + +#define perl_set_targ(p, len) \ + SvUPGRADE(TARG, SVt_PV); \ + SvPOK_on(TARG); \ + sv_setpvn(TARG, (char *) p, len) + +MODULE = rspamd PACKAGE = rspamd +PROTOTYPES: DISABLE + +void +get_header (r, header) + CODE: + dXSTARG; + struct worker_task *r; + SV *header; + char *s; + STRLEN len; + + perl_set_session(r); + + header = ST(1); + if (SvROK (header) && SvTYPE (SvRV (header)) == SVt_PV) { + header = SvRV (header); + } + + s = (char *) SvPV (header, len); + + if ((s = (char *)g_mime_message_get_header (r->message, s)) == NULL) { + XSRETURN_UNDEF; + } + else { + ngx_http_perl_set_targ (s, strlen (s)); + ST(0) = TARG; + } + +void +get_part_num (r) + CODE: + dXSTARG; + struct worker_task *r; + + perl_set_session (r); + sv_upgrade(TARG, SVt_IV); + sv_setiv(TARG, r->parts_count); + + ST(0) = TARG; + + +HV * +get_part (r, num) + CODE: + struct worker_task *r; + SV *num; + int number; + struct mime_part *part; + char *type; + + perl_set_session (r); + num = ST(1); + + number = (int) SvIV (num); + if (number < 0 || number > r->parts_count - 1) { + XSRETURN_UNDEF; + } + + TAILQ_FOREACH (part, &r->parts, next) { + if (--number == 0) { + break; + } + } + RETVAL = newHV(); + type = g_mime_content_type_to_string (part->type); + + hv_store_ent (RETVAL, + newSVpv ("type", sizeof ("type") - 1), + newSVpv (type, strlen(type)), 0); + hv_store_ent (RETVAL, + newSVpv ("content", sizeof ("content") - 1), + newSVpv ((char *)part->content->data, part->content->len), 0); + sv_2mortal((SV*)RETVAL); + OUTPUT: + RETVAL + diff --git a/perl/typemap b/perl/typemap new file mode 100644 index 000000000..17a1b16eb --- /dev/null +++ b/perl/typemap @@ -0,0 +1,3 @@ +TYPEMAP + +rspamd T_PTROBJ diff --git a/worker.c b/worker.c index ab02ecea2..0b3dd30bc 100644 --- a/worker.c +++ b/worker.c @@ -73,12 +73,16 @@ free_task (struct worker_task *task) { struct uri *cur; struct filter_result *res; + struct mime_part *part; if (task) { if (task->msg) { fstrfree (task->msg->buf); free (task->msg); } + if (task->message) { + g_object_unref (task->message); + } if (task->helo) { free (task->helo); } @@ -90,15 +94,22 @@ free_task (struct worker_task *task) } while (!TAILQ_EMPTY (&task->urls)) { cur = TAILQ_FIRST (&task->urls); + TAILQ_REMOVE (&task->urls, cur, next); free (cur->string); free (cur); - TAILQ_REMOVE (&task->urls, cur, next); } while (!TAILQ_EMPTY (&task->results)) { res = TAILQ_FIRST (&task->results); free (res); TAILQ_REMOVE (&task->results, res, next); } + while (!TAILQ_EMPTY (&task->parts)) { + part = TAILQ_FIRST (&task->parts); + g_object_unref (part->type); + g_object_unref (part->content); + TAILQ_REMOVE (&task->parts, part, next); + free (part); + } free (task); } } @@ -107,6 +118,7 @@ static void mime_foreach_callback (GMimeObject *part, gpointer user_data) { struct worker_task *task = (struct worker_task *)user_data; + struct mime_part *mime_part; const GMimeContentType *type; GMimeDataWrapper *wrapper; GMimeStream *part_stream; @@ -150,6 +162,10 @@ mime_foreach_callback (GMimeObject *part, gpointer user_data) if (g_mime_data_wrapper_write_to_stream (wrapper, part_stream) != -1) { part_content = g_mime_stream_mem_get_byte_array (GMIME_STREAM_MEM (part_stream)); type = g_mime_part_get_content_type (GMIME_PART (part)); + mime_part = g_malloc (sizeof (struct mime_part)); + mime_part->type = type; + mime_part->content = part_content; + TAILQ_INSERT_TAIL (&task->parts, mime_part, next); if (g_mime_content_type_is_type (type, "text", "html")) { url_parse_html (task, part_content); } @@ -182,6 +198,8 @@ process_message (struct worker_task *task) /* parse the message from the stream */ message = g_mime_parser_construct_message (parser); + + task->message = message; /* free the parser (and the stream) */ g_object_unref (parser); @@ -385,6 +403,7 @@ accept_socket (int fd, short what, void *arg) new_task->parts_count = 0; TAILQ_INIT (&new_task->urls); TAILQ_INIT (&new_task->results); + TAILQ_INIT (&new_task->parts); /* Read event */ new_task->bev = bufferevent_new (nfd, read_socket, write_socket, err_socket, (void *)new_task); -- 2.39.5