Skip to content
Commits on Source (4)
UNAME = $(shell uname)
GITVER = $(shell git describe --always --dirty)
VERSION = $(GITVER)
......@@ -68,6 +69,10 @@ MWLDFLAGS += -O0
endif
MWCFLAGS = -std=gnu99 -g $(DEFS) $(CCSEC) $(WARNINGS)
ifeq ($(UNAME),FreeBSD)
MWCFLAGS += -I/usr/local/include
MWLDFLAGS = -L/usr/local/lib
endif
ifneq ($(RELEASE_BUILD),0)
MWCFLAGS += -O2
# This requires optimisation so add it here instead of CCSEC
......
......@@ -3,8 +3,8 @@ DEPTH=../
include ../Makefile.common
build: libmw.a
$(MAKE) -C server $@
$(MAKE) -C client $@
$(MAKE) -C server $@
$(MAKE) -C webclient $@
$(MAKE) -C utils $@
ln -fs server/mwserv client/mw .
......
......@@ -13,8 +13,12 @@ JSDIR = $(JSDIR_$(JSENGINE))
JSOBJ = $(JSOBJ_$(JSENGINE))
JSFLAGS = $(JSFLAGS_$(JSENGINE))
LDLIBS+= -lreadline -ltermcap -lcrypt -lsqlite3 -lcurl -lpthread -lcrypto -ljansson -lz -lm
CFLAGS+= -I.. $(JSFLAGS)
LDLIBS += -lreadline -ltermcap -lcrypt -lsqlite3 -lcurl -lpthread -lcrypto -ljansson -lz -lm
ifeq ($(UNAME),FreeBSD)
LDLIBS += -lintl
endif
CFLAGS += -I.. $(JSFLAGS)
# Force build order as we need generated mozjs headers to build mw
build: $(JSOBJ)
......
......@@ -15,6 +15,7 @@
#include <time.h>
#include <stdbool.h>
#include <sys/stat.h>
#include <signal.h>
#include <util.h>
#include "talker_privs.h"
......
......@@ -12,6 +12,10 @@
#include <termcap.h>
#include <stdbool.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#include "command.h"
#include "alarm.h"
......
......@@ -8,6 +8,7 @@
#include <time.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <string.h>
#include "files.h"
#include "str_util.h"
......
......@@ -4,6 +4,7 @@
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#include <time.h>
......
......@@ -27,6 +27,7 @@ struct hlist_node {
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#undef LIST_HEAD
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
......
......@@ -2,8 +2,16 @@ SRCROOT = $(CURDIR)/../..
DEPTH=../../
include $(DEPTH)Makefile.common
CFLAGS+= -I..
LDLIBS+= -ljansson -lsqlite3
POLLER = epoll
CFLAGS += -I..
ifeq ($(UNAME),FreeBSD)
CFLAGS += -DSTRFRY_MISSING
POLLER := kqueue
endif
CODE := $(filter-out poll-%.c, $(CODE)) poll-$(POLLER).c
LDLIBS += -ljansson -lsqlite3
build: mwserv
......
......@@ -10,9 +10,6 @@
#include "talker_privs.h"
#include "gags.h"
/* should be defined by strings.h */
char *strfry(char *string);
/* local prototypes */
void gag_normal(char *text);
void gag_chef(char *text);
......@@ -385,6 +382,7 @@ void gag_swab(char *text)
/* strfry */
void gag_strfry(char *text)
{
#ifndef STRFRY_MISSING
char *new;
char *old = strdup(text);
char str[MAXTEXTLENGTH];
......@@ -398,6 +396,7 @@ void gag_strfry(char *text)
free(new);
free(old);
#endif
}
static char *duplstr(char *text)
......
#include <sys/epoll.h>
#include <strings.h>
#include <socket.h>
#include "poll.h"
struct epoll_priv {
int pollfd;
};
struct epoll_priv ep = {
.pollfd = -1
};
int poll_addconn(ipc_connection_t *conn)
{
struct epoll_event ev;
int ret;
bzero(&ev, sizeof(ev));
ev.events = EPOLLIN | EPOLLERR;
ev.data.ptr = conn;
ret = epoll_ctl(ep.pollfd, EPOLL_CTL_ADD, conn->fd, &ev);
return ret;
}
int poll_init(void)
{
if (ep.pollfd == -1)
ep.pollfd = epoll_create(30);
return 0;
}
void poll_delete(int fd)
{
struct epoll_event ev;
bzero(&ev, sizeof(ev));
epoll_ctl(ep.pollfd, EPOLL_CTL_DEL, fd, &ev);
}
int poll_with_writes(ipc_connection_t *conn)
{
struct epoll_event ev;
bzero(&ev, sizeof(ev));
ev.events = EPOLLIN | EPOLLOUT | EPOLLERR;
ev.data.ptr = conn;
return epoll_ctl(ep.pollfd, EPOLL_CTL_MOD, conn->fd, &ev);
}
int poll_without_writes(ipc_connection_t *conn)
{
struct epoll_event ev;
bzero(&ev, sizeof(ev));
ev.events = EPOLLIN | EPOLLERR;
ev.data.ptr = conn;
return epoll_ctl(ep.pollfd, EPOLL_CTL_MOD, conn->fd, &ev);
}
int poll_fd_without_writes(int fd)
{
struct epoll_event ev;
bzero(&ev, sizeof(ev));
ev.events = EPOLLIN | EPOLLERR;
ev.data.ptr = NULL;
return epoll_ctl(ep.pollfd, EPOLL_CTL_ADD, fd, &ev);
}
int poll_wait(int timeout_millis, int (*callback)(poll_event_t *, int, void *), void *data)
{
#define NEVENTS (20)
struct epoll_event evs[NEVENTS];
poll_event_t pevs[NEVENTS];
int ret;
ret = epoll_wait(ep.pollfd, evs, NEVENTS, timeout_millis);
if (ret < 0)
return ret;
for (int i = 0; i < ret; i++) {
bzero(&pevs[i], sizeof(pevs[i]));
pevs[i].data = evs[i].data.ptr;
pevs[i].is_error = (evs[i].events & (EPOLLERR | EPOLLHUP | EPOLLRDHUP));
pevs[i].is_read = (evs[i].events & (EPOLLIN | EPOLLPRI));
pevs[i].is_write = (evs[i].events & (EPOLLOUT));
}
ret = callback(pevs, ret, data);
return ret;
}
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
#include <strings.h>
#include <errno.h>
#include <socket.h>
#include "poll.h"
struct kq_priv {
int kqd;
};
struct kq_priv kp = {
.kqd = -1
};
int poll_addconn(ipc_connection_t *conn)
{
struct kevent ev;
EV_SET(&ev, conn->fd, EVFILT_READ, EV_ADD, 0, 0, conn);
return kevent(kp.kqd, &ev, 1, NULL, 0, NULL);
}
int poll_init(void)
{
if (kp.kqd == -1)
kp.kqd = kqueue();
return 0;
}
void poll_delete(int fd)
{
struct kevent ev;
EV_SET(&ev, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
kevent(kp.kqd, &ev, 1, NULL, 0, NULL);
EV_SET(&ev, fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
kevent(kp.kqd, &ev, 1, NULL, 0, NULL);
}
int poll_with_writes(ipc_connection_t *conn)
{
struct kevent ev;
EV_SET(&ev, conn->fd, EVFILT_WRITE, EV_ADD, 0, 0, conn);
return kevent(kp.kqd, &ev, 1, NULL, 0, NULL);
}
int poll_without_writes(ipc_connection_t *conn)
{
struct kevent ev;
int ret;
EV_SET(&ev, conn->fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
ret = kevent(kp.kqd, &ev, 1, NULL, 0, NULL);
if (ret != 0 && errno != ENOENT)
return ret;
return 0;
}
int poll_fd_without_writes(int fd)
{
struct kevent ev;
int ret;
EV_SET(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, NULL);
ret = kevent(kp.kqd, &ev, 1, NULL, 0, NULL);
if (ret != 0)
return ret;
EV_SET(&ev, fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
ret = kevent(kp.kqd, &ev, 1, NULL, 0, NULL);
if (ret != 0 && errno != ENOENT)
return ret;
return 0;
}
int poll_wait(int timeout_millis, int (*callback)(poll_event_t *, int, void *), void *data)
{
#define NEVENTS (20)
struct timespec timeout = {
.tv_sec = timeout_millis / 1000,
.tv_nsec = timeout_millis % 1000 * 1000000
};
struct kevent evs[NEVENTS];
poll_event_t pevs[NEVENTS];
int ret;
ret = kevent(kp.kqd, NULL, 0, evs, NEVENTS, &timeout);
if (ret == -1)
return ret;
for (int i = 0; i < ret; i++) {
bzero(&pevs[i], sizeof(pevs[i]));
pevs[i].data = evs[i].udata;
pevs[i].is_error = (evs[i].flags & (EV_EOF | EV_ERROR));
pevs[i].is_read = (evs[i].filter == EVFILT_READ);
pevs[i].is_write = (evs[i].filter == EVFILT_WRITE);
}
ret = callback(pevs, ret, data);
return ret;
}
#ifndef SERVER_POLL_H
#define SERVER_POLL_H
typedef struct {
int is_read;
int is_write;
int is_error;
void *data;
} poll_event_t;
extern int poll_addconn(ipc_connection_t *conn);
extern int poll_init(void);
extern void poll_delete(int fd);
extern int poll_with_writes(ipc_connection_t *conn);
extern int poll_without_writes(ipc_connection_t *conn);
extern int poll_fd_without_writes(int fd);
extern int poll_wait(int timeout_millis, int (*callback)(poll_event_t *events, int nmemb, void *data), void *data);
#endif /* SERVER_POLL_H */
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/epoll.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
......@@ -26,13 +25,13 @@
#include "replay.h"
#include "actions.h"
#include "gags.h"
#include "poll.h"
#include <folders.h>
#include <perms.h>
#include <special.h>
struct list_head connection_list;
static int pollfd = -1;
int mainsock_die = 0;
int open_mainsock(uint16_t port)
......@@ -83,11 +82,7 @@ ipc_connection_t * add_connection(int fd)
list_add_tail(&(new->list), &connection_list);
/* register interest in read events */
struct epoll_event ev;
bzero(&ev, sizeof(ev));
ev.events = EPOLLIN | EPOLLERR;
ev.data.ptr = new;
if (epoll_ctl( pollfd, EPOLL_CTL_ADD, new->fd, &ev)) {
if (poll_addconn(new)) {
fprintf(stderr, "Error adding new conn to poll: %s\n", strerror(errno));
}
......@@ -114,11 +109,8 @@ void accept_connection(int mainsock)
void drop_connection(ipc_connection_t * conn)
{
struct epoll_event ev;
printf("Drop connection fd=%d\n", conn->fd);
bzero(&ev, sizeof(ev));
epoll_ctl(pollfd, EPOLL_CTL_DEL, conn->fd, &ev);
poll_delete(conn->fd);
list_del_init(&conn->list);
if (conn->fd != -1) close(conn->fd);
conn->fd = -1;
......@@ -141,79 +133,78 @@ void drop_connection(ipc_connection_t * conn)
ipcmsg_destroy(whoinfo);
}
void watch_mainsock(int mainsock)
static int mainsock_event_cb(poll_event_t *events, int nmemb, void *data)
{
struct epoll_event ev;
/* add the mainsock to the epoll list
* it will only generate read events */
bzero(&ev, sizeof(ev));
ev.events = EPOLLIN | EPOLLERR;
ev.data.ptr = NULL;
if (epoll_ctl(pollfd, EPOLL_CTL_ADD, mainsock, &ev)) {
fprintf(stderr, "Error adding mainsock: %s\n", strerror(errno));
return;
}
int *mainsock = data;
struct epoll_event event[20];
int ret;
struct timeval last;
gettimeofday(&last, NULL);
for (int i = 0; i < nmemb; i++) {
poll_event_t *ev = &events[i];
bodge:
while ((ret = epoll_wait(pollfd, event, 20, 1000)) >= 0) {
for (int i=0; i<ret; i++) {
/* even on mainsock */
if (event[i].data.ptr == NULL) {
if (event[i].events & (EPOLLERR | EPOLLHUP)) {
return;
} else
if (event[i].events & EPOLLIN) {
accept_connection(mainsock);
} else {
fprintf(stderr, "unexpected event on mainsock.\n");
}
/* event on mainsock */
if (ev->data == NULL) {
if (ev->is_error) {
return 1;
} else
if (ev->is_read) {
accept_connection(*mainsock);
} else {
ipc_connection_t *c = event[i].data.ptr;
if (event[i].events & (EPOLLERR | EPOLLHUP | EPOLLRDHUP)) {
ipcconn_bad(c);
} else
if (event[i].events & (EPOLLIN | EPOLLPRI)) {
ipc_message_t *msg = read_socket(c, 1);
while (msg != NULL) {
process_msg(c, msg);
msg=read_socket(c,0);
}
} else
if (event[i].events & EPOLLOUT) {
write_socket(c);
} else {
fprintf(stderr, "unexpected event on fd=%d.\n", c->fd);
fprintf(stderr, "unexpected event on mainsock.\n");
}
} else {
ipc_connection_t *c = ev->data;
if (ev->is_error) {
ipcconn_bad(c);
} else
if (ev->is_read) {
ipc_message_t *msg = read_socket(c, 1);
while (msg != NULL) {
process_msg(c, msg);
msg=read_socket(c,0);
}
} else
if (ev->is_write) {
write_socket(c);
} else {
fprintf(stderr, "unexpected event on fd=%d.\n", c->fd);
}
}
/* check if we had to drop any connections and clean them away */
struct list_head *pos, *q;
list_for_each_safe(pos, q, &connection_list) {
ipc_connection_t * c = list_entry(pos, ipc_connection_t, list);
/* connections that went bad */
if (c->fd != -1 && c->state == IPCSTATE_ERROR) {
drop_connection(c);
}
/* connections with a soft close */
if (c->state == IPCSTATE_PURGE && list_empty(&(c->outq))) {
drop_connection(c);
}
/* check if we had to drop any connections and clean them away */
struct list_head *pos, *q;
list_for_each_safe(pos, q, &connection_list) {
ipc_connection_t * c = list_entry(pos, ipc_connection_t, list);
/* connections that went bad */
if (c->fd != -1 && c->state == IPCSTATE_ERROR) {
drop_connection(c);
}
/* connections with a soft close */
if (c->state == IPCSTATE_PURGE && list_empty(&(c->outq))) {
drop_connection(c);
}
}
/* end of events handling, do periodic stuff here */
}
return 0;
}
/* epoll got interupted, not actually an error, go around again */
if (ret == -1 && errno == EINTR) goto bodge;
void watch_mainsock(int mainsock)
{
int ret;
struct timeval last;
gettimeofday(&last, NULL);
/* epoll gave an error */
fprintf(stderr, "epoll error: %s\n", strerror(errno));
if (poll_fd_without_writes(mainsock)) {
fprintf(stderr, "Error adding mainsock: %s\n", strerror(errno));
return;
}
do {
while ((ret = poll_wait(1000, mainsock_event_cb, &mainsock)) >= 0) {
/* end of events handling, do periodic stuff here */
}
/* poll got interrupted, not actually an error, go around again */
} while (ret == -1 && errno == EINTR);
fprintf(stderr, "poll error: %s\n", strerror(errno));
}
void write_socket(ipc_connection_t * conn)
......@@ -223,13 +214,9 @@ void write_socket(ipc_connection_t * conn)
if (list_empty(&conn->outq)) {
/* tx queue is empty, stop write events */
struct epoll_event ev;
bzero(&ev, sizeof(ev));
ev.events = EPOLLIN | EPOLLERR;
ev.data.ptr = conn;
if (epoll_ctl(pollfd, EPOLL_CTL_MOD, conn->fd, &ev)) {
fprintf(stderr, "Error updating poll fd=%d: %s\n", conn->fd, strerror(errno));
}
if (poll_without_writes(conn))
fprintf(stderr, "Error updating poll fd=%d: %s\n",
conn->fd, strerror(errno));
return;
}
struct list_head * pos = conn->outq.next;
......@@ -624,13 +611,8 @@ void msg_attach(ipc_message_t *msg, ipc_connection_t *conn)
int wasempty = msg_queue(msg, conn);
/* nothing was queueed, switch on write notifications */
if (wasempty) {
struct epoll_event ev;
bzero(&ev, sizeof(ev));
ev.events = EPOLLIN | EPOLLOUT | EPOLLERR;
ev.data.ptr = conn;
epoll_ctl(pollfd, EPOLL_CTL_MOD, conn->fd, &ev);
}
if (wasempty)
poll_with_writes(conn);
}
/* test if the user is gagged and apply the filter
......@@ -750,9 +732,7 @@ void migrate_old_folders(void)
void init_server()
{
INIT_LIST_HEAD(&connection_list);
if (pollfd == -1) {
pollfd = epoll_create(30);
}
poll_init();
}
ipc_message_t * msg_wholist(void)
......
......@@ -2,8 +2,10 @@
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
......
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
......
......@@ -84,7 +84,7 @@ void open_command_socket()
}
sa.sun_family = AF_UNIX;
snprintf(sa.sun_path, UNIX_PATH_MAX, MSGDIR"/mwpoll.%d", getpid());
if (bind(command_sock, &sa, sizeof(sa))) {
if (bind(command_sock, (struct sockaddr *)&sa, sizeof(sa))) {
fprintf(stderr, "Error binding %s: %s\n", sa.sun_path, strerror(errno));
close(command_sock);
command_sock = -1;
......