r4777: added a smb_composite_sesssetup() async composite function. This
[gd/samba-autobuild/.git] / source4 / libcli / raw / clitransport.c
index e70ee915c6ff60937583d0f0a2dfbf309303f3e9..55a7e25f723d538dd5225146e76c58fe9c41ca42 100644 (file)
@@ -1,7 +1,8 @@
 /* 
    Unix SMB/CIFS implementation.
    SMB client transport context management functions
-   Copyright (C) Andrew Tridgell 1994-2003
+
+   Copyright (C) Andrew Tridgell 1994-2005
    Copyright (C) James Myers 2003 <myersjj@samba.org>
    
    This program is free software; you can redistribute it and/or modify
@@ -22,6 +23,8 @@
 #include "includes.h"
 #include "libcli/raw/libcliraw.h"
 #include "system/time.h"
+#include "dlinklist.h"
+#include "events.h"
 
 
 static void smbcli_transport_process_recv(struct smbcli_transport *transport);
@@ -31,7 +34,7 @@ static void smbcli_transport_process_send(struct smbcli_transport *transport);
   an event has happened on the socket
 */
 static void smbcli_transport_event_handler(struct event_context *ev, struct fd_event *fde, 
-                                       time_t t, uint16_t flags)
+                                          struct timeval t, uint16_t flags)
 {
        struct smbcli_transport *transport = fde->private;
 
@@ -51,8 +54,8 @@ static int transport_destructor(void *ptr)
        struct smbcli_transport *transport = ptr;
 
        smbcli_transport_dead(transport);
-       event_remove_fd(transport->event.ctx, transport->event.fde);
-       event_remove_timed(transport->event.ctx, transport->event.te);
+       event_remove_fd(transport->socket->event.ctx, transport->socket->event.fde);
+       event_remove_timed(transport->socket->event.ctx, transport->socket->event.te);
        return 0;
 }
 
