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 {
34 struct smbcli_socket *sock;
35 const char *dest_host;
39 static int smbcli_sock_destructor(void *ptr)
41 struct smbcli_socket *sock = talloc_get_type(ptr, struct smbcli_socket);
43 if (sock->event.fde && sock->event.ctx) {
44 event_remove_fd(sock->event.ctx, sock->event.fde);
50 create a smbcli_socket context
52 struct smbcli_socket *smbcli_sock_init(TALLOC_CTX *mem_ctx)
54 struct smbcli_socket *sock;
56 sock = talloc_zero(mem_ctx, struct smbcli_socket);
61 sock->event.ctx = event_context_init(sock);
62 if (sock->event.ctx == NULL) {
67 talloc_set_destructor(sock, smbcli_sock_destructor);
72 static NTSTATUS smbcli_sock_connect_one(struct smbcli_socket *sock,
73 const char *hostaddr, int port);
76 handle socket write events during an async connect. These happen when the OS
77 has either completed the connect() or has returned an error
79 static void smbcli_sock_connect_handler(struct event_context *ev, struct fd_event *fde,
80 struct timeval t, uint16_t flags)
82 struct smbcli_composite *c = talloc_get_type(fde->private, struct smbcli_composite);
83 struct clisocket_connect *conn = talloc_get_type(c->private, struct clisocket_connect);
86 c->status = socket_connect_complete(conn->sock->sock, 0);
87 if (NT_STATUS_IS_OK(c->status)) {
88 socket_set_option(conn->sock->sock, lp_socket_options(), NULL);
89 conn->sock->hostname = talloc_strdup(conn->sock, conn->dest_host);
90 c->state = SMBCLI_REQUEST_DONE;
97 /* that port failed - try the next port */
98 for (i=c->stage+1;conn->iports[i];i++) {
100 c->status = smbcli_sock_connect_one(conn->sock,
103 if (NT_STATUS_IS_OK(c->status) ||
104 NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
105 conn->sock->event.fde->private = c;
110 c->state = SMBCLI_REQUEST_ERROR;
118 try to connect to the given address/port
120 static NTSTATUS smbcli_sock_connect_one(struct smbcli_socket *sock,
121 const char *hostaddr, int port)
127 talloc_free(sock->sock);
131 if (sock->event.fde) {
132 event_remove_fd(sock->event.ctx, sock->event.fde);
133 sock->event.fde = NULL;
136 status = socket_create("ip", SOCKET_TYPE_STREAM, &sock->sock, 0);
137 if (!NT_STATUS_IS_OK(status)) {
141 talloc_steal(sock, sock->sock);
143 /* we initially look for write - see the man page on
144 non-blocking connect */
145 fde.fd = socket_get_fd(sock->sock);
146 fde.flags = EVENT_FD_WRITE;
147 fde.handler = smbcli_sock_connect_handler;
150 sock->event.fde = event_add_fd(sock->event.ctx, &fde);
152 set_blocking(fde.fd, False);
154 return socket_connect(sock->sock, NULL, 0, hostaddr, port, 0);
159 connect a smbcli_socket context to an IP/port pair
160 if port is 0 then choose 445 then 139
162 this is the async send side of the interface
164 struct smbcli_composite *smbcli_sock_connect_send(struct smbcli_socket *sock,
165 const char *host_addr, int port)
167 struct smbcli_composite *c;
168 struct clisocket_connect *conn;
171 c = talloc_zero(sock, struct smbcli_composite);
172 if (c == NULL) return NULL;
174 c->event_ctx = sock->event.ctx;
176 conn = talloc(c, struct clisocket_connect);
177 if (conn == NULL) goto failed;
181 /* work out what ports we will try */
183 const char **ports = lp_smb_ports();
184 for (i=0;ports[i];i++) /* noop */ ;
185 conn->iports = talloc_array(c, int, i+1);
186 if (conn->iports == NULL) goto failed;
187 for (i=0;ports[i];i++) {
188 conn->iports[i] = atoi(ports[i]);
192 conn->iports = talloc_array(c, int, 2);
193 if (conn->iports == NULL) goto failed;
194 conn->iports[0] = port;
198 conn->dest_host = talloc_strdup(c, host_addr);
199 if (conn->dest_host == NULL) goto failed;
202 c->state = SMBCLI_REQUEST_SEND;
204 /* startup the connect process for each port in turn until one
205 succeeds or tells us that it is pending */
206 for (i=0;conn->iports[i];i++) {
208 conn->sock->port = conn->iports[i];
209 c->status = smbcli_sock_connect_one(sock,
212 if (NT_STATUS_IS_OK(c->status) ||
213 NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
214 sock->event.fde->private = c;
219 c->state = SMBCLI_REQUEST_ERROR;
228 finish a smbcli_sock_connect_send() operation
230 NTSTATUS smbcli_sock_connect_recv(struct smbcli_composite *c)
233 status = smb_composite_wait(c);
239 connect a smbcli_socket context to an IP/port pair
240 if port is 0 then choose the ports listed in smb.conf (normally 445 then 139)
242 sync version of the function
244 NTSTATUS smbcli_sock_connect(struct smbcli_socket *sock, const char *host_addr, int port)
246 struct smbcli_composite *c;
248 c = smbcli_sock_connect_send(sock, host_addr, port);
250 return NT_STATUS_NO_MEMORY;
253 return smbcli_sock_connect_recv(c);
257 /****************************************************************************
258 mark the socket as dead
259 ****************************************************************************/
260 void smbcli_sock_dead(struct smbcli_socket *sock)
262 if (sock->sock != NULL) {
263 talloc_free(sock->sock);
268 /****************************************************************************
269 Set socket options on a open connection.
270 ****************************************************************************/
271 void smbcli_sock_set_options(struct smbcli_socket *sock, const char *options)
273 socket_set_option(sock->sock, options, NULL);
276 /****************************************************************************
277 Write to socket. Return amount written.
278 ****************************************************************************/
279 ssize_t smbcli_sock_write(struct smbcli_socket *sock, const uint8_t *data, size_t len)
285 if (sock->sock == NULL) {
290 blob.data = discard_const(data);
293 status = socket_send(sock->sock, &blob, &nsent, 0);
294 if (NT_STATUS_IS_ERR(status)) {
302 /****************************************************************************
303 Read from socket. return amount read
304 ****************************************************************************/
305 ssize_t smbcli_sock_read(struct smbcli_socket *sock, uint8_t *data, size_t len)
310 if (sock->sock == NULL) {
315 status = socket_recv(sock->sock, data, len, &nread, 0);
316 if (NT_STATUS_IS_ERR(status)) {
324 /****************************************************************************
325 resolve a hostname and connect
326 ****************************************************************************/
327 BOOL smbcli_sock_connect_byname(struct smbcli_socket *sock, const char *host, int port)
329 int name_type = 0x20;
334 name = talloc_strdup(sock, host);
336 /* allow hostnames of the form NAME#xx and do a netbios lookup */
337 if ((p = strchr(name, '#'))) {
338 name_type = strtol(p+1, NULL, 16);
342 if (!resolve_name(name, name, &ip, name_type)) {
346 sock->hostname = name;
348 status = smbcli_sock_connect(sock, sys_inet_ntoa(ip), port);
350 return NT_STATUS_IS_OK(status);