[PATCH 3/3] s3: Add an async smb_connect

Volker Lendecke vl at samba.org
Sun Dec 12 10:55:06 MST 2010


This connects to 445 and after 5 milliseconds also to 139. It treats a netbios
session setup failure as equivalent as a TCP connect failure. So if 139 is
faster but fails the nb session setup, the 445 still has the chance to succeed.
---
 source3/Makefile.in          |    1 +
 source3/include/proto.h      |    5 +
 source3/libsmb/smb_connect.c |  244 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 250 insertions(+), 0 deletions(-)
 create mode 100644 source3/libsmb/smb_connect.c

diff --git a/source3/Makefile.in b/source3/Makefile.in
index 2faa4a0..ba0bb32 100644
--- a/source3/Makefile.in
+++ b/source3/Makefile.in
@@ -591,6 +591,7 @@ LIBSMB_OBJ = libsmb/clientgen.o libsmb/cliconnect.o libsmb/clifile.o \
 	     libsmb/clistr.o libsmb/cliquota.o libsmb/clifsinfo.o libsmb/clidfs.o \
 	     libsmb/clioplock.o libsmb/clirap2.o \
 	     libsmb/smb_seal.o libsmb/async_smb.o \
+	     libsmb/smb_connect.o \
 	     $(LIBSAMBA_OBJ) \
 	     $(LIBNMB_OBJ) \
 	     $(LIBNBT_OBJ) \
diff --git a/source3/include/proto.h b/source3/include/proto.h
index 1fe7f46..49b0245 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -5611,6 +5611,11 @@ struct tevent_req *fncall_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
 			       void *private_data);
 int fncall_recv(struct tevent_req *req, int *perr);
 
