r5275: - added support for NBT_OPCODE_MULTI_HOME_REG (opcode 0xf) for WINS name regis...
authorAndrew Tridgell <tridge@samba.org>
Tue, 8 Feb 2005 01:05:41 +0000 (01:05 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:09:36 +0000 (13:09 -0500)
- fixed a bug in the send queue handling on timeouts

- added support for handling unexpected replies (replies to the wrong
  port) at the nbtsocket layer

- added separate layer 2 code for wins refresh and wins registration
(This used to be commit 2502b02898407e3262c09a5a4aa573c5f87b8f5f)

source4/include/structs.h
source4/libcli/nbt/libnbt.h
source4/libcli/nbt/namerefresh.c
source4/libcli/nbt/nameregister.c
source4/libcli/nbt/nbtsocket.c
source4/librpc/idl/nbt.idl

index d8164c9b06d4a44b5ec8306dfb903cf766f4b434..1781ee09ec0eef5f375fe3a6fc2af0ef8354e6dd 100644 (file)
@@ -159,6 +159,7 @@ struct nbt_name_register;
 struct nbt_name_refresh;
 struct nbt_name_register_bcast;
 struct nbt_name_refresh_wins;
+struct nbt_name_register_wins;
 
 struct messaging_context;
 struct stream_connection;
index c126f592808e0e1460ebfdcb9523ad6dfb426c7c..63711490feae209cfd712b4f29cba3243999b00a 100644 (file)
@@ -113,7 +113,13 @@ struct nbt_name_socket {
                                const char *, int );
                void *private;
        } incoming;
-          
+
+       /* what to do with unexpected replies */
+       struct {
+               void (*handler)(struct nbt_name_socket *, struct nbt_name_packet *, 
+                               const char *, int );
+               void *private;
+       } unexpected;
 };
 
 
@@ -161,6 +167,7 @@ struct nbt_name_register {
                uint16_t nb_flags;
                BOOL register_demand;
                BOOL broadcast;
+               BOOL multi_homed;
                uint32_t ttl;
                int timeout; /* in seconds */
                int retries;
@@ -184,9 +191,10 @@ struct nbt_name_register_bcast {
        } in;
 };
 
-/* wins name refresh with multiple wins servers to try and multiple
+
+/* wins name register with multiple wins servers to try and multiple
    addresses to register */
