s3: Add an async smbsock_connect
[Samba.git] / source3 / libsmb / smbsock_connect.c
blob335579576442f2cab68151b9568783de46709f54
1 /*
2 Unix SMB/CIFS implementation.
3 Connect to 445 and 139/nbsesssetup
4 Copyright (C) Volker Lendecke 2010
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "../lib/async_req/async_sock.h"
22 #include "async_smb.h"
24 struct nb_connect_state {
25 struct tevent_context *ev;
26 int sock;
27 struct nmb_name called;
28 struct nmb_name calling;
31 static int nb_connect_state_destructor(struct nb_connect_state *state);
32 static void nb_connect_connected(struct tevent_req *subreq);
33 static void nb_connect_done(struct tevent_req *subreq);
35 static struct tevent_req *nb_connect_send(TALLOC_CTX *mem_ctx,
36 struct tevent_context *ev,
37 const struct sockaddr_storage *addr,
38 const char *called_name,
39 int called_type,
40 const char *calling_name,
41 int calling_type)
43 struct tevent_req *req, *subreq;
44 struct nb_connect_state *state;
46 req = tevent_req_create(mem_ctx, &state, struct nb_connect_state);
47 if (req == NULL) {
48 return NULL;
50 state->ev = ev;
51 make_nmb_name(&state->called, called_name, called_type);
52 make_nmb_name(&state->calling, calling_name, calling_type);
53 state->sock = -1;
55 talloc_set_destructor(state, nb_connect_state_destructor);
57 subreq = open_socket_out_send(state, ev, addr, 139, 5000);
58 if (tevent_req_nomem(subreq, req)) {
59 return tevent_req_post(req, ev);
61 tevent_req_set_callback(subreq, nb_connect_connected, req);
62 return req;
65 static int nb_connect_state_destructor(struct nb_connect_state *state)
67 if (state->sock != -1) {
68 close(state->sock);
70 return 0;
73 static void nb_connect_connected(struct tevent_req *subreq)
75 struct tevent_req *req = tevent_req_callback_data(
76 subreq, struct tevent_req);
77 struct nb_connect_state *state = tevent_req_data(
78 req, struct nb_connect_state);
79 NTSTATUS status;
81 status = open_socket_out_recv(subreq, &state->sock);
82 TALLOC_FREE(subreq);
83 if (!NT_STATUS_IS_OK(status)) {
84 tevent_req_nterror(req, status);
85 return;
87 subreq = cli_session_request_send(state, state->ev, state->sock,
88 &state->called, &state->calling);
89 if (tevent_req_nomem(subreq, req)) {
90 return;
92 tevent_req_set_callback(subreq, nb_connect_done, req);
95 static void nb_connect_done(struct tevent_req *subreq)
97 struct tevent_req *req = tevent_req_callback_data(
98 subreq, struct tevent_req);
99 bool ret;
100 int err;
101 uint8_t resp;
103 ret = cli_session_request_recv(subreq, &err, &resp);
104 TALLOC_FREE(subreq);
105 if (!ret) {
106 tevent_req_nterror(req, map_nt_error_from_unix(err));
107 return;
109 if (resp != 0x82) {
110 tevent_req_nterror(req, NT_STATUS_RESOURCE_NAME_NOT_FOUND);
111 return;
113 tevent_req_done(req);
116 static NTSTATUS nb_connect_recv(struct tevent_req *req, int *sock)
118 struct nb_connect_state *state = tevent_req_data(
119 req, struct nb_connect_state);
120 NTSTATUS status;
122 if (tevent_req_is_nterror(req, &status)) {
123 return status;
125 *sock = state->sock;
126 state->sock = -1;
127 return NT_STATUS_OK;
130 struct smbsock_connect_state {
131 struct tevent_context *ev;
132 const struct sockaddr_storage *addr;
133 const char *called_name;
134 const char *calling_name;
135 struct tevent_req *req_139;
136 struct tevent_req *req_445;
137 int sock;
138 uint16_t port;
141 static int smbsock_connect_state_destructor(
142 struct smbsock_connect_state *state);
143 static void smbsock_connect_connected(struct tevent_req *subreq);
144 static void smbsock_connect_do_139(struct tevent_req *subreq);
146 struct tevent_req *smbsock_connect_send(TALLOC_CTX *mem_ctx,
147 struct tevent_context *ev,
148 const struct sockaddr_storage *addr,
149 const char *called_name,
150 const char *calling_name)
152 struct tevent_req *req, *subreq;
153 struct smbsock_connect_state *state;
155 req = tevent_req_create(mem_ctx, &state, struct smbsock_connect_state);
156 if (req == NULL) {
157 return NULL;
159 state->ev = ev;
160 state->addr = addr;
161 state->sock = -1;
162 state->called_name =
163 (called_name != NULL) ? called_name : "*SMBSERVER";
164 state->calling_name =
165 (calling_name != NULL) ? calling_name : global_myname();
167 talloc_set_destructor(state, smbsock_connect_state_destructor);
169 state->req_445 = open_socket_out_send(state, ev, addr, 445, 5000);
170 if (tevent_req_nomem(state->req_445, req)) {
171 return tevent_req_post(req, ev);
173 tevent_req_set_callback(state->req_445, smbsock_connect_connected,
174 req);
177 * After 5 msecs, fire the 139 request
179 subreq = tevent_wakeup_send(state, ev, timeval_current_ofs(0, 5000));
180 if (tevent_req_nomem(subreq, req)) {
181 TALLOC_FREE(state->req_445);
182 return tevent_req_post(req, ev);
184 tevent_req_set_callback(subreq, smbsock_connect_do_139, req);
185 return req;
188 static int smbsock_connect_state_destructor(
189 struct smbsock_connect_state *state)
191 if (state->sock != -1) {
192 close(state->sock);
194 return 0;
197 static void smbsock_connect_do_139(struct tevent_req *subreq)
199 struct tevent_req *req = tevent_req_callback_data(
200 subreq, struct tevent_req);
201 struct smbsock_connect_state *state = tevent_req_data(
202 req, struct smbsock_connect_state);
203 bool ret;
205 ret = tevent_wakeup_recv(subreq);
206 TALLOC_FREE(subreq);
207 if (!ret) {
208 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
209 return;
211 state->req_139 = nb_connect_send(state, state->ev, state->addr,
212 state->called_name, 0x20,
213 state->calling_name, 0x0);
214 if (tevent_req_nomem(state->req_139, req)) {
215 return;
217 tevent_req_set_callback(state->req_139, smbsock_connect_connected,
218 req);
221 static void smbsock_connect_connected(struct tevent_req *subreq)
223 struct tevent_req *req = tevent_req_callback_data(
224 subreq, struct tevent_req);
225 struct smbsock_connect_state *state = tevent_req_data(
226 req, struct smbsock_connect_state);
227 struct tevent_req *unfinished_req;
228 NTSTATUS status;
230 if (subreq == state->req_445) {
232 status = open_socket_out_recv(subreq, &state->sock);
233 TALLOC_FREE(state->req_445);
234 unfinished_req = state->req_139;
235 state->port = 445;
237 } else if (subreq == state->req_139) {
239 status = nb_connect_recv(subreq, &state->sock);
240 TALLOC_FREE(state->req_139);
241 unfinished_req = state->req_445;
242 state->port = 139;
244 } else {
245 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
246 return;
249 if (NT_STATUS_IS_OK(status)) {
250 TALLOC_FREE(unfinished_req);
251 state->req_139 = NULL;
252 state->req_445 = NULL;
253 tevent_req_done(req);
254 return;
256 if (unfinished_req == NULL) {
258 * Both requests failed
260 tevent_req_nterror(req, status);
261 return;
264 * Do nothing, wait for the second request to come here.
268 NTSTATUS smbsock_connect_recv(struct tevent_req *req, int *sock,
269 uint16_t *port)
271 struct smbsock_connect_state *state = tevent_req_data(
272 req, struct smbsock_connect_state);
273 NTSTATUS status;
275 if (tevent_req_is_nterror(req, &status)) {
276 return status;
278 *sock = state->sock;
279 state->sock = -1;
280 *port = state->port;
281 return NT_STATUS_OK;
284 NTSTATUS smbsock_connect(const struct sockaddr_storage *addr,
285 const char *called_name, const char *calling_name,
286 int *pfd, uint16_t *port)
288 TALLOC_CTX *frame = talloc_stackframe();
289 struct event_context *ev;
290 struct tevent_req *req;
291 NTSTATUS status = NT_STATUS_NO_MEMORY;
293 ev = event_context_init(frame);
294 if (ev == NULL) {
295 goto fail;
297 req = smbsock_connect_send(frame, ev, addr, called_name, calling_name);
298 if (req == NULL) {
299 goto fail;
301 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
302 goto fail;
304 status = smbsock_connect_recv(req, pfd, port);
305 fail:
306 TALLOC_FREE(frame);
307 return status;