@@ -62,19 +65,12 @@ static int transport_destructor(void *ptr)
 struct smbcli_transport *smbcli_transport_init(struct smbcli_socket *sock)
 {
        struct smbcli_transport *transport;
-       struct fd_event fde;
 
        transport = talloc_p(sock, struct smbcli_transport);
        if (!transport) return NULL;
 
        ZERO_STRUCTP(transport);
 
-       transport->event.ctx = event_context_init(transport);
-       if (transport->event.ctx == NULL) {
-               talloc_free(transport);
-               return NULL;
-       }
-
        transport->socket = talloc_reference(transport, sock);
        transport->negotiate.protocol = PROTOCOL_NT1;
        transport->options.use_spnego = lp_use_spnego();
@@ -87,13 +83,11 @@ struct smbcli_transport *smbcli_transport_init(struct smbcli_socket *sock)
 
        ZERO_STRUCT(transport->called);
 
-       fde.fd = socket_get_fd(sock->sock);
-       fde.flags = EVENT_FD_READ;
-       fde.handler = smbcli_transport_event_handler;
-       fde.private = transport;
-       fde.ref_count = 1;
-
-       transport->event.fde = event_add_fd(transport->event.ctx, &fde);
+       /* take over event handling from the socket layer - it only
+          handles events up until we are connected */
+       transport->socket->event.fde->handler = smbcli_transport_event_handler;
+       transport->socket->event.fde->private = transport;
+       transport->socket->event.fde->flags = EVENT_FD_READ;
 
        talloc_set_destructor(transport, transport_destructor);
 
@@ -136,7 +130,7 @@ void smbcli_transport_dead(struct smbcli_transport *transport)
 */
 static void smbcli_transport_write_enable(struct smbcli_transport *transport)
 {
-       transport->event.fde->flags |= EVENT_FD_WRITE;
+       transport->socket->event.fde->flags |= EVENT_FD_WRITE;
 }
 
 /*
@@ -144,17 +138,17 @@ static void smbcli_transport_write_enable(struct smbcli_transport *transport)
 */
 static void smbcli_transport_write_disable(struct smbcli_transport *transport)
 {
-       transport->event.fde->flags &= ~EVENT_FD_WRITE;
+       transport->socket->event.fde->flags &= ~EVENT_FD_WRITE;
 }
 
-/****************************************************************************
-send a session request (if appropriate)
-****************************************************************************/
-BOOL smbcli_transport_connect(struct smbcli_transport *transport,
-                          struct nmb_name *calling, 
-                          struct nmb_name *called)
+/*
+  send a session request
+*/
+struct smbcli_request *smbcli_transport_connect_send(struct smbcli_transport *transport,
+                                                    struct nmb_name *calling, 
+                                                    struct nmb_name *called)
 {
-       char *p;
+       uint8_t *p;
        int len = NBT_HDR_SIZE;
        struct smbcli_request *req;
 
@@ -162,45 +156,103 @@ BOOL smbcli_transport_connect(struct smbcli_transport *transport,
                transport->called = *called;
        }
 
-       /* 445 doesn't have session request */
-       if (transport->socket->port == 445) {
-               return True;
-       }
-
        /* allocate output buffer */
-       req = smbcli_request_setup_nonsmb(transport, NBT_HDR_SIZE + 2*nbt_mangled_name_len());
+       req = smbcli_request_setup_nonsmb(transport, 
+                                         NBT_HDR_SIZE + 2*nbt_mangled_name_len());
+       if (req == NULL) return NULL;
 
        /* put in the destination name */
        p = req->out.buffer + NBT_HDR_SIZE;
-       name_mangle(called->name, p, called->name_type);
-       len += name_len(p);
+       name_mangle(called->name, (char *)p, called->name_type);
+       len += name_len((char *)p);
 
        /* and my name */
        p = req->out.buffer+len;
-       name_mangle(calling->name, p, calling->name_type);
-       len += name_len(p);
+       name_mangle(calling->name, (char *)p, calling->name_type);
+       len += name_len((char *)p);
 
        _smb_setlen(req->out.buffer,len-4);
        SCVAL(req->out.buffer,0,0x81);
 
-       if (!smbcli_request_send(req) ||
-           !smbcli_request_receive(req)) {
+       if (!smbcli_request_send(req)) {
                smbcli_request_destroy(req);
-               return False;
+               return NULL;
        }
-       
-       if (CVAL(req->in.buffer,0) != 0x82) {
-               transport->error.etype = ETYPE_NBT;
-               transport->error.e.nbt_error = CVAL(req->in.buffer,4);
+
+       return req;
+}
+
+/*
+  map a session request error to a NTSTATUS
+ */
+static NTSTATUS map_session_refused_error(uint8_t error)
+{
+       switch (error) {
+       case 0x80:
+       case 0x81:
+               return NT_STATUS_REMOTE_NOT_LISTENING;
+       case 0x82:
+               return NT_STATUS_RESOURCE_NAME_NOT_FOUND;
+       case 0x83:
+               return NT_STATUS_REMOTE_RESOURCES;
+       }
+       return NT_STATUS_UNEXPECTED_IO_ERROR;
+}
+
+
+/*
+  finish a smbcli_transport_connect()
+*/
+NTSTATUS smbcli_transport_connect_recv(struct smbcli_request *req)
+{
+       NTSTATUS status;
+
+       if (!smbcli_request_receive(req)) {
                smbcli_request_destroy(req);
-               return False;
+               return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
+       }
+
+       switch (CVAL(req->in.buffer,0)) {
+       case 0x82:
+               status = NT_STATUS_OK;
+               break;
+       case 0x83:
+               status = map_session_refused_error(CVAL(req->in.buffer,4));
+               break;
+       case 0x84:
+               DEBUG(1,("Warning: session retarget not supported\n"));
+               status = NT_STATUS_NOT_SUPPORTED;
+               break;
+       default:
+               status = NT_STATUS_UNEXPECTED_IO_ERROR;
+               break;
        }
 
        smbcli_request_destroy(req);
-       return True;
+       return status;
 }
 
 
+/*
+  send a session request (if needed)
+*/
+BOOL smbcli_transport_connect(struct smbcli_transport *transport,
+                             struct nmb_name *calling, 
+                             struct nmb_name *called)
+{
+       struct smbcli_request *req;
+       NTSTATUS status;
+
+       if (transport->socket->port == 445) {
+               return True;
+       }
+
+       req = smbcli_transport_connect_send(transport, 
+                                           calling, called);
+       status = smbcli_transport_connect_recv(req);
+       return NT_STATUS_IS_OK(status);
+}
+
 /****************************************************************************
 get next mid in sequence
 ****************************************************************************/
@@ -231,35 +283,35 @@ again:
 }
 
 static void idle_handler(struct event_context *ev, 
-                        struct timed_event *te, time_t t)
+                        struct timed_event *te, struct timeval t)
 {
        struct smbcli_transport *transport = te->private;
-       te->next_event = t + transport->idle.period;
+       te->next_event = timeval_add(&te->next_event, 0, transport->idle.period);
        transport->idle.func(transport, transport->idle.private);
 }
 
 /*
   setup the idle handler for a transport
-  the period is in seconds
+  the period is in microseconds
 */
 void smbcli_transport_idle_handler(struct smbcli_transport *transport, 
-                               void (*idle_func)(struct smbcli_transport *, void *),
-                               uint_t period,
-                               void *private)
+                                  void (*idle_func)(struct smbcli_transport *, void *),
+                                  uint64_t period,
+                                  void *private)
 {
        struct timed_event te;
        transport->idle.func = idle_func;
        transport->idle.private = private;
        transport->idle.period = period;
 
-       if (transport->event.te != NULL) {
-               event_remove_timed(transport->event.ctx, transport->event.te);
+       if (transport->socket->event.te != NULL) {
+               event_remove_timed(transport->socket->event.ctx, transport->socket->event.te);
        }
 
-       te.next_event = time(NULL) + period;
+       te.next_event = timeval_current_ofs(0, period);
        te.handler = idle_handler;
        te.private = transport;
-       transport->event.te = event_add_timed(transport->event.ctx, &te);
+       transport->socket->event.te = event_add_timed(transport->socket->event.ctx, &te);
 }
 
 /*
@@ -414,6 +466,7 @@ static void smbcli_transport_finish_recv(struct smbcli_transport *transport)
                transport->error.etype = ETYPE_SOCKET;
                transport->error.e.socket_error = SOCKET_READ_BAD_SIG;
                req->state = SMBCLI_REQUEST_ERROR;
+               req->status = NT_STATUS_ACCESS_DENIED;
                goto error;
        };
 
@@ -459,8 +512,8 @@ static void smbcli_transport_process_recv(struct smbcli_transport *transport)
                if (transport->recv_buffer.received == NBT_HDR_SIZE) {
                        /* we've got a full header */
                        transport->recv_buffer.req_size = smb_len(transport->recv_buffer.header) + NBT_HDR_SIZE;
-                       transport->recv_buffer.buffer = talloc(transport,
-                                                              NBT_HDR_SIZE+transport->recv_buffer.req_size);
+                       transport->recv_buffer.buffer = talloc_size(transport,
+                                                                   NBT_HDR_SIZE+transport->recv_buffer.req_size);
                        if (transport->recv_buffer.buffer == NULL) {
                                smbcli_transport_dead(transport);
                                return;