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;
40 static int smbcli_sock_destructor(void *ptr)
42 struct smbcli_socket *sock = talloc_get_type(ptr, struct smbcli_socket);
44 if (sock->event.fde && sock->event.ctx) {
45 event_remove_fd(sock->event.ctx, sock->event.fde);
51 create a smbcli_socket context
53 struct smbcli_socket *smbcli_sock_init(TALLOC_CTX *mem_ctx)
55 struct smbcli_socket *sock;
57 sock = talloc_zero(mem_ctx, struct smbcli_socket);
62 sock->event.ctx = event_context_init(sock);
63 if (sock->event.ctx == NULL) {
68 talloc_set_destructor(sock, smbcli_sock_destructor);
73 static NTSTATUS smbcli_sock_connect_one(struct smbcli_socket *sock,
74 const char *hostaddr, int port);
77 handle socket write events during an async connect. These happen when the OS
78 has either completed the connect() or has returned an error
80 static void smbcli_sock_connect_handler(struct event_context *ev, struct fd_event *fde,
81 struct timeval t, uint16_t flags)
83 struct smbcli_composite *c = talloc_get_type(fde->private, struct smbcli_composite);
84 struct clisocket_connect *conn = talloc_get_type(c->private, struct clisocket_connect);
87 c->status = socket_connect_complete(conn->sock->sock, 0);
88 if (NT_STATUS_IS_OK(c->status)) {
89 socket_set_option(conn->sock->sock, lp_socket_options(), NULL);
90 conn->sock->hostname = talloc_strdup(conn->sock, conn->dest_host);
91 c->state = SMBCLI_REQUEST_DONE;
98 /* that port failed - try the next port */
99 for (i=conn->port_num+1;conn->iports[i];i++) {
101 c->status = smbcli_sock_connect_one(conn->sock,
104 if (NT_STATUS_IS_OK(c->status) ||
105 NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
106 conn->sock->event.fde->private = c;
111 c->state = SMBCLI_REQUEST_ERROR;
119 try to connect to the given address/port
121 static NTSTATUS smbcli_sock_connect_one(struct smbcli_socket *sock,
122 const char *hostaddr, int port)
128 talloc_free(sock->sock);
132 if (sock->event.fde) {
133 event_remove_fd(sock->event.ctx, sock->event.fde);
134 sock->event.fde = NULL;
137 status = socket_create("ip", SOCKET_TYPE_STREAM, &sock->sock, 0);
138 if (!NT_STATUS_IS_OK(status)) {
142 talloc_steal(sock, sock->sock);
144 /* we initially look for write - see the man page on
145 non-blocking connect */
146 fde.fd = socket_get_fd(sock->sock);
147 fde.flags = EVENT_FD_WRITE;
148 fde.handler = smbcli_sock_connect_handler;
151 sock->event.fde = event_add_fd(sock->event.ctx, &fde);
153 set_blocking(fde.fd, False);
155 return socket_connect(sock->sock, NULL, 0, hostaddr, port, 0);
160 connect a smbcli_socket context to an IP/port pair
161 if port is 0 then choose 445 then 139
163 this is the async send side of the interface
165 struct smbcli_composite *smbcli_sock_connect_send(struct smbcli_socket *sock,
166 const char *host_addr, int port)
168 struct smbcli_composite *c;
169 struct clisocket_connect *conn;
172 c = talloc_zero(sock, struct smbcli_composite);
173 if (c == NULL) return NULL;
175 c->event_ctx = sock->event.ctx;
177 conn = talloc(c, struct clisocket_connect);
178 if (conn == NULL) goto failed;
182 /* work out what ports we will try */
184 const char **ports = lp_smb_ports();
185 for (i=0;ports[i];i++) /* noop */ ;
186 conn->iports = talloc_array(c, int, i+1);
187 if (conn->iports == NULL) goto failed;
188 for (i=0;ports[i];i++) {
189 conn->iports[i] = atoi(ports[i]);
193 conn->iports = talloc_array(c, int, 2);
194 if (conn->iports == NULL) goto failed;
195 conn->iports[0] = port;
199 conn->dest_host = talloc_strdup(c, host_addr);
200 if (conn->dest_host == NULL) goto failed;
203 c->state = SMBCLI_REQUEST_SEND;
205 /* startup the connect process for each port in turn until one
206 succeeds or tells us that it is pending */
207 for (i=0;conn->iports[i];i++) {
209 conn->sock->port = conn->iports[i];
210 c->status = smbcli_sock_connect_one(sock,
213 if (NT_STATUS_IS_OK(c->status) ||
214 NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
215 sock->event.fde->private = c;
220 c->state = SMBCLI_REQUEST_ERROR;
229 finish a smbcli_sock_connect_send() operation
231 NTSTATUS smbcli_sock_connect_recv(struct smbcli_composite *c)
234 status = smb_composite_wait(c);
240 connect a smbcli_socket context to an IP/port pair
241 if port is 0 then choose the ports listed in smb.conf (normally 445 then 139)
243 sync version of the function
245 NTSTATUS smbcli_sock_connect(struct smbcli_socket *sock, const char *host_addr, int port)
247 struct smbcli_composite *c;
249 c = smbcli_sock_connect_send(sock, host_addr, port);
251 return NT_STATUS_NO_MEMORY;
254 return smbcli_sock_connect_recv(c);
258 /****************************************************************************
259 mark the socket as dead
260 ****************************************************************************/
261 void smbcli_sock_dead(struct smbcli_socket *sock)
263 if (sock->sock != NULL) {
264 talloc_free(sock->sock);
269 /****************************************************************************
270 Set socket options on a open connection.
271 ****************************************************************************/
272 void smbcli_sock_set_options(struct smbcli_socket *sock, const char *options)
274 socket_set_option(sock->sock, options, NULL);
277 /****************************************************************************
278 Write to socket. Return amount written.
279 ****************************************************************************/
280 ssize_t smbcli_sock_write(struct smbcli_socket *sock, const uint8_t *data, size_t len)
286 if (sock->sock == NULL) {
291 blob.data = discard_const(data);
294 status = socket_send(sock->sock, &blob, &nsent, 0);
295 if (NT_STATUS_IS_ERR(status)) {
303 /****************************************************************************
304 Read from socket. return amount read
305 ****************************************************************************/
306 ssize_t smbcli_sock_read(struct smbcli_socket *sock, uint8_t *data, size_t len)
311 if (sock->sock == NULL) {
316 status = socket_recv(sock->sock, data, len, &nread, 0);
317 if (NT_STATUS_IS_ERR(status)) {
325 /****************************************************************************
326 resolve a hostname and connect
327 ****************************************************************************/
328 BOOL smbcli_sock_connect_byname(struct smbcli_socket *sock, const char *host, int port)
330 int name_type = NBT_NAME_SERVER;
333 struct nbt_name nbt_name;
336 name = talloc_strdup(sock, host);
338 /* allow hostnames of the form NAME#xx and do a netbios lookup */
339 if ((p = strchr(name, '#'))) {
340 name_type = strtol(p+1, NULL, 16);
344 nbt_name.name = name;
345 nbt_name.type = name_type;
346 nbt_name.scope = NULL;
348 status = resolve_name(&nbt_name, sock, &address);
349 if (!NT_STATUS_IS_OK(status)) {
353 sock->hostname = name;
355 status = smbcli_sock_connect(sock, address, port);
357 return NT_STATUS_IS_OK(status);