diff options
-rw-r--r-- | pttbbs/daemon/boardd/LICENSE | 26 | ||||
-rw-r--r-- | pttbbs/daemon/boardd/Makefile | 13 | ||||
-rw-r--r-- | pttbbs/daemon/boardd/boardd.c | 370 | ||||
-rw-r--r-- | pttbbs/daemon/boardd/server.c | 194 | ||||
-rw-r--r-- | pttbbs/daemon/boardd/server.h | 19 |
5 files changed, 383 insertions, 239 deletions
diff --git a/pttbbs/daemon/boardd/LICENSE b/pttbbs/daemon/boardd/LICENSE new file mode 100644 index 00000000..50b70e96 --- /dev/null +++ b/pttbbs/daemon/boardd/LICENSE @@ -0,0 +1,26 @@ +Copyright (c) 2010-2011, Chen-Yu Tsai <wens@csie.org> +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. The names of the author and contributors may be used to endorse or + promote products derived from this software without specific prior + written permission. + +THIS SOFTWARE IS PROVIDED "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 +THE COPYRIGHT HOLDER OR 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. diff --git a/pttbbs/daemon/boardd/Makefile b/pttbbs/daemon/boardd/Makefile index 1256059d..4cd5ac3d 100644 --- a/pttbbs/daemon/boardd/Makefile +++ b/pttbbs/daemon/boardd/Makefile @@ -4,16 +4,23 @@ SRCROOT= ../.. .include "$(SRCROOT)/pttbbs.mk" PROG= boardd +SRCS= boardd.c server.c -SRCS= boardd.c - +CLEANFILES+= *~ UTILDIR= $(SRCROOT)/util UTILOBJ= $(UTILDIR)/util_var.o +LIBEVENT_CFLAGS!= pkg-config --cflags libevent +LIBEVENT_LIBS_L!= pkg-config --libs-only-L libevent +LIBEVENT_LIBS_l!= pkg-config --libs-only-l libevent + +CFLAGS+= $(LIBEVENT_CFLAGS) +LDFLAGS+= $(LIBEVENT_LIBS_L) + LDADD+= $(UTILOBJ) \ $(SRCROOT)/common/bbs/libcmbbs.a \ $(SRCROOT)/common/sys/libcmsys.a \ $(SRCROOT)/common/osdep/libosdep.a \ - -levent + $(LIBEVENT_LIBS_l) .include <bsd.prog.mk> diff --git a/pttbbs/daemon/boardd/boardd.c b/pttbbs/daemon/boardd/boardd.c index b6fb5cc7..e6e7966f 100644 --- a/pttbbs/daemon/boardd/boardd.c +++ b/pttbbs/daemon/boardd/boardd.c @@ -1,343 +1,241 @@ // $Id$ +// Memcached protocol based board data export daemon -// Copyright (c) 2010, Chen-Yu Tsai <wens@csie.org> +// Copyright (c) 2010-2011, Chen-Yu Tsai <wens@csie.org> // 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. The names of the author and contributors may be used to endorse or -// promote products derived from this software without specific prior -// written permission. -// -// THIS SOFTWARE IS PROVIDED "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 -// THE COPYRIGHT HOLDER OR 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 <stdio.h> + +// TODO: +// 1. [done] add hotboard support +// 2. [done] rewrite with libevent 2.0 +// 3. [done] split out independent server code +// 4. [done] add article list support +// 5. add article content support +// 6. encode output in UTF-8 (with UAO support) +// 7. encode article list in JSON for better structure + #include <stdlib.h> #include <string.h> -#include <strings.h> #include <ctype.h> -#include <unistd.h> -#include <fcntl.h> -#include <signal.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <event.h> +#include <event2/buffer.h> +#include <event2/bufferevent.h> +#include <event2/util.h> -#include "cmsys.h" -#include "cmbbs.h" -#include "config.h" -#include "var.h" +#include <cmbbs.h> +#include <var.h> +#include <perm.h> -static struct event ev_listen; +#include "server.h" -static const char whitespace[] = " \t\r\n"; +#define DEFAULT_ARTICLE_LIST 20 -#define TIMEOUT 600 -#define MAX_CLIENTS 1000 -#define BUF_SIZE 8192 +// helper function -typedef struct { - struct bufferevent * bufev; - int fd; -} conn_ctx; +#define BOARD_HIDDEN(bptr) (bptr->brdattr & (BRD_HIDE | BRD_TOP) || \ + (bptr->level & ~(PERM_BASIC|PERM_CHAT|PERM_PAGE|PERM_POST|PERM_LOGINOK) && \ + !(bptr->brdattr & BRD_POSTMASK))) -typedef struct { - char *cmd; - void (*func)(conn_ctx *ctx, const char * arg); -} CMD; +static void +article_list(struct evbuffer *buf, boardheader_t *bptr, int offset, int length) +{ + int total, fd = -1; + char path[PATH_MAX]; + fileheader_t fhdr; -static char databuf[BUF_SIZE]; + setbfile(path, bptr->brdname, FN_DIR); + total = get_num_records(path, sizeof(fileheader_t)); -void cb_endconn(struct bufferevent *bufev, short what, void *arg); + if (total <= 0) + return; -// helper function + while (offset < 0) + offset += total; -#define BOARD_HIDDEN(bptr) (bptr->brdattr & (BRD_HIDE | BRD_TOP) || \ - (bptr->level & ~(PERM_BASIC|PERM_CHAT|PERM_PAGE|PERM_POST|PERM_LOGINOK) && \ - !(bptr->brdattr & BRD_POSTMASK))) -void answer_key(const char *key, int keylen, struct evbuffer *buf) + while (length-- > 0) { + if (get_records_keep(path, &fhdr, sizeof(fhdr), ++offset, 1, &fd) <= 0) + break; + + evbuffer_add_printf(buf, "%d,%s,%s,%s,%s\n", + offset, fhdr.filename, fhdr.date, fhdr.owner, fhdr.title); + } + + if (fd >= 0) + close(fd); +} + +static void +answer_key(struct evbuffer *buf, const char *key) { - char *data, *p; int bid; boardheader_t *bptr; if (isdigit(*key)) { + char *p; + if ((bid = atoi(key)) == 0 || bid > MAX_BOARD) return; - if ((p = memchr(key, '.', keylen)) == NULL) + if ((p = strchr(key, '.')) == NULL) return; - p++; bptr = getbcache(bid); if (!bptr->brdname[0] || BOARD_HIDDEN(bptr)) return; - if (strncmp(p, "isboard", 7) == 0) - data = (bptr->brdattr & BRD_GROUPBOARD) ? "0" : "1"; - else if (strncmp(p, "hidden", 6) == 0) - data = BOARD_HIDDEN(bptr) ? "1" : "0"; - else if (strncmp(p, "brdname", 7) == 0) - data = bptr->brdname; - else if (strncmp(p, "over18", 6) == 0) - data = (bptr->brdattr & BRD_OVER18) ? "1" : "0"; - else if (strncmp(p, "title", 5) == 0) - data = bptr->title; - else if (strncmp(p, "BM", 2) == 0) - data = bptr->BM; - else if (strncmp(p, "parent", 6) == 0) { - snprintf(databuf, sizeof(databuf), "%d", bptr->parent); - data = databuf; - } else if (strncmp(p, "children", 8) == 0) { + key = p + 1; + + if (strcmp(key, "isboard") == 0) + evbuffer_add_printf(buf, "%d", (bptr->brdattr & BRD_GROUPBOARD) ? 0 : 1); + else if (strcmp(key, "over18") == 0) + evbuffer_add_printf(buf, "%d", (bptr->brdattr & BRD_OVER18) ? 0 : 1); + else if (strcmp(key, "hidden") == 0) + evbuffer_add_printf(buf, "%d", BOARD_HIDDEN(bptr) ? 0 : 1); + else if (strcmp(key, "brdname") == 0) + evbuffer_add(buf, bptr->brdname, strlen(bptr->brdname)); + else if (strcmp(key, "title") == 0) + evbuffer_add(buf, bptr->title + 7, strlen(bptr->title) - 7); + else if (strcmp(key, "class") == 0) + evbuffer_add(buf, bptr->title, 4); + else if (strcmp(key, "BM") == 0) + evbuffer_add(buf, bptr->BM, strlen(bptr->BM)); + else if (strcmp(key, "parent") == 0) + evbuffer_add_printf(buf, "%d", bptr->parent); + else if (strcmp(key, "count") == 0) { + char path[PATH_MAX]; + setbfile(path, bptr->brdname, FN_DIR); + evbuffer_add_printf(buf, "%d", get_num_records(path, sizeof(fileheader_t))); + } else if (strcmp(key, "children") == 0) { if (!(bptr->brdattr & BRD_GROUPBOARD)) return; - data = p = databuf; for (bid = bptr->firstchild[1]; bid > 0; bid = bptr->next[1]) { bptr = getbcache(bid); - p += snprintf(p, sizeof(databuf) - (databuf - p), "%d,", bid); + evbuffer_add_printf(buf, "%d,", bid); } + } else if (strncmp(key, "articles.", 9) == 0) { + int offset, length; + + key += 9; + + if (!isdigit(*key) && *key != '-') + return; + + offset = atoi(key); + p = strchr(key, '.'); - *--p = '\0'; + if (!p || (length = atoi(p+1)) == 0) + length = DEFAULT_ARTICLE_LIST; + + return article_list(buf, bptr, offset, length); } else return; } else if (strncmp(key, "tobid.", 6) == 0) { - char *bname = strndup(key + 6, keylen - 6); - bid = getbnum(bname); - free(bname); + bid = getbnum(key + 6); bptr = getbcache(bid); if (!bptr->brdname[0] || BOARD_HIDDEN(bptr)) return; - snprintf(databuf, sizeof(databuf), "%d", bid); - data = databuf; + evbuffer_add_printf(buf, "%d", bid); #if HOTBOARDCACHE } else if (strncmp(key, "hotboards", 9) == 0) { - data = p = databuf; for (bid = 0; bid < SHM->nHOTs; bid++) { bptr = getbcache(SHM->HBcache[bid] + 1); if (BOARD_HIDDEN(bptr)) continue; - p += snprintf(p, sizeof(databuf) - (databuf - p), "%d,", SHM->HBcache[bid] + 1); + evbuffer_add_printf(buf, "%d,", SHM->HBcache[bid] + 1); } - - *--p = '\0'; #endif - } else - return; - - evbuffer_add_printf(buf, "VALUE %.*s 0 %ld\r\n%s\r\n", keylen, key, strlen(data), data); + } } // Command functions void -cmd_get(conn_ctx *ctx, const char *arg) +cmd_get(struct bufferevent *bev, void *ctx, int argc, char **argv) { - const char *key; - size_t keylen; - static struct evbuffer *buf; + struct evbuffer *output = bufferevent_get_output(bev), + *buf = evbuffer_new(); - key = arg + strspn(arg, whitespace); - - if (*key == '\0') { - bufferevent_write(ctx->bufev, "ERROR\r\n", 7); + if (*argv++ == NULL) { + evbuffer_add_reference(output, "ERROR\r\n", 7, NULL, NULL); return; } - if (buf == NULL) - if ((buf = evbuffer_new()) == NULL) { - const char msg[] = "SERVER_ERROR Can't allocate buffer\r\n"; - bufferevent_write(ctx->bufev, msg, strlen(msg)); - return; - } - - while (*key) { - keylen = strcspn(key, whitespace); - - answer_key(key, keylen, buf); + do { + answer_key(buf, *argv); + if (evbuffer_get_length(buf) == 0) + continue; + evbuffer_add_printf(output, "VALUE %s 0 %ld\r\n", *argv, evbuffer_get_length(buf)); + evbuffer_add_buffer(output, buf); + evbuffer_add_printf(output, "\r\n"); + } while (*++argv); - bufferevent_write_buffer(ctx->bufev, buf); - - key += keylen; - key += strspn(key, whitespace); - } - - bufferevent_write(ctx->bufev, "END\r\n", 5); + evbuffer_add_reference(output, "END\r\n", 5, NULL, NULL); } void -cmd_version(conn_ctx *ctx, const char *arg) +cmd_version(struct bufferevent *bev, void *ctx, int argc, char **argv) { const char msg[] = "VERSION 0.0.1\r\n"; - bufferevent_write(ctx->bufev, msg, strlen(msg)); + evbuffer_add_reference(bufferevent_get_output(bev), msg, strlen(msg), NULL, NULL); } void -cmd_unknown(conn_ctx *ctx, const char *arg) +cmd_unknown(struct bufferevent *bev, void *ctx, int argc, char **argv) { const char msg[] = "SERVER_ERROR Not implemented\r\n"; - bufferevent_write(ctx->bufev, msg, strlen(msg)); + evbuffer_add_reference(bufferevent_get_output(bev), msg, strlen(msg), NULL, NULL); } void -cmd_quit(conn_ctx *ctx, const char * arg) +cmd_quit(struct bufferevent *bev, void *ctx, int argc, char **argv) { - cb_endconn(ctx->bufev, 0, ctx); + bufferevent_free(bev); } -static const CMD cmdlist[] = { +static const struct { + const char *cmd; + void (*func)(struct bufferevent *bev, void *ctx, int argc, char **argv); +} cmdlist[] = { {"get", cmd_get}, {"quit", cmd_quit}, {"version", cmd_version}, {NULL, cmd_unknown} }; -// Callbacks - void -cb_client(struct bufferevent *bufev, void *arg) +client_read_cb(struct bufferevent *bev, void *ctx) { - conn_ctx *ctx = arg; - char *p, *cmd, *line = NULL; - int i; + int argc, i; + char **argv; + size_t len; + struct evbuffer *input = bufferevent_get_input(bev); + char *line = evbuffer_readln(input, &len, EVBUFFER_EOL_CRLF); - if ((line = evbuffer_readline(EVBUFFER_INPUT(bufev))) == NULL) + if (!line) return; - fprintf(stderr, "Client cmd [%d] %s\n", ctx->fd, line); - - cmd = line + strspn(line, whitespace); - p = cmd + strcspn(cmd, whitespace); - *p++ = '\0'; - p += strspn(p, whitespace); + argc = split_args(line, &argv); for (i = 0; cmdlist[i].cmd; i++) - if (strcasecmp(line, cmdlist[i].cmd) == 0) + if (evutil_ascii_strcasecmp(line, cmdlist[i].cmd) == 0) break; - (cmdlist[i].func)(ctx, p); - - free(line); -} - -void -cb_endconn(struct bufferevent *bufev, short what, void *arg) -{ - conn_ctx *ctx = arg; - close(ctx->fd); - bufferevent_free(bufev); - free(ctx); + (cmdlist[i].func)(bev, ctx, argc, argv); - fprintf(stderr, "Client disconnect: %d\n", ctx->fd); -} - -void -setup_client(int fd) -{ - fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK); - - conn_ctx *ctx = calloc(1, sizeof(conn_ctx)); - - if (ctx == NULL) { - close(fd); - return; - } - - if ((ctx->bufev = bufferevent_new(fd, cb_client, NULL, cb_endconn, ctx)) == NULL) { - free(ctx); - close(fd); - return; - } - - ctx->fd = fd; - bufferevent_settimeout(ctx->bufev, TIMEOUT, TIMEOUT); - bufferevent_enable(ctx->bufev, EV_READ | EV_WRITE); + free(argv); + free(line); } void -cb_listen(int fd, short event, void *arg) -{ - struct sockaddr_in clientaddr; - socklen_t len = sizeof(clientaddr); - int cfd; - - if ((cfd = accept(fd, (struct sockaddr *)&clientaddr, &len)) < 0 ) - return; - - setup_client(cfd); - - fprintf(stderr, "Client connect: %d\n", cfd); -} - -int main(int argc, char *argv[]) +setup_program() { - int ch, sfd = 0, inetd = 0, daemon = 1; - char *iface_ip = "127.0.0.1:5150"; - struct event_base *evb; - - Signal(SIGPIPE, SIG_IGN); - while ((ch = getopt(argc, argv, "Dil:h")) != -1) - switch (ch) { - case 'D': - daemon = 0; - break; - case 'i': - inetd = 1; - break; - case 'l': - iface_ip = optarg; - break; - case 'h': - default: - fprintf(stderr, "usage: boardd [-D] [-i] [-l [interface_ip]:port]\n"); - return 1; - } - - if (!inetd) - if ((sfd = tobindex(iface_ip, 100, NULL, 1)) < 0) - return 1; - setuid(BBSUID); setgid(BBSGID); + chdir(BBSHOME); - srandom(getpid() + time(NULL)); attach_SHM(); - - if (daemon) - daemonize(BBSHOME "/run/boardd.pid", NULL); - - evb = event_init(); - event_base_priority_init(evb, 4); - - if (!inetd) { - fcntl(sfd, F_SETFL, fcntl(sfd, F_GETFL, 0) | O_NONBLOCK); - event_set(&ev_listen, sfd, EV_READ | EV_PERSIST, cb_listen, &ev_listen); - event_priority_set(&ev_listen, 3); - event_add(&ev_listen, NULL); - } else - setup_client(0); - event_dispatch(); - - return 0; } + diff --git a/pttbbs/daemon/boardd/server.c b/pttbbs/daemon/boardd/server.c new file mode 100644 index 00000000..2f9bbac1 --- /dev/null +++ b/pttbbs/daemon/boardd/server.c @@ -0,0 +1,194 @@ +// $Id$ +// Barebone TCP socket server daemon based on libevent 2.0 + +// Copyright (c) 2011, Chen-Yu Tsai <wens@csie.org> +// All rights reserved. + +// This is a simple TCP/IP server daemon based on libevent 2.0. +// This program does not depend on anything other than libevent 2.0. +// Without additional code linked in, this program alone will behave as an +// echo server. +// +// You can supply your client_read_cb(), client_event_cb(), setup_client(), or +// setup_program() functions to modify the behavior of the server. + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#include <unistd.h> +#include <assert.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/socket.h> +#include <netinet/in.h> + +#include <event2/event.h> +#include <event2/buffer.h> +#include <event2/bufferevent.h> +#include <event2/util.h> +#include <event2/listener.h> + +#include "server.h" + +static const struct timeval timeout = {600, 0}; + +int +split_args(char *line, char ***argp) +{ + int argc = 0; + char *p, **argv; + + if ((argv = calloc(MAX_ARGS + 1, sizeof(char *))) == NULL) + return -1; + + while ((p = strsep(&line, " \t\r\n")) != NULL) { + argv[argc++] = p; + + if (argc == MAX_ARGS) + break; + } + + argv = realloc(argv, (argc + 1) * sizeof(char *)); + *argp = argv; + + return argc; +} + +void __attribute__((weak)) +client_read_cb(struct bufferevent *bev, void *ctx) +{ + bufferevent_write_buffer(bev, bufferevent_get_input(bev)); +} + +void __attribute__((weak)) +client_event_cb(struct bufferevent *bev, short events, void *ctx) +{ + if (events & BEV_EVENT_ERROR) + perror("Error from bufferevent"); + if (events & (BEV_EVENT_EOF | BEV_EVENT_TIMEOUT | BEV_EVENT_ERROR)) { + bufferevent_free(bev); + } +} + +void __attribute__((weak)) +setup_client(struct event_base *base, evutil_socket_t fd, + struct sockaddr *address, int socklen) +{ + struct bufferevent *bev = bufferevent_socket_new(base, fd, + BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS); + bufferevent_setcb(bev, client_read_cb, NULL, client_event_cb, NULL); + bufferevent_set_timeouts(bev, &timeout, &timeout); + bufferevent_enable(bev, EV_READ|EV_WRITE); +} + +static void +accept_conn_cb(struct evconnlistener *listener, evutil_socket_t fd, + struct sockaddr *address, int socklen, void *ctx) +{ + struct event_base *base = evconnlistener_get_base(listener); + return setup_client(base, fd, address, socklen); +} + +int __attribute__((weak)) daemon(int nochdir, int noclose); +void __attribute__((weak)) setup_program(); + +int main(int argc, char *argv[]) +{ + int ch, inetd = 0, run_as_daemon = 1; + const char *iface_ip = "127.0.0.1:5150"; + struct event_base *base; + struct evconnlistener *listener; + + while ((ch = getopt(argc, argv, "Dil:h")) != -1) + switch (ch) { + case 'D': + run_as_daemon = 0; + break; + case 'i': + inetd = 1; + break; + case 'l': + iface_ip = optarg; + break; + case 'h': + default: + fprintf(stderr, "usage: " " [-D] [-i] [-l interface_ip:port]\n"); + exit(EXIT_FAILURE); + } + + if (run_as_daemon && !inetd) + if (daemon(1, 1) < 0) { + perror("daemon"); + exit(EXIT_FAILURE); + } + + base = event_base_new(); + assert(base); + + if (!inetd) { + struct sockaddr sa; + int len = sizeof(sa); + + if (evutil_parse_sockaddr_port(iface_ip, &sa, &len) < 0) + exit(EXIT_FAILURE); + + listener = evconnlistener_new_bind(base, accept_conn_cb, NULL, + LEV_OPT_CLOSE_ON_FREE | LEV_OPT_CLOSE_ON_EXEC | LEV_OPT_REUSEABLE, + 100, &sa, len); + + if (!listener) + exit(EXIT_FAILURE); + } else { + struct sockaddr sa; + socklen_t len = sizeof(sa); + getpeername(0, &sa, &len); + setup_client(base, 0, &sa, len); + } + + if (setup_program) + setup_program(); + + signal(SIGPIPE, SIG_IGN); + + event_base_dispatch(base); + + return 0; +} + +#ifdef __linux__ + +int +daemon(int nochdir, int noclose) +{ + int fd; + + switch (fork()) { + case -1: + return -1; + case 0: + break; + default: + _exit(0); + } + + if (setsid() == -1) + return -1; + + if (!nochdir) + chdir("/"); + + if (!noclose && (fd = open("/dev/null", O_RDWR)) >= 0) { + dup2(fd, 0); + dup2(fd, 1); + dup2(fd, 2); + + if (fd > 2) + close(fd); + } + + return 0; +} + +#endif // __linux__ diff --git a/pttbbs/daemon/boardd/server.h b/pttbbs/daemon/boardd/server.h new file mode 100644 index 00000000..9cba93b7 --- /dev/null +++ b/pttbbs/daemon/boardd/server.h @@ -0,0 +1,19 @@ +// $Id$ + +// Copyright (c) 2011, Chen-Yu Tsai <wens@csie.org> +// All rights reserved. + +#include <event2/listener.h> +#include <event2/bufferevent.h> + +#ifndef MAX_ARGS +#define MAX_ARGS 100 +#endif + +extern void client_read_cb(struct bufferevent *bev, void *ctx); +extern void client_event_cb(struct bufferevent *bev, short events, void *ctx); +extern void setup_client(struct event_base *base, evutil_socket_t fd, + struct sockaddr *address, int socklen); +extern void setup_program(); + +extern int split_args(char *line, char ***argp); |