summaryrefslogtreecommitdiff
path: root/source3/libsmb
diff options
context:
space:
mode:
authorVolker Lendecke <vl@samba.org>2011-01-04 18:22:38 +0100
committerVolker Lendecke <vl@samba.org>2011-01-07 13:28:04 +0100
commit77a9b0e265ae6e65bd0a0b73f65b3a8953b3f59d (patch)
treee7468c30c5d997f026a0601ffb25056f6f4797ba /source3/libsmb
parentcbd5e4e16b6499a945bd5969bdd2da87bdf21255 (diff)
downloadsamba-77a9b0e265ae6e65bd0a0b73f65b3a8953b3f59d.tar.gz
samba-77a9b0e265ae6e65bd0a0b73f65b3a8953b3f59d.tar.bz2
samba-77a9b0e265ae6e65bd0a0b73f65b3a8953b3f59d.zip
s3: Add nb_trans_send/recv
This does an async port 137 transaction: It connects to /tmp/.nmbd/unexpected, sends out the query and then waits for a reply on both the socket as well as data from /tmp/.nmbd/unexpected. Every packet is passed through a validator. If that returns true, the packet received is finally accepted.
Diffstat (limited to 'source3/libsmb')
-rw-r--r--source3/libsmb/namequery.c197
1 files changed, 197 insertions, 0 deletions
diff --git a/source3/libsmb/namequery.c b/source3/libsmb/namequery.c
index 1356db88b5..8eb4cea508 100644
--- a/source3/libsmb/namequery.c
+++ b/source3/libsmb/namequery.c
@@ -462,6 +462,203 @@ static NTSTATUS sock_packet_read_recv(struct tevent_req *req,
return NT_STATUS_OK;
}
+struct nb_trans_state {
+ struct tevent_context *ev;
+ int sock;
+ struct nb_packet_reader *reader;
+
+ const struct sockaddr_storage *dst_addr;
+ uint8_t *buf;
+ size_t buflen;
+ enum packet_type type;
+ int trn_id;
+
+ bool (*validator)(struct packet_struct *p,
+ void *private_data);
+ void *private_data;
+
+ struct packet_struct *packet;
+};
+
+static int nb_trans_state_destructor(struct nb_trans_state *s);
+static void nb_trans_got_reader(struct tevent_req *subreq);
+static void nb_trans_done(struct tevent_req *subreq);
+static void nb_trans_sent(struct tevent_req *subreq);
+static void nb_trans_send_next(struct tevent_req *subreq);
+
+static struct tevent_req *nb_trans_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const struct sockaddr_storage *my_addr,
+ const struct sockaddr_storage *dst_addr,
+ bool bcast,
+ uint8_t *buf, size_t buflen,
+ enum packet_type type, int trn_id,
+ bool (*validator)(struct packet_struct *p,
+ void *private_data),
+ void *private_data)
+{
+ struct tevent_req *req, *subreq;
+ struct nb_trans_state *state;
+
+ req = tevent_req_create(mem_ctx, &state, struct nb_trans_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ talloc_set_destructor(state, nb_trans_state_destructor);
+ state->ev = ev;
+ state->dst_addr = dst_addr;
+ state->buf = buf;
+ state->buflen = buflen;
+ state->type = type;
+ state->trn_id = trn_id;
+ state->validator = validator;
+ state->private_data = private_data;
+
+ state->sock = open_socket_in(SOCK_DGRAM, 0, 3, my_addr, True);
+ if (state->sock == -1) {
+ tevent_req_nterror(req, map_nt_error_from_unix(errno));
+ DEBUG(10, ("open_socket_in failed: %s\n", strerror(errno)));
+ return tevent_req_post(req, ev);
+ }
+
+ if (bcast) {
+ set_socket_options(state->sock,"SO_BROADCAST");
+ }
+
+ subreq = nb_packet_reader_send(state, ev, type, state->trn_id, NULL);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, nb_trans_got_reader, req);
+ return req;
+}
+
+static int nb_trans_state_destructor(struct nb_trans_state *s)
+{
+ if (s->sock != -1) {
+ close(s->sock);
+ s->sock = -1;
+ }
+ if (s->packet != NULL) {
+ free_packet(s->packet);
+ s->packet = NULL;
+ }
+ return 0;
+}
+
+static void nb_trans_got_reader(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct nb_trans_state *state = tevent_req_data(
+ req, struct nb_trans_state);
+ NTSTATUS status;
+
+ status = nb_packet_reader_recv(subreq, state, &state->reader);
+ TALLOC_FREE(subreq);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("nmbd not around\n"));
+ state->reader = NULL;
+ }
+
+ subreq = sock_packet_read_send(
+ state, state->ev, state->sock,
+ state->reader, state->type, state->trn_id,
+ state->validator, state->private_data);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, nb_trans_done, req);
+
+#if !DEBUG_UNEXPECTED
+ subreq = sendto_send(state, state->ev, state->sock,
+ state->buf, state->buflen, 0, state->dst_addr);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, nb_trans_sent, req);
+#endif
+}
+
+static void nb_trans_sent(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct nb_trans_state *state = tevent_req_data(
+ req, struct nb_trans_state);
+ ssize_t sent;
+ int err;
+
+ sent = sendto_recv(subreq, &err);
+ TALLOC_FREE(subreq);
+ if (sent == -1) {
+ DEBUG(10, ("sendto failed: %s\n", strerror(err)));
+ tevent_req_nterror(req, map_nt_error_from_unix(err));
+ return;
+ }
+ subreq = tevent_wakeup_send(state, state->ev,
+ timeval_current_ofs(1, 0));
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, nb_trans_send_next, req);
+}
+
+static void nb_trans_send_next(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct nb_trans_state *state = tevent_req_data(
+ req, struct nb_trans_state);
+ bool ret;
+
+ ret = tevent_wakeup_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (!ret) {
+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+ return;
+ }
+ subreq = sendto_send(state, state->ev, state->sock,
+ state->buf, state->buflen, 0, state->dst_addr);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, nb_trans_sent, req);
+}
+
+static void nb_trans_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct nb_trans_state *state = tevent_req_data(
+ req, struct nb_trans_state);
+ NTSTATUS status;
+
+ status = sock_packet_read_recv(subreq, &state->packet);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ tevent_req_done(req);
+}
+
+static NTSTATUS nb_trans_recv(struct tevent_req *req,
+ struct packet_struct **ppacket)
+{
+ struct nb_trans_state *state = tevent_req_data(
+ req, struct nb_trans_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().