[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