2 Unix SMB/CIFS implementation.
4 SMB client socket context management functions
6 Copyright (C) Andrew Tridgell 1994-2005
7 Copyright (C) James Myers 2003 <myersjj@samba.org>
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include "libcli/raw/libcliraw.h"
27 #include "libcli/composite/composite.h"
30 this private structure is used during async connection handling
32 struct clisocket_connect {
35 struct smbcli_socket *sock;
36 const char *dest_host;
41 create a smbcli_socket context
42 The event_ctx is optional - if not supplied one will be created
44 struct smbcli_socket *smbcli_sock_init(TALLOC_CTX *mem_ctx,
45 struct event_context *event_ctx)
47 struct smbcli_socket *sock;
49 sock = talloc_zero(mem_ctx, struct smbcli_socket);
55 sock->event.ctx = talloc_reference(sock, event_ctx);
57 sock->event.ctx = event_context_init(sock);
59 if (sock->event.ctx == NULL) {
67 static NTSTATUS smbcli_sock_connect_one(struct smbcli_socket *sock,
68 const char *hostaddr, int port,
69 struct composite_context *c);
72 handle socket write events during an async connect. These happen when the OS
73 has either completed the connect() or has returned an error
75 static void smbcli_sock_connect_handler(struct event_context *ev, struct fd_event *fde,
76 uint16_t flags, void *private)
78 struct composite_context *c = talloc_get_type(private, struct composite_context);
79 struct clisocket_connect *conn = talloc_get_type(c->private, struct clisocket_connect);
82 c->status = socket_connect_complete(conn->sock->sock, 0);
83 if (NT_STATUS_IS_OK(c->status)) {
84 socket_set_option(conn->sock->sock, lp_socket_options(), NULL);
85 conn->sock->hostname = talloc_strdup(conn->sock, conn->dest_host);
86 c->state = SMBCLI_REQUEST_DONE;
93 /* that port failed - try the next port */
94 for (i=conn->port_num+1;conn->iports[i];i++) {
96 c->status = smbcli_sock_connect_one(conn->sock,
99 if (NT_STATUS_IS_OK(c->status) ||
100 NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
105 c->state = SMBCLI_REQUEST_ERROR;
113 try to connect to the given address/port
115 static NTSTATUS smbcli_sock_connect_one(struct smbcli_socket *sock,
116 const char *hostaddr, int port,
117 struct composite_context *c)
122 talloc_free(sock->sock);
125 talloc_free(sock->event.fde);
127 status = socket_create("ip", SOCKET_TYPE_STREAM, &sock->sock, 0);
128 if (!NT_STATUS_IS_OK(status)) {
132 talloc_steal(sock, sock->sock);
134 /* we initially look for write - see the man page on
135 non-blocking connect */
136 sock->event.fde = event_add_fd(sock->event.ctx, sock, socket_get_fd(sock->sock),
137 EVENT_FD_WRITE, smbcli_sock_connect_handler, c);
140 set_blocking(socket_get_fd(sock->sock), False);
142 return socket_connect(sock->sock, NULL, 0, hostaddr, port, 0);
147 connect a smbcli_socket context to an IP/port pair
148 if port is 0 then choose 445 then 139
150 this is the async send side of the interface
152 struct composite_context *smbcli_sock_connect_send(struct smbcli_socket *sock,
153 const char *host_addr, int port)
155 struct composite_context *c;
156 struct clisocket_connect *conn;
159 c = talloc_zero(sock, struct composite_context);
160 if (c == NULL) return NULL;
162 c->event_ctx = sock->event.ctx;
164 conn = talloc(c, struct clisocket_connect);
165 if (conn == NULL) goto failed;
169 /* work out what ports we will try */
171 const char **ports = lp_smb_ports();
172 for (i=0;ports[i];i++) /* noop */ ;
173 conn->iports = talloc_array(c, int, i+1);
174 if (conn->iports == NULL) goto failed;
175 for (i=0;ports[i];i++) {
176 conn->iports[i] = atoi(ports[i]);
180 conn->iports = talloc_array(c, int, 2);
181 if (conn->iports == NULL) goto failed;
182 conn->iports[0] = port;
186 conn->dest_host = talloc_strdup(c, host_addr);
187 if (conn->dest_host == NULL) goto failed;
190 c->state = SMBCLI_REQUEST_SEND;
192 /* startup the connect process for each port in turn until one
193 succeeds or tells us that it is pending */
194 for (i=0;conn->iports[i];i++) {
196 conn->sock->port = conn->iports[i];
197 c->status = smbcli_sock_connect_one(sock,
200 if (NT_STATUS_IS_OK(c->status) ||
201 NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
206 c->state = SMBCLI_REQUEST_ERROR;
215 finish a smbcli_sock_connect_send() operation
217 NTSTATUS smbcli_sock_connect_recv(struct composite_context *c)
220 status = composite_wait(c);
226 connect a smbcli_socket context to an IP/port pair
227 if port is 0 then choose the ports listed in smb.conf (normally 445 then 139)
229 sync version of the function
231 NTSTATUS smbcli_sock_connect(struct smbcli_socket *sock, const char *host_addr, int port)
233 struct composite_context *c;
235 c = smbcli_sock_connect_send(sock, host_addr, port);
237 return NT_STATUS_NO_MEMORY;
240 return smbcli_sock_connect_recv(c);
244 /****************************************************************************
245 mark the socket as dead
246 ****************************************************************************/
247 void smbcli_sock_dead(struct smbcli_socket *sock)
249 if (sock->sock != NULL) {
250 talloc_free(sock->sock);
255 /****************************************************************************
256 Set socket options on a open connection.
257 ****************************************************************************/
258 void smbcli_sock_set_options(struct smbcli_socket *sock, const char *options)
260 socket_set_option(sock->sock, options, NULL);
263 /****************************************************************************
264 Write to socket. Return amount written.
265 ****************************************************************************/
266 ssize_t smbcli_sock_write(struct smbcli_socket *sock, const uint8_t *data, size_t len)
272 if (sock->sock == NULL) {
277 blob.data = discard_const(data);
280 status = socket_send(sock->sock, &blob, &nsent, 0);
281 if (NT_STATUS_IS_ERR(status)) {
289 /****************************************************************************
290 Read from socket. return amount read
291 ****************************************************************************/
292 ssize_t smbcli_sock_read(struct smbcli_socket *sock, uint8_t *data, size_t len)
297 if (sock->sock == NULL) {
302 status = socket_recv(sock->sock, data, len, &nread, 0);
303 if (NT_STATUS_IS_ERR(status)) {
311 /****************************************************************************
312 resolve a hostname and connect
313 ****************************************************************************/
314 BOOL smbcli_sock_connect_byname(struct smbcli_socket *sock, const char *host, int port)
316 int name_type = NBT_NAME_SERVER;
319 struct nbt_name nbt_name;
322 name = talloc_strdup(sock, host);
324 /* allow hostnames of the form NAME#xx and do a netbios lookup */
325 if ((p = strchr(name, '#'))) {
326 name_type = strtol(p+1, NULL, 16);
330 nbt_name.name = name;
331 nbt_name.type = name_type;
332 nbt_name.scope = NULL;
334 status = resolve_name(&nbt_name, sock, &address);
335 if (!NT_STATUS_IS_OK(status)) {
339 sock->hostname = name;
341 status = smbcli_sock_connect(sock, address, port);
343 return NT_STATUS_IS_OK(status);