-struct nbt_name_refresh_wins {
+struct nbt_name_register_wins {
        struct {
                struct nbt_name name;
                const char **wins_servers;
@@ -201,6 +209,7 @@ struct nbt_name_refresh_wins {
 };
 
 
+
 /* a name refresh request */
 struct nbt_name_refresh {
        struct {
@@ -220,3 +229,21 @@ struct nbt_name_refresh {
                uint8_t rcode;
        } out;
 };
+
+/* wins name refresh with multiple wins servers to try and multiple
+   addresses to register */
+struct nbt_name_refresh_wins {
+       struct {
+               struct nbt_name name;
+               const char **wins_servers;
+               const char **addresses;
+               uint16_t nb_flags;
+               uint32_t ttl;
+       } in;
+       struct {
+               const char *wins_server;
+               uint8_t rcode;
+       } out;
+};
+
+
index d8dbede7278e0c05db9ff509fa164ab4b989b56d..99d79054a62604aea4d618fdbd08b1bccddd7f6f 100644 (file)
@@ -141,8 +141,8 @@ NTSTATUS nbt_name_refresh(struct nbt_name_socket *nbtsock,
 struct refresh_wins_state {
        struct nbt_name_socket *nbtsock;
        struct nbt_name_refresh *io;
-       char **wins_servers;
-       char **addresses;
+       const char **wins_servers;
+       const char **addresses;
        int address_idx;
        struct nbt_name_request *req;
 };
index 9e9a1e171000092ee2971c86c165ea1031a2cd50..b0ed1ae89c3c5f0c97f8793f182fa15bf1a23dc9 100644 (file)
@@ -40,7 +40,11 @@ struct nbt_name_request *nbt_name_register_send(struct nbt_name_socket *nbtsock,
 
        packet->qdcount = 1;
        packet->arcount = 1;
-       packet->operation = NBT_OPCODE_REGISTER;
+       if (io->in.multi_homed) {
+               packet->operation = NBT_OPCODE_MULTI_HOME_REG;
+       } else {
+               packet->operation = NBT_OPCODE_REGISTER;
+       }
        if (io->in.broadcast) {
                packet->operation |= NBT_FLAG_BROADCAST;
        }
@@ -221,6 +225,7 @@ struct composite_context *nbt_name_register_bcast_send(struct nbt_name_socket *n
        state->io->in.nb_flags        = io->in.nb_flags;
        state->io->in.register_demand = False;
        state->io->in.broadcast       = True;
+       state->io->in.multi_homed     = False;
        state->io->in.ttl             = io->in.ttl;
        state->io->in.timeout         = 1;
        state->io->in.retries         = 2;
@@ -264,3 +269,165 @@ NTSTATUS nbt_name_register_bcast(struct nbt_name_socket *nbtsock,
        struct composite_context *c = nbt_name_register_bcast_send(nbtsock, io);
        return nbt_name_register_bcast_recv(c);
 }
+
+
+/*
+  a wins name register with multiple WINS servers and multiple
+  addresses to register. Try each WINS server in turn, until we get a
+  reply for each address
+*/
+struct register_wins_state {
+       struct nbt_name_socket *nbtsock;
+       struct nbt_name_register *io;
+       const char **wins_servers;
+       const char **addresses;
+       int address_idx;
+       struct nbt_name_request *req;
+};
+
+
+/*
+  state handler for WINS multi-homed multi-server name register
+*/
+static void name_register_wins_handler(struct nbt_name_request *req)
+{
+       struct composite_context *c = talloc_get_type(req->async.private, 
+                                                     struct composite_context);
+       struct register_wins_state *state = talloc_get_type(c->private, 
+                                                           struct register_wins_state);
+       NTSTATUS status;
+
+       status = nbt_name_register_recv(state->req, state, state->io);
+       if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+               /* the register timed out - try the next WINS server */
+               state->wins_servers++;
+               state->address_idx = 0;
+               if (state->wins_servers[0] == NULL) {
+                       c->state = SMBCLI_REQUEST_ERROR;
+                       c->status = status;
+                       goto done;
+               }
+               state->io->in.dest_addr = state->wins_servers[0];
+               state->io->in.address   = state->addresses[0];
+               state->req = nbt_name_register_send(state->nbtsock, state->io);
+               if (state->req == NULL) {
+                       c->state = SMBCLI_REQUEST_ERROR;
+                       c->status = NT_STATUS_NO_MEMORY;
+               } else {
+                       state->req->async.fn      = name_register_wins_handler;
+                       state->req->async.private = c;
+               }
+       } else if (!NT_STATUS_IS_OK(status)) {
+               c->state = SMBCLI_REQUEST_ERROR;
+               c->status = status;
+       } else {
+               if (state->io->out.rcode == 0 &&
+                   state->addresses[state->address_idx+1] != NULL) {
+                       /* register our next address */
+                       state->io->in.address = state->addresses[++(state->address_idx)];
+                       state->req = nbt_name_register_send(state->nbtsock, state->io);
+                       if (state->req == NULL) {
+                               c->state = SMBCLI_REQUEST_ERROR;
+                               c->status = NT_STATUS_NO_MEMORY;
+                       } else {
+                               state->req->async.fn      = name_register_wins_handler;
+                               state->req->async.private = c;
+                       }
+               } else {
+                       c->state = SMBCLI_REQUEST_DONE;
+                       c->status = NT_STATUS_OK;
+               }
+       }
+
+done:
+       if (c->state >= SMBCLI_REQUEST_DONE &&
+           c->async.fn) {
+               c->async.fn(c);
+       }
+}
+
+/*
+  the async send call for a multi-server WINS register
+*/
+struct composite_context *nbt_name_register_wins_send(struct nbt_name_socket *nbtsock,
+                                                     struct nbt_name_register_wins *io)
+{
+       struct composite_context *c;
+       struct register_wins_state *state;
+
+       c = talloc_zero(nbtsock, struct composite_context);
+       if (c == NULL) goto failed;
+
+       state = talloc(c, struct register_wins_state);
+       if (state == NULL) goto failed;
+
+       state->io = talloc(state, struct nbt_name_register);
+       if (state->io == NULL) goto failed;
+
+       state->wins_servers = str_list_copy(state, io->in.wins_servers);
+       if (state->wins_servers == NULL || 
+           state->wins_servers[0] == NULL) goto failed;
+
+       state->addresses = str_list_copy(state, io->in.addresses);
+       if (state->addresses == NULL || 
+           state->addresses[0] == NULL) goto failed;
+
+       state->io->in.name            = io->in.name;
+       state->io->in.dest_addr       = state->wins_servers[0];
+       state->io->in.address         = io->in.addresses[0];
+       state->io->in.nb_flags        = io->in.nb_flags;
+       state->io->in.broadcast       = False;
+       state->io->in.register_demand = False;
+       state->io->in.multi_homed     = (io->in.nb_flags & NBT_NM_GROUP)?False:True;
+       state->io->in.ttl             = io->in.ttl;
+       state->io->in.timeout         = 3;
+       state->io->in.retries         = 2;
+
+       state->nbtsock     = nbtsock;
+       state->address_idx = 0;
+
+       state->req = nbt_name_register_send(nbtsock, state->io);
+       if (state->req == NULL) goto failed;
+
+       state->req->async.fn      = name_register_wins_handler;
+       state->req->async.private = c;
+
+       c->private   = state;
+       c->state     = SMBCLI_REQUEST_SEND;
+       c->event_ctx = nbtsock->event_ctx;
+
+       return c;
+
+failed:
+       talloc_free(c);
+       return NULL;
+}
+
+/*
+  multi-homed WINS name register - recv side
+*/
+NTSTATUS nbt_name_register_wins_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
+                                    struct nbt_name_register_wins *io)
+{
+       NTSTATUS status;
+       status = composite_wait(c);
+       if (NT_STATUS_IS_OK(status)) {
+               struct register_wins_state *state = 
+                       talloc_get_type(c->private, struct register_wins_state);
+               io->out.wins_server = talloc_steal(mem_ctx, state->wins_servers[0]);
+               io->out.rcode = state->io->out.rcode;
+       }
+       talloc_free(c);
+       return status;
+}
+
+/*
+  multi-homed WINS register - sync interface
+*/
+NTSTATUS nbt_name_register_wins(struct nbt_name_socket *nbtsock,
+                               TALLOC_CTX *mem_ctx,
+                               struct nbt_name_register_wins *io)
+{
+       struct composite_context *c = nbt_name_register_wins_send(nbtsock, io);
+       return nbt_name_register_wins_recv(c, mem_ctx, io);
+}
index 38b356338cdeca1351b082e5521b6d5495b91105..c771d3b4f53ccbf51aa151288a516f32dee122a3 100644 (file)
@@ -82,10 +82,10 @@ static void nbt_name_socket_send(struct nbt_name_socket *nbtsock)
                }
 
                DLIST_REMOVE(nbtsock->send_queue, req);
+               req->state = NBT_REQUEST_WAIT;
                if (req->is_reply) {
                        talloc_free(req);
                } else {
-                       req->state = NBT_REQUEST_WAIT;
                        EVENT_FD_READABLE(nbtsock->fde);
                        nbtsock->num_pending++;
                }
@@ -122,7 +122,11 @@ static void nbt_name_socket_timeout(struct event_context *ev, struct timed_event
                req->te = event_add_timed(req->nbtsock->event_ctx, req, 
                                          timeval_add(&t, req->timeout, 0),
                                          nbt_name_socket_timeout, req);
-               DLIST_ADD_END(req->nbtsock->send_queue, req, struct nbt_name_request *);
+               if (req->state != NBT_REQUEST_SEND) {
+                       req->state = NBT_REQUEST_SEND;
+                       DLIST_ADD_END(req->nbtsock->send_queue, req, 
+                                     struct nbt_name_request *);
+               }
                EVENT_FD_WRITEABLE(req->nbtsock->fde);
                return;
        }
@@ -206,8 +210,12 @@ static void nbt_name_socket_recv(struct nbt_name_socket *nbtsock)
        /* find the matching request */
        req = idr_find(nbtsock->idr, packet->name_trn_id);
        if (req == NULL) {
-               DEBUG(2,("Failed to match request for incoming name packet id 0x%04x\n",
-                        packet->name_trn_id));
+               if (nbtsock->unexpected.handler) {
+                       nbtsock->unexpected.handler(nbtsock, packet, src_addr, src_port);
+               } else {
+                       DEBUG(2,("Failed to match request for incoming name packet id 0x%04x on %p\n",
+                                packet->name_trn_id, nbtsock));
+               }
                talloc_free(tmp_ctx);
                return;
        }
@@ -227,13 +235,11 @@ static void nbt_name_socket_recv(struct nbt_name_socket *nbtsock)
                req->num_retries   = 0;
                req->received_wack = True;
                if (packet->answers[0].ttl != 0) {
-                       req->timeout       = MIN(packet->answers[0].ttl, 20);
+                       req->timeout = MIN(packet->answers[0].ttl, 20);
                }
-               req->te            = event_add_timed(req->nbtsock->event_ctx, req, 
-                                                    timeval_current_ofs(req->timeout, 0),
-                                                    nbt_name_socket_timeout, req);
-               DLIST_ADD_END(req->nbtsock->send_queue, req, struct nbt_name_request *);
-               EVENT_FD_WRITEABLE(req->nbtsock->fde);
+               req->te = event_add_timed(req->nbtsock->event_ctx, req, 
+                                         timeval_current_ofs(req->timeout, 0),
+                                         nbt_name_socket_timeout, req);
                talloc_free(tmp_ctx);
                return;
        }
@@ -319,6 +325,7 @@ struct nbt_name_socket *nbt_name_socket_init(TALLOC_CTX *mem_ctx,
        nbtsock->send_queue = NULL;
        nbtsock->num_pending = 0;
        nbtsock->incoming.handler = NULL;
+       nbtsock->unexpected.handler = NULL;
 
        nbtsock->fde = event_add_fd(nbtsock->event_ctx, nbtsock, 
                                    socket_get_fd(nbtsock->sock), 0,
@@ -375,6 +382,7 @@ struct nbt_name_request *nbt_name_request_send(struct nbt_name_socket *nbtsock,
                                       UINT16_MAX);
        }
        if (id == -1) goto failed;
+
        request->name_trn_id = id;
        req->name_trn_id     = id;
 
index 08dde1f0183ed52212f306b6475b567072bad0a4..859cecd593fc952a061e73ef669f7d477ddade58 100644 (file)
@@ -26,11 +26,15 @@ interface nbt
 
        /* the opcodes are in the operation field, masked with
           NBT_OPCODE */
-        const int NBT_OPCODE_QUERY          =  (0<<11);
-       const int NBT_OPCODE_REGISTER       =  (5<<11);
-       const int NBT_OPCODE_RELEASE        =  (6<<11);
-       const int NBT_OPCODE_WACK           =  (7<<11);
-       const int NBT_OPCODE_REFRESH        =  (8<<11);
+       typedef enum {
+               NBT_OPCODE_QUERY          =  (0x0<<11),
+               NBT_OPCODE_REGISTER       =  (0x5<<11),
+               NBT_OPCODE_RELEASE        =  (0x6<<11),
+               NBT_OPCODE_WACK           =  (0x7<<11),
+               NBT_OPCODE_REFRESH        =  (0x8<<11),
+               NBT_OPCODE_REFRESH2       =  (0x9<<11),
+               NBT_OPCODE_MULTI_HOME_REG =  (0xf<<11)
+       } nbt_opcode;
 
        /* rcode values */
        typedef enum {