summaryrefslogtreecommitdiff
path: root/source3/libsmb
diff options
context:
space:
mode:
authorVolker Lendecke <vl@samba.org>2011-01-04 18:17:33 +0100
committerVolker Lendecke <vl@samba.org>2011-01-07 13:28:04 +0100
commitcbd5e4e16b6499a945bd5969bdd2da87bdf21255 (patch)
tree0b7d60b77fec554abcbe810e33a4c68500be3be9 /source3/libsmb
parentd801d4da2d9f6146b4dfe5e2a0be00e8d2d3ae1b (diff)
downloadsamba-cbd5e4e16b6499a945bd5969bdd2da87bdf21255.tar.gz
samba-cbd5e4e16b6499a945bd5969bdd2da87bdf21255.tar.bz2
samba-cbd5e4e16b6499a945bd5969bdd2da87bdf21255.zip
s3: Add sock_packet_read
Read packets from both a socket and from /tmp/.nmbd/unexpected simultaneously
Diffstat (limited to 'source3/libsmb')
-rw-r--r--source3/libsmb/namequery.c215
1 files changed, 215 insertions, 0 deletions
diff --git a/source3/libsmb/namequery.c b/source3/libsmb/namequery.c
index c7b37b7db2..1356db88b5 100644
--- a/source3/libsmb/namequery.c
+++ b/source3/libsmb/namequery.c
@@ -23,6 +23,7 @@
#include "libads/dns.h"
#include "../libcli/netlogon.h"
#include "librpc/gen_ndr/messaging.h"
+#include "lib/async_req/async_sock.h"
/* nmbd.c sets this to True. */
bool global_in_nmbd = False;
@@ -247,6 +248,220 @@ static struct node_status *parse_node_status(TALLOC_CTX *mem_ctx, char *p,
return ret;
}
+struct sock_packet_read_state {
+ struct tevent_context *ev;
+ enum packet_type type;
+ int trn_id;
+
+ struct nb_packet_reader *reader;
+ struct tevent_req *reader_req;
+
+ int sock;
+ struct tevent_req *socket_req;
+ uint8_t buf[1024];
+ struct sockaddr_storage addr;
+ socklen_t addr_len;
+
+ bool (*validator)(struct packet_struct *p,
+ void *private_data);
+ void *private_data;
+
+ struct packet_struct *packet;
+};
+
+static int sock_packet_read_state_destructor(struct sock_packet_read_state *s);
+static void sock_packet_read_got_packet(struct tevent_req *subreq);
+static void sock_packet_read_got_socket(struct tevent_req *subreq);
+
+static struct tevent_req *sock_packet_read_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ int sock, /* dgram socket */
+ struct nb_packet_reader *reader,
+ enum packet_type type,
+ int trn_id,
+ bool (*validator)(struct packet_struct *p, void *private_data),
+ void *private_data)
+{
+ struct tevent_req *req;
+ struct sock_packet_read_state *state;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct sock_packet_read_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ talloc_set_destructor(state, sock_packet_read_state_destructor);
+ state->ev = ev;
+ state->reader = reader;
+ state->sock = sock;
+ state->type = type;
+ state->trn_id = trn_id;
+ state->validator = validator;
+ state->private_data = private_data;
+
+ if (reader != NULL) {
+ state->reader_req = nb_packet_read_send(state, ev, reader);
+ if (tevent_req_nomem(state->reader_req, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(
+ state->reader_req, sock_packet_read_got_packet, req);
+ }
+
+ state->addr_len = sizeof(state->addr);
+ state->socket_req = recvfrom_send(state, ev, sock,
+ state->buf, sizeof(state->buf), 0,
+ &state->addr, &state->addr_len);
+ if (tevent_req_nomem(state->socket_req, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(state->socket_req, sock_packet_read_got_socket,
+ req);
+
+ return req;
+}
+
+static int sock_packet_read_state_destructor(struct sock_packet_read_state *s)
+{
+ if (s->packet != NULL) {
+ free_packet(s->packet);
+ s->packet = NULL;
+ }
+ return 0;
+}
+
+static void sock_packet_read_got_packet(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct sock_packet_read_state *state = tevent_req_data(
+ req, struct sock_packet_read_state);
+ NTSTATUS status;
+
+ status = nb_packet_read_recv(subreq, &state->packet);
+
+ TALLOC_FREE(state->reader_req);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ if (state->socket_req != NULL) {
+ /*
+ * Still waiting for socket
+ */
+ return;
+ }
+ /*
+ * Both socket and packet reader failed
+ */
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ if ((state->validator != NULL) &&
+ !state->validator(state->packet, state->private_data)) {
+ DEBUG(10, ("validator failed\n"));
+
+ free_packet(state->packet);
+ state->packet = NULL;
+
+ state->reader_req = nb_packet_read_send(state, state->ev,
+ state->reader);
+ if (tevent_req_nomem(state->reader_req, req)) {
+ return;
+ }
+ tevent_req_set_callback(
+ state->reader_req, sock_packet_read_got_packet, req);
+ return;
+ }
+
+ TALLOC_FREE(state->socket_req);
+ tevent_req_done(req);
+}
+
+static void sock_packet_read_got_socket(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct sock_packet_read_state *state = tevent_req_data(
+ req, struct sock_packet_read_state);
+ struct sockaddr_in *in_addr;
+ ssize_t received;
+ int err;
+
+ received = recvfrom_recv(subreq, &err);
+
+ TALLOC_FREE(state->socket_req);
+
+ if (received == -1) {
+ if (state->reader_req != NULL) {
+ /*
+ * Still waiting for reader
+ */
+ return;
+ }
+ /*
+ * Both socket and reader failed
+ */
+ tevent_req_nterror(req, map_nt_error_from_unix(err));
+ return;
+ }
+ if (state->addr.ss_family != AF_INET) {
+ goto retry;
+ }
+ in_addr = (struct sockaddr_in *)(void *)&state->addr;
+
+ state->packet = parse_packet((char *)state->buf, received, state->type,
+ in_addr->sin_addr, in_addr->sin_port);
+ if (state->packet == NULL) {
+ DEBUG(10, ("parse_packet failed\n"));
+ goto retry;
+ }
+ if ((state->trn_id != -1) &&
+ (state->trn_id != packet_trn_id(state->packet))) {
+ DEBUG(10, ("Expected transaction id %d, got %d\n",
+ state->trn_id, packet_trn_id(state->packet)));
+ goto retry;
+ }
+
+ if ((state->validator != NULL) &&
+ !state->validator(state->packet, state->private_data)) {
+ DEBUG(10, ("validator failed\n"));
+ goto retry;
+ }
+
+ tevent_req_done(req);
+ return;
+
+retry:
+ if (state->packet != NULL) {
+ free_packet(state->packet);
+ state->packet = NULL;
+ }
+ state->socket_req = recvfrom_send(state, state->ev, state->sock,
+ state->buf, sizeof(state->buf), 0,
+ &state->addr, &state->addr_len);
+ if (tevent_req_nomem(state->socket_req, req)) {
+ return;
+ }
+ tevent_req_set_callback(state->socket_req, sock_packet_read_got_socket,
+ req);
+}
+
+static NTSTATUS sock_packet_read_recv(struct tevent_req *req,
+ struct packet_struct **ppacket)
+{
+ struct sock_packet_read_state *state = tevent_req_data(
+ req, struct sock_packet_read_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+ *ppacket = state->packet;
+ state->packet = NULL;
+ return NT_STATUS_OK;
+}
+
/****************************************************************************
Try and send a request to nmbd to send a packet_struct packet first.
If this fails, use send_packet().