+struct tevent_req *smb_connect_send(TALLOC_CTX *mem_ctx,
+				    struct tevent_context *ev,
+				    const struct sockaddr_storage *addr);
+NTSTATUS smb_connect_recv(struct tevent_req *req, int *sock);
+
 /* The following definitions come from rpc_server/srv_samr_nt.c */
 NTSTATUS access_check_object( struct security_descriptor *psd, struct security_token *token,
 			      enum sec_privilege needed_priv_1, enum sec_privilege needed_priv_2,
diff --git a/source3/libsmb/smb_connect.c b/source3/libsmb/smb_connect.c
new file mode 100644
index 0000000..f0d2b4b
--- /dev/null
+++ b/source3/libsmb/smb_connect.c
@@ -0,0 +1,244 @@
+/*
+   Unix SMB/CIFS implementation.
+   Connect to 445 and 139/nbsesssetup
+   Copyright (C) Volker Lendecke 2010
+
+   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 3 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "../lib/async_req/async_sock.h"
+#include "async_smb.h"
+
+struct nb_connect_state {
+	struct tevent_context *ev;
+	int sock;
+	struct nmb_name called;
+	struct nmb_name calling;
+};
+
+static int nb_connect_state_destructor(struct nb_connect_state *state);
+static void nb_connect_connected(struct tevent_req *subreq);
+static void nb_connect_done(struct tevent_req *subreq);
+
+static struct tevent_req *nb_connect_send(TALLOC_CTX *mem_ctx,
+					  struct tevent_context *ev,
+					  const struct sockaddr_storage *addr,
+					  const char *called_name,
+					  int called_type,
+					  const char *calling_name,
+					  int calling_type)
+{
+	struct tevent_req *req, *subreq;
+	struct nb_connect_state *state;
+
+	req = tevent_req_create(mem_ctx, &state, struct nb_connect_state);
+	if (req == NULL) {
+		return NULL;
+	}
+	state->ev = ev;
+	make_nmb_name(&state->called, called_name, called_type);
+	make_nmb_name(&state->calling, calling_name, calling_type);
+	state->sock = -1;
+
+	talloc_set_destructor(state, nb_connect_state_destructor);
+
+	subreq = open_socket_out_send(state, ev, addr, 139, 5000);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq, nb_connect_connected, req);
+	return req;
+}
+
+static int nb_connect_state_destructor(struct nb_connect_state *state)
+{
+	if (state->sock != -1) {
+		close(state->sock);
+	}
+	return 0;
+}
+
+static void nb_connect_connected(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct nb_connect_state *state = tevent_req_data(
+		req, struct nb_connect_state);
+	NTSTATUS status;
+
+	status = open_socket_out_recv(subreq, &state->sock);
+	TALLOC_FREE(subreq);
+	if (!NT_STATUS_IS_OK(status)) {
+		tevent_req_nterror(req, status);
+		return;
+	}
+	subreq = cli_session_request_send(state, state->ev, state->sock,
+					  &state->called, &state->calling);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, nb_connect_done, req);
+}
+
+static void nb_connect_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	bool ret;
+	int err;
+	uint8_t resp;
+
+	ret = cli_session_request_recv(subreq, &err, &resp);
+	TALLOC_FREE(subreq);
+	if (!ret) {
+		tevent_req_nterror(req, map_nt_error_from_unix(err));
+		return;
+	}
+	if (resp != 0x82) {
+		tevent_req_nterror(req, NT_STATUS_RESOURCE_NAME_NOT_FOUND);
+		return;
+	}
+	tevent_req_done(req);
+}
+
+static NTSTATUS nb_connect_recv(struct tevent_req *req, int *sock)
+{
+	struct nb_connect_state *state = tevent_req_data(
+		req, struct nb_connect_state);
+	NTSTATUS status;
+
+	if (tevent_req_is_nterror(req, &status)) {
+		return status;
+	}
+	*sock = state->sock;
+	state->sock = -1;
+	return NT_STATUS_OK;
+}
+
+struct smb_connect_state {
+	struct tevent_context *ev;
+	const struct sockaddr_storage *addr;
+	struct tevent_req *req_139;
+	struct tevent_req *req_445;
+	int sock;
+};
+
+static int smb_connect_state_destructor(struct smb_connect_state *state);
+static void smb_connect_connected(struct tevent_req *subreq);
+static void smb_connect_do_139(struct tevent_req *subreq);
+
+struct tevent_req *smb_connect_send(TALLOC_CTX *mem_ctx,
+				    struct tevent_context *ev,
+				    const struct sockaddr_storage *addr)
+{
+	struct tevent_req *req, *subreq;
+	struct smb_connect_state *state;
+
+	req = tevent_req_create(mem_ctx, &state, struct smb_connect_state);
+	if (req == NULL) {
+		return NULL;
+	}
+	state->ev = ev;
+	state->addr = addr;
+	state->sock = -1;
+	talloc_set_destructor(state, smb_connect_state_destructor);
+
+	state->req_445 = open_socket_out_send(state, ev, addr, 139, 5000);
+	if (tevent_req_nomem(state->req_445, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(state->req_445, smb_connect_connected, req);
+
+	/*
+	 * After 5 msecs, fire the 139 request
+	 */
+	subreq = tevent_wakeup_send(state, ev, tevent_timeval_set(0, 5000));
+	if (tevent_req_nomem(subreq, req)) {
+		TALLOC_FREE(state->req_445);
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq, smb_connect_do_139, req);
+	return req;
+}
+
+static int smb_connect_state_destructor(struct smb_connect_state *state)
+{
+	if (state->sock != -1) {
+		close(state->sock);
+	}
+	return 0;
+}
+
+static void smb_connect_do_139(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct smb_connect_state *state = tevent_req_data(
+		req, struct smb_connect_state);
+	bool ret;
+
+	ret = tevent_wakeup_recv(subreq);
+	TALLOC_FREE(subreq);
+	if (!ret) {
+		tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+		return;
+	}
+	state->req_139 = nb_connect_send(state, state->ev, state->addr,
+					 "*SMBSERVER", 0x20,
+					 global_myname(), 0);
+	if (tevent_req_nomem(state->req_139, req)) {
+		return;
+	}
+	tevent_req_set_callback(state->req_139, smb_connect_connected, req);
+}
+
+static void smb_connect_connected(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct smb_connect_state *state = tevent_req_data(
+		req, struct smb_connect_state);
+	NTSTATUS status;
+
+	status = NT_STATUS_INTERNAL_ERROR;
+
+	if (subreq == state->req_445) {
+		status = open_socket_out_recv(subreq, &state->sock);
+	} else if (subreq == state->req_139) {
+		status = nb_connect_recv(subreq, &state->sock);
+	}
+	TALLOC_FREE(state->req_139);
+	TALLOC_FREE(state->req_445);
+
+	if (!NT_STATUS_IS_OK(status)) {
+		tevent_req_nterror(req, status);
+		return;
+	}
+	tevent_req_done(req);
+}
+
+NTSTATUS smb_connect_recv(struct tevent_req *req, int *sock)
+{
+	struct smb_connect_state *state = tevent_req_data(
+		req, struct smb_connect_state);
+	NTSTATUS status;
+
+	if (tevent_req_is_nterror(req, &status)) {
+		return status;
+	}
+	*sock = state->sock;
+	state->sock = -1;
+	return NT_STATUS_OK;
+}
-- 
1.7.0.4


--Kj7319i9nmIyA2yE--


More information about the samba-technical mailing list