diff options
author | Andrew Tridgell <tridge@samba.org> | 2004-10-17 10:04:49 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 12:59:57 -0500 |
commit | 6591a226144d371a6b68fc5e7201a90a77dc9153 (patch) | |
tree | 072ee4cbf33f0469f23e424517d17b79c750852d | |
parent | 844de2b65c931120a2408365c00fa80cb65959fc (diff) | |
download | samba-6591a226144d371a6b68fc5e7201a90a77dc9153.tar.gz samba-6591a226144d371a6b68fc5e7201a90a77dc9153.tar.bz2 samba-6591a226144d371a6b68fc5e7201a90a77dc9153.zip |
r3016: - converted the events code to talloc
- added the new messaging system, based on unix domain sockets. It
gets over 10k messages/second on my laptop without any socket
cacheing, which is better than I expected.
- added a LOCAL-MESSAGING torture test
(This used to be commit 3af06478da7ab34a272226d8d9ac87e0a4940cfb)
-rw-r--r-- | source4/configure.in | 1 | ||||
-rw-r--r-- | source4/lib/events.c | 46 | ||||
-rw-r--r-- | source4/lib/messaging/config.m4 | 1 | ||||
-rw-r--r-- | source4/lib/messaging/config.mk | 8 | ||||
-rw-r--r-- | source4/lib/messaging/messaging.c | 445 | ||||
-rw-r--r-- | source4/lib/socket/socket_unix.c | 10 | ||||
-rw-r--r-- | source4/libcli/raw/clitransport.c | 2 | ||||
-rw-r--r-- | source4/librpc/rpc/dcerpc_tcp.c | 2 | ||||
-rw-r--r-- | source4/smbd/config.mk | 2 | ||||
-rw-r--r-- | source4/smbd/process_thread.c | 3 | ||||
-rw-r--r-- | source4/smbd/service.c | 5 | ||||
-rw-r--r-- | source4/smbd/service.h | 2 | ||||
-rw-r--r-- | source4/torture/config.mk | 6 | ||||
-rw-r--r-- | source4/torture/local/messaging.c | 92 | ||||
-rw-r--r-- | source4/torture/torture.c | 1 |
15 files changed, 583 insertions, 43 deletions
diff --git a/source4/configure.in b/source4/configure.in index 6bd8f9323c..703017ffc8 100644 --- a/source4/configure.in +++ b/source4/configure.in @@ -15,6 +15,7 @@ SMB_INCLUDE_M4(lib/popt/config.m4) SMB_INCLUDE_M4(lib/iconv.m4) SMB_INCLUDE_M4(lib/basic.m4) SMB_INCLUDE_M4(lib/socket/config.m4) +SMB_INCLUDE_M4(lib/messaging/config.m4) SMB_INCLUDE_M4(lib/tdb/config.m4) SMB_INCLUDE_M4(lib/ldb/config.m4) SMB_INCLUDE_M4(lib/cmdline/config.m4) diff --git a/source4/lib/events.c b/source4/lib/events.c index 4ae7cad8af..0e98b42503 100644 --- a/source4/lib/events.c +++ b/source4/lib/events.c @@ -71,11 +71,11 @@ call, and all subsequent calls pass this event_context as the first element. Event handlers also receive this as their first argument. */ -struct event_context *event_context_init(void) +struct event_context *event_context_init(TALLOC_CTX *mem_ctx) { struct event_context *ev; - ev = malloc(sizeof(*ev)); + ev = talloc_p(mem_ctx, struct event_context); if (!ev) return NULL; /* start off with no events */ @@ -91,40 +91,12 @@ struct event_context *event_context_init(void) */ void event_context_destroy(struct event_context *ev) { - struct fd_event *fde; - struct timed_event *te; - struct loop_event *le; - ev->ref_count--; if (ev->ref_count != 0) { return; } - for (fde=ev->fd_events; fde;) { - struct fd_event *next = fde->next; - event_remove_fd(ev, fde); - if (fde->ref_count == 0) { - free(fde); - } - fde=next; - } - for (te=ev->timed_events; te;) { - struct timed_event *next = te->next; - event_remove_timed(ev, te); - if (te->ref_count == 0) { - free(te); - } - te=next; - } - for (le=ev->loop_events; le;) { - struct loop_event *next = le->next; - event_remove_loop(ev, le); - if (le->ref_count == 0) { - free(le); - } - le=next; - } - free(ev); + talloc_free(ev); } @@ -175,7 +147,7 @@ struct event_context * event_context_merge(struct event_context *ev, struct even */ struct fd_event *event_add_fd(struct event_context *ev, struct fd_event *e) { - e = memdup(e, sizeof(*e)); + e = talloc_memdup(ev, e, sizeof(*e)); if (!e) return NULL; DLIST_ADD(ev->fd_events, e); e->ref_count = 1; @@ -245,7 +217,7 @@ void event_remove_fd_all_handler(struct event_context *ev, void *handler) */ struct timed_event *event_add_timed(struct event_context *ev, struct timed_event *e) { - e = memdup(e, sizeof(*e)); + e = talloc_memdup(ev, e, sizeof(*e)); if (!e) return NULL; e->ref_count = 1; DLIST_ADD(ev->timed_events, e); @@ -274,7 +246,7 @@ BOOL event_remove_timed(struct event_context *ev, struct timed_event *e1) */ struct loop_event *event_add_loop(struct event_context *ev, struct loop_event *e) { - e = memdup(e, sizeof(*e)); + e = talloc_memdup(ev, e, sizeof(*e)); if (!e) return NULL; e->ref_count = 1; DLIST_ADD(ev->loop_events, e); @@ -330,7 +302,7 @@ int event_loop_once(struct event_context *ev) struct loop_event *next = le->next; if (le->ref_count == 0) { DLIST_REMOVE(ev->loop_events, le); - free(le); + talloc_unlink(ev, le); } else { le->ref_count++; le->handler(ev, le, t); @@ -351,7 +323,7 @@ int event_loop_once(struct event_context *ev) if (ev->maxfd == fe->fd) { ev->maxfd = EVENT_INVALID_MAXFD; } - free(fe); + talloc_unlink(ev, fe); } else { if (fe->flags & EVENT_FD_READ) { FD_SET(fe->fd, &r_fds); @@ -432,7 +404,7 @@ int event_loop_once(struct event_context *ev) struct timed_event *next = te->next; if (te->ref_count == 0) { DLIST_REMOVE(ev->timed_events, te); - free(te); + talloc_unlink(ev, te); } else if (te->next_event <= t) { te->ref_count++; te->handler(ev, te, t); diff --git a/source4/lib/messaging/config.m4 b/source4/lib/messaging/config.m4 new file mode 100644 index 0000000000..1797069ff2 --- /dev/null +++ b/source4/lib/messaging/config.m4 @@ -0,0 +1 @@ +SMB_SUBSYSTEM_MK(MESSAGING,lib/messaging/config.mk) diff --git a/source4/lib/messaging/config.mk b/source4/lib/messaging/config.mk new file mode 100644 index 0000000000..6c30894779 --- /dev/null +++ b/source4/lib/messaging/config.mk @@ -0,0 +1,8 @@ + +################################################ +# Start SUBSYSTEM MESSAGING +[SUBSYSTEM::MESSAGING] +INIT_OBJ_FILES = \ + lib/messaging/messaging.o +# End SUBSYSTEM MESSAGING +################################################ diff --git a/source4/lib/messaging/messaging.c b/source4/lib/messaging/messaging.c new file mode 100644 index 0000000000..f9caf5071c --- /dev/null +++ b/source4/lib/messaging/messaging.c @@ -0,0 +1,445 @@ +/* + Unix SMB/CIFS implementation. + + Samba internal messaging functions + + Copyright (C) Andrew Tridgell 2004 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +/* change the message version with any incompatible changes in the protocol */ +#define MESSAGING_VERSION 1 + +struct messaging_state { + servid_t server_id; + struct socket_context *sock; + char *path; + struct dispatch_fn *dispatch; + + struct { + struct event_context *ev; + struct fd_event *fde; + } event; +}; + +/* we have a linked list of dispatch handlers that this messaging + server can deal with */ +struct dispatch_fn { + struct dispatch_fn *next, *prev; + uint32_t msg_type; + void *private; + void (*fn)(void *msg_ctx, void *private, + uint32_t msg_type, servid_t server_id, DATA_BLOB *data); +}; + +/* an individual message */ +struct messaging_rec { + struct messaging_rec *next, *prev; + + struct messaging_state *msg; + struct socket_context *sock; + struct fd_event *fde; + const char *path; + + struct { + uint32_t version; + uint32_t msg_type; + servid_t from; + servid_t to; + uint32_t length; + } header; + + DATA_BLOB data; + + uint32_t ndone; +}; + +/* + A useful function for testing the message system. +*/ +static void ping_message(void *msg_ctx, void *private, + uint32_t msg_type, servid_t src, DATA_BLOB *data) +{ + DEBUG(1,("INFO: Received PING message from server %u [%.*s]\n", + (uint_t)src, data->length, data->data?(const char *)data->data:"")); + messaging_send(msg_ctx, src, MSG_PONG, data); +} + +/* + return the path to a messaging socket +*/ +static char *messaging_path(TALLOC_CTX *mem_ctx, servid_t server_id) +{ + char *name = talloc_asprintf(mem_ctx, "messaging/msg.%u", (unsigned)server_id); + char *ret; + ret = lock_path(mem_ctx, name); + talloc_free(name); + return ret; +} + +/* + dispatch a fully received message +*/ +static void messaging_dispatch(struct messaging_state *msg, struct messaging_rec *rec) +{ + struct dispatch_fn *d; + for (d=msg->dispatch;d;d=d->next) { + if (d->msg_type == rec->header.msg_type) { + d->fn(msg, d->private, d->msg_type, rec->header.from, &rec->data); + } + } + + /* we don't free the record itself here as there may + be more messages from this client */ + data_blob_free(&rec->data); + rec->header.length = 0; + rec->ndone = 0; +} + + +/* + handle IO for a single message +*/ +static void messaging_recv_handler(struct event_context *ev, struct fd_event *fde, + time_t t, uint16_t flags) +{ + struct messaging_rec *rec = fde->private; + struct messaging_state *msg = rec->msg; + NTSTATUS status; + + if (rec->ndone < sizeof(rec->header)) { + /* receive the header */ + DATA_BLOB blob; + status = socket_recv(rec->sock, rec, + &blob, sizeof(rec->header) - rec->ndone, 0); + if (NT_STATUS_IS_ERR(status)) { + talloc_free(rec); + return; + } + + if (blob.length == 0) { + return; + } + + memcpy(rec->ndone + (char *)&rec->header, blob.data, blob.length); + rec->ndone += blob.length; + data_blob_free(&blob); + + if (rec->ndone == sizeof(rec->header)) { + if (rec->header.version != MESSAGING_VERSION) { + DEBUG(0,("meessage with wrong version %u\n", + rec->header.version)); + talloc_free(rec); + } + rec->data = data_blob_talloc(rec, NULL, rec->header.length); + if (rec->data.length != rec->header.length) { + DEBUG(0,("Unable to allocate message of size %u\n", + rec->header.length)); + talloc_free(rec); + } + } + } + + if (rec->ndone >= sizeof(rec->header) && + rec->ndone < sizeof(rec->header) + rec->header.length) { + /* receive the body, if any */ + DATA_BLOB blob; + status = socket_recv(rec->sock, rec, + &blob, sizeof(rec->header) + rec->header.length - rec->ndone, 0); + if (NT_STATUS_IS_ERR(status)) { + talloc_free(rec); + return; + } + + if (blob.length == 0) { + return; + } + + memcpy(rec->data.data + (rec->ndone - sizeof(rec->header)), + blob.data, blob.length); + + rec->ndone += blob.length; + } + + if (rec->ndone == sizeof(rec->header) + rec->header.length) { + /* we've got the whole message */ + messaging_dispatch(msg, rec); + } +} + +/* + destroy a messaging record +*/ +static int rec_destructor(void *ptr) +{ + struct messaging_rec *rec = ptr; + struct messaging_state *msg = rec->msg; + event_remove_fd(msg->event.ev, rec->fde); + return 0; +} + +/* + handle a new incoming connection +*/ +static void messaging_listen_handler(struct event_context *ev, struct fd_event *fde, + time_t t, uint16_t flags) +{ + struct messaging_state *msg = fde->private; + struct messaging_rec *rec; + NTSTATUS status; + struct fd_event fde2; + + rec = talloc_p(msg, struct messaging_rec); + if (rec == NULL) { + smb_panic("Unable to allocate messaging_rec"); + } + + status = socket_accept(msg->sock, &rec->sock, 0); + if (!NT_STATUS_IS_OK(status)) { + smb_panic("Unable to accept messaging_rec"); + } + talloc_steal(rec, rec->sock); + + rec->msg = msg; + rec->ndone = 0; + rec->header.length = 0; + rec->path = msg->path; + + fde2.private = rec; + fde2.fd = socket_get_fd(rec->sock); + fde2.flags = EVENT_FD_READ; + fde2.handler = messaging_recv_handler; + + rec->fde = event_add_fd(msg->event.ev, &fde2); + + talloc_set_destructor(rec, rec_destructor); +} + +/* + Register a dispatch function for a particular message type. +*/ +void messaging_register(void *ctx, void *private, + uint32_t msg_type, + void (*fn)(void *, void *, uint32_t, servid_t, DATA_BLOB *)) +{ + struct messaging_state *msg = ctx; + struct dispatch_fn *d; + + d = talloc_p(msg, struct dispatch_fn); + d->msg_type = msg_type; + d->private = private; + d->fn = fn; + DLIST_ADD(msg->dispatch, d); +} + +/* + De-register the function for a particular message type. +*/ +void messaging_deregister(void *ctx, uint32_t msg_type) +{ + struct messaging_state *msg = ctx; + struct dispatch_fn *d, *next; + + for (d = msg->dispatch; d; d = next) { + next = d->next; + if (d->msg_type == msg_type) { + DLIST_REMOVE(msg->dispatch, d); + talloc_free(d); + } + } +} + + + +/* + handle IO for sending a message +*/ +static void messaging_send_handler(struct event_context *ev, struct fd_event *fde, + time_t t, uint16_t flags) +{ + struct messaging_rec *rec = fde->private; + NTSTATUS status; + + if (rec->ndone < sizeof(rec->header)) { + /* send the header */ + size_t nsent; + DATA_BLOB blob; + + blob.data = rec->ndone + (char *)&rec->header; + blob.length = sizeof(rec->header) - rec->ndone; + + status = socket_send(rec->sock, rec, &blob, &nsent, 0); + if (NT_STATUS_IS_ERR(status)) { + talloc_free(rec); + return; + } + + if (nsent == 0) { + return; + } + + rec->ndone += nsent; + } + + if (rec->ndone >= sizeof(rec->header) && + rec->ndone < sizeof(rec->header) + rec->header.length) { + /* send the body, if any */ + DATA_BLOB blob; + size_t nsent; + + blob.data = rec->data.data + (rec->ndone - sizeof(rec->header)); + blob.length = rec->header.length - (rec->ndone - sizeof(rec->header)); + + status = socket_send(rec->sock, rec, &blob, &nsent, 0); + if (NT_STATUS_IS_ERR(status)) { + talloc_free(rec); + return; + } + + rec->ndone += nsent; + } + + if (rec->ndone == sizeof(rec->header) + rec->header.length) { + /* we've done the whole message */ + talloc_free(rec); + } +} + + +/* + Send a message to a particular server +*/ +NTSTATUS messaging_send(void *msg_ctx, servid_t server, uint32_t msg_type, DATA_BLOB *data) +{ + struct messaging_state *msg = msg_ctx; + struct messaging_rec *rec; + NTSTATUS status; + struct fd_event fde; + + rec = talloc_p(msg, struct messaging_rec); + if (rec == NULL) { + return NT_STATUS_NO_MEMORY; + } + + rec->msg = msg; + rec->header.version = MESSAGING_VERSION; + rec->header.msg_type = msg_type; + rec->header.from = msg->server_id; + rec->header.to = server; + rec->header.length = data?data->length:0; + if (rec->header.length != 0) { + rec->data = data_blob_talloc(rec, data->data, data->length); + } else { + rec->data = data_blob(NULL, 0); + } + rec->ndone = 0; + + status = socket_create("unix", SOCKET_TYPE_STREAM, &rec->sock, 0); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(rec); + return status; + } + talloc_steal(rec, rec->sock); + + rec->path = messaging_path(rec, server); + + status = socket_connect(rec->sock, NULL, 0, rec->path, 0, 0); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(rec); + return status; + } + + fde.private = rec; + fde.fd = socket_get_fd(rec->sock); + fde.flags = EVENT_FD_WRITE; + fde.handler = messaging_send_handler; + + rec->fde = event_add_fd(msg->event.ev, &fde); + + talloc_set_destructor(rec, rec_destructor); + + return NT_STATUS_OK; +} + + +/* + destroy the messaging context +*/ +static int messaging_destructor(void *msg_ctx) +{ + struct messaging_state *msg = msg_ctx; + event_remove_fd(msg->event.ev, msg->event.fde); + return 0; +} + +/* + create the listening socket and setup the dispatcher +*/ +void *messaging_init(TALLOC_CTX *mem_ctx, servid_t server_id, struct event_context *ev) +{ + struct messaging_state *msg; + NTSTATUS status; + struct fd_event fde; + + msg = talloc_p(mem_ctx, struct messaging_state); + if (msg == NULL) { + return NULL; + } + + /* create the messaging directory if needed */ + msg->path = lock_path(msg, "messaging"); + mkdir(msg->path, 0700); + talloc_free(msg->path); + + msg->server_id = server_id; + msg->dispatch = NULL; + msg->path = messaging_path(msg, server_id); + + status = socket_create("unix", SOCKET_TYPE_STREAM, &msg->sock, 0); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(msg); + return NULL; + } + + /* by stealing here we ensure that the socket is cleaned up (and even + deleted) on exit */ + talloc_steal(msg, msg->sock); + + status = socket_listen(msg->sock, msg->path, 0, 50, 0); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("Unable to setup messaging listener for '%s'\n", msg->path)); + talloc_free(msg); + return NULL; + } + + fde.private = msg; + fde.fd = socket_get_fd(msg->sock); + fde.flags = EVENT_FD_READ; + fde.handler = messaging_listen_handler; + + msg->event.ev = ev; + msg->event.fde = event_add_fd(ev, &fde); + + talloc_set_destructor(msg, messaging_destructor); + + messaging_register(msg, NULL, MSG_PING, ping_message); + + return msg; +} + + diff --git a/source4/lib/socket/socket_unix.c b/source4/lib/socket/socket_unix.c index d87eaf49c4..7e169c47a7 100644 --- a/source4/lib/socket/socket_unix.c +++ b/source4/lib/socket/socket_unix.c @@ -29,6 +29,7 @@ static NTSTATUS unixdom_init(struct socket_context *sock) if (sock->fd == -1) { return NT_STATUS_INSUFFICIENT_RESOURCES; } + sock->private_data = NULL; return NT_STATUS_OK; } @@ -36,6 +37,11 @@ static NTSTATUS unixdom_init(struct socket_context *sock) static void unixdom_close(struct socket_context *sock) { close(sock->fd); + /* if we were listening, then don't leave the socket lying + around in the filesystem */ + if (sock->private_data) { + unlink((const char *)sock->private_data); + } } static NTSTATUS unixdom_connect(struct socket_context *sock, @@ -82,6 +88,9 @@ static NTSTATUS unixdom_listen(struct socket_context *sock, return NT_STATUS_INVALID_PARAMETER; } + /* delete if it already exists */ + unlink(my_address); + ZERO_STRUCT(my_addr); my_addr.sun_family = AF_UNIX; strncpy(my_addr.sun_path, my_address, sizeof(my_addr.sun_path)); @@ -104,6 +113,7 @@ static NTSTATUS unixdom_listen(struct socket_context *sock, } sock->state = SOCKET_STATE_SERVER_LISTEN; + sock->private_data = (void *)talloc_strdup(sock, my_address); return NT_STATUS_OK; } diff --git a/source4/libcli/raw/clitransport.c b/source4/libcli/raw/clitransport.c index f06f2c57ff..3944afb638 100644 --- a/source4/libcli/raw/clitransport.c +++ b/source4/libcli/raw/clitransport.c @@ -68,7 +68,7 @@ struct smbcli_transport *smbcli_transport_init(struct smbcli_socket *sock) ZERO_STRUCTP(transport); - transport->event.ctx = event_context_init(); + transport->event.ctx = event_context_init(transport); if (transport->event.ctx == NULL) { talloc_free(transport); return NULL; diff --git a/source4/librpc/rpc/dcerpc_tcp.c b/source4/librpc/rpc/dcerpc_tcp.c index e28e939a7a..130f20a861 100644 --- a/source4/librpc/rpc/dcerpc_tcp.c +++ b/source4/librpc/rpc/dcerpc_tcp.c @@ -360,7 +360,7 @@ NTSTATUS dcerpc_pipe_open_tcp(struct dcerpc_pipe **p, tcp->fd = fd; tcp->server_name = talloc_strdup((*p), server); - tcp->event_ctx = event_context_init(); + tcp->event_ctx = event_context_init(tcp); tcp->pending_send = NULL; tcp->recv.received = 0; tcp->recv.data = data_blob(NULL, 0); diff --git a/source4/smbd/config.mk b/source4/smbd/config.mk index 5aa04725b4..55f040f805 100644 --- a/source4/smbd/config.mk +++ b/source4/smbd/config.mk @@ -37,6 +37,8 @@ REQUIRED_SUBSYSTEMS = \ [SUBSYSTEM::SERVER_SERVICE] INIT_OBJ_FILES = \ smbd/service.o +REQUIRED_SUBSYSTEMS = \ + MESSAGING # End SUBSYSTEM SERVER ####################### diff --git a/source4/smbd/process_thread.c b/source4/smbd/process_thread.c index 85f30c9ddd..108b098b8a 100644 --- a/source4/smbd/process_thread.c +++ b/source4/smbd/process_thread.c @@ -72,7 +72,7 @@ static void thread_accept_connection(struct event_context *ev, struct fd_event * main event_context is continued. */ - ev = event_context_init(); + ev = event_context_init(server_socket); if (!ev) { DEBUG(0,("thread_accept_connection: failed to create event_context!\n")); socket_destroy(sock); @@ -87,6 +87,7 @@ static void thread_accept_connection(struct event_context *ev, struct fd_event * return; } + talloc_steal(conn, ev); talloc_steal(conn, sock); /* TODO: is this MUTEX_LOCK in the right place here? diff --git a/source4/smbd/service.c b/source4/smbd/service.c index 9a7ac73559..d4ba9c990c 100644 --- a/source4/smbd/service.c +++ b/source4/smbd/service.c @@ -48,7 +48,7 @@ struct server_context *server_service_startup(const char *model) ZERO_STRUCTP(srv_ctx); - srv_ctx->events = event_context_init(); + srv_ctx->events = event_context_init(srv_ctx); if (!srv_ctx->events) { DEBUG(0,("event_context_init() failed\n")); return NULL; @@ -247,6 +247,9 @@ struct server_connection *server_setup_connection(struct event_context *ev, return NULL; } + /* setup to receive internal messages on this connection */ + srv_conn->messaging_ctx = messaging_init(srv_conn, srv_conn->server_id, ev); + return srv_conn; } diff --git a/source4/smbd/service.h b/source4/smbd/service.h index e9ef0bff06..93f24a34f9 100644 --- a/source4/smbd/service.h +++ b/source4/smbd/service.h @@ -124,6 +124,8 @@ struct server_connection { struct server_socket *server_socket; struct server_service *service; + + void *messaging_ctx; }; #endif /* _SERVER_SERVICE_H */ diff --git a/source4/torture/config.mk b/source4/torture/config.mk index 81988c5275..9967696c24 100644 --- a/source4/torture/config.mk +++ b/source4/torture/config.mk @@ -102,9 +102,11 @@ REQUIRED_SUBSYSTEMS = \ [SUBSYSTEM::TORTURE_LOCAL] ADD_OBJ_FILES = \ torture/local/iconv.o \ - torture/local/talloc.o + torture/local/talloc.o \ + torture/local/messaging.o REQUIRED_SUBSYSTEMS = \ - LIBSMB + LIBSMB \ + MESSAGING # End SUBSYSTEM TORTURE_LOCAL ################################# diff --git a/source4/torture/local/messaging.c b/source4/torture/local/messaging.c new file mode 100644 index 0000000000..7302e3c119 --- /dev/null +++ b/source4/torture/local/messaging.c @@ -0,0 +1,92 @@ +/* + Unix SMB/CIFS implementation. + + local test for messaging code + + Copyright (C) Andrew Tridgell 2004 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +static void pong_message(void *msg_ctx, void *private, + uint32_t msg_type, servid_t src, DATA_BLOB *data) +{ + int *count = private; + (*count)++; +} + +/* + test ping speed +*/ +static BOOL test_ping_speed(TALLOC_CTX *mem_ctx) +{ + struct event_context *ev = event_context_init(mem_ctx); + void *msg_ctx1, *msg_ctx2; + int ping_count = 0; + int pong_count = 0; + BOOL ret = True; + + msg_ctx1 = messaging_init(mem_ctx, 1, ev); + msg_ctx2 = messaging_init(mem_ctx, 2, ev); + + messaging_register(msg_ctx2, &pong_count, MSG_PONG, pong_message); + + start_timer(); + + printf("Sending pings for 10 seconds\n"); + while (end_timer() < 10.0) { + DATA_BLOB data; + data.data = "testing"; + data.length = strlen(data.data); + + messaging_send(msg_ctx2, 1, MSG_PING, &data); + messaging_send(msg_ctx2, 1, MSG_PING, NULL); + ping_count += 2; + event_loop_once(ev); + event_loop_once(ev); + } + + printf("waiting for %d remaining replies\n", ping_count - pong_count); + while (end_timer() < 30 && pong_count < ping_count) { + event_loop_once(ev); + } + + if (ping_count != pong_count) { + printf("ping test failed! received %d, sent %d\n", pong_count, ping_count); + ret = False; + } + + printf("ping rate of %.0f messages/sec\n", (ping_count+pong_count)/end_timer()); + + talloc_free(msg_ctx1); + talloc_free(msg_ctx2); + + event_context_destroy(ev); + return ret; +} + +BOOL torture_local_messaging(int dummy) +{ + TALLOC_CTX *mem_ctx = talloc_init("torture_local_messaging"); + BOOL ret = True; + + ret &= test_ping_speed(mem_ctx); + + talloc_free(mem_ctx); + + return True; +} diff --git a/source4/torture/torture.c b/source4/torture/torture.c index 3ce40ffb4a..6b5d9ebd2e 100644 --- a/source4/torture/torture.c +++ b/source4/torture/torture.c @@ -3430,6 +3430,7 @@ static struct { {"LOCAL-NTLMSSP", torture_ntlmssp_self_check, 0}, {"LOCAL-ICONV", torture_local_iconv, 0}, {"LOCAL-TALLOC", torture_local_talloc, 0}, + {"LOCAL-MESSAGING", torture_local_messaging, 0}, /* ldap testers */ {"LDAP-BASIC", torture_ldap_basic, 0}, |