summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/include/structs.h1
-rw-r--r--source4/libcli/wrepl/winsrepl.c100
-rw-r--r--source4/libcli/wrepl/winsrepl.h14
-rw-r--r--source4/torture/nbt/winsreplication.c40
4 files changed, 137 insertions, 18 deletions
diff --git a/source4/include/structs.h b/source4/include/structs.h
index 582aee1332..20b8cfa721 100644
--- a/source4/include/structs.h
+++ b/source4/include/structs.h
@@ -268,6 +268,7 @@ struct ads_struct;
struct wrepl_packet;
struct wrepl_associate;
+struct wrepl_associate_stop;
struct wrepl_pull_table;
struct wrepl_pull_names;
diff --git a/source4/libcli/wrepl/winsrepl.c b/source4/libcli/wrepl/winsrepl.c
index 297dccbf38..31ef1ffbeb 100644
--- a/source4/libcli/wrepl/winsrepl.c
+++ b/source4/libcli/wrepl/winsrepl.c
@@ -31,6 +31,7 @@
*/
static void wrepl_socket_dead(struct wrepl_socket *wrepl_socket, NTSTATUS status)
{
+ talloc_set_destructor(wrepl_socket, NULL);
wrepl_socket->dead = True;
if (wrepl_socket->fde) {
@@ -96,9 +97,31 @@ static void wrepl_handler_send(struct wrepl_socket *wrepl_socket)
return;
}
- DLIST_REMOVE(wrepl_socket->send_queue, req);
- DLIST_ADD_END(wrepl_socket->recv_queue, req, struct wrepl_request *);
- req->state = WREPL_REQUEST_RECV;
+ if (req->disconnect_after_send) {
+ DLIST_REMOVE(wrepl_socket->send_queue, req);
+ req->status = NT_STATUS_OK;
+ req->state = WREPL_REQUEST_DONE;
+ wrepl_socket_dead(wrepl_socket, NT_STATUS_LOCAL_DISCONNECT);
+ if (req->async.fn) {
+ req->async.fn(req);
+ }
+ return;
+ }
+
+ if (req->send_only) {
+ DLIST_REMOVE(wrepl_socket->send_queue, req);
+ req->status = NT_STATUS_OK;
+ req->state = WREPL_REQUEST_DONE;
+ if (req->async.fn) {
+ EVENT_FD_READABLE(wrepl_socket->fde);
+ req->async.fn(req);
+ return;
+ }
+ } else {
+ DLIST_REMOVE(wrepl_socket->send_queue, req);
+ DLIST_ADD_END(wrepl_socket->recv_queue, req, struct wrepl_request *);
+ req->state = WREPL_REQUEST_RECV;
+ }
EVENT_FD_READABLE(wrepl_socket->fde);
}
@@ -289,7 +312,7 @@ failed:
static int wrepl_socket_destructor(void *ptr)
{
struct wrepl_socket *sock = talloc_get_type(ptr, struct wrepl_socket);
- wrepl_socket_dead(sock, NT_STATUS_CONNECTION_DISCONNECTED);
+ wrepl_socket_dead(sock, NT_STATUS_LOCAL_DISCONNECT);
return 0;
}
@@ -415,7 +438,7 @@ static NTSTATUS wrepl_request_wait(struct wrepl_request *req)
connect a wrepl_socket to a WINS server
*/
struct wrepl_request *wrepl_connect_send(struct wrepl_socket *wrepl_socket,
- const char *address)
+ const char *our_ip, const char *peer_ip)
{
struct wrepl_request *req;
NTSTATUS status;
@@ -429,8 +452,12 @@ struct wrepl_request *wrepl_connect_send(struct wrepl_socket *wrepl_socket,
DLIST_ADD(wrepl_socket->recv_queue, req);
talloc_set_destructor(req, wrepl_request_destructor);
-
- status = socket_connect(wrepl_socket->sock, iface_best_ip(address), 0, address,
+
+ if (!our_ip) {
+ our_ip = iface_best_ip(peer_ip);
+ }
+
+ status = socket_connect(wrepl_socket->sock, our_ip, 0, peer_ip,
WINS_REPLICATION_PORT, 0);
if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) goto failed;
@@ -453,9 +480,9 @@ NTSTATUS wrepl_connect_recv(struct wrepl_request *req)
/*
connect a wrepl_socket to a WINS server - sync API
*/
-NTSTATUS wrepl_connect(struct wrepl_socket *wrepl_socket, const char *address)
+NTSTATUS wrepl_connect(struct wrepl_socket *wrepl_socket, const char *our_ip, const char *peer_ip)
{
- struct wrepl_request *req = wrepl_connect_send(wrepl_socket, address);
+ struct wrepl_request *req = wrepl_connect_send(wrepl_socket, our_ip, peer_ip);
return wrepl_connect_recv(req);
}
@@ -619,6 +646,59 @@ NTSTATUS wrepl_associate(struct wrepl_socket *wrepl_socket,
/*
+ stop an association - send
+*/
+struct wrepl_request *wrepl_associate_stop_send(struct wrepl_socket *wrepl_socket,
+ struct wrepl_associate_stop *io)
+{
+ struct wrepl_packet *packet;
+ struct wrepl_request *req;
+
+ packet = talloc_zero(wrepl_socket, struct wrepl_packet);
+ if (packet == NULL) return NULL;
+
+ packet->opcode = WREPL_OPCODE_BITS;
+ packet->assoc_ctx = io->in.assoc_ctx;
+ packet->mess_type = WREPL_STOP_ASSOCIATION;
+ packet->message.stop.reason = io->in.reason;
+
+ req = wrepl_request_send(wrepl_socket, packet);
+
+ if (req && io->in.reason == 0) {
+ req->send_only = True;
+ req->disconnect_after_send = True;
+ }
+
+ talloc_free(packet);
+
+ return req;
+}
+
+/*
+ stop an association - recv
+*/
+NTSTATUS wrepl_associate_stop_recv(struct wrepl_request *req,
+ struct wrepl_associate_stop *io)
+{
+ struct wrepl_packet *packet=NULL;
+ NTSTATUS status;
+ status = wrepl_request_recv(req, req->wrepl_socket, &packet);
+ NT_STATUS_NOT_OK_RETURN(status);
+ talloc_free(packet);
+ return status;
+}
+
+/*
+ setup an association - sync api
+*/
+NTSTATUS wrepl_associate_stop(struct wrepl_socket *wrepl_socket,
+ struct wrepl_associate_stop *io)
+{
+ struct wrepl_request *req = wrepl_associate_stop_send(wrepl_socket, io);
+ return wrepl_associate_stop_recv(req, io);
+}
+
+/*
fetch the partner tables - send
*/
struct wrepl_request *wrepl_pull_table_send(struct wrepl_socket *wrepl_socket,
@@ -735,8 +815,6 @@ NTSTATUS wrepl_pull_names_recv(struct wrepl_request *req,
io->out.num_names = packet->message.replication.info.reply.num_names;
- status = NT_STATUS_NO_MEMORY;
-
io->out.names = talloc_array(packet, struct wrepl_name, io->out.num_names);
if (io->out.names == NULL) goto nomem;
diff --git a/source4/libcli/wrepl/winsrepl.h b/source4/libcli/wrepl/winsrepl.h
index e78f0464e7..89a4c642b2 100644
--- a/source4/libcli/wrepl/winsrepl.h
+++ b/source4/libcli/wrepl/winsrepl.h
@@ -69,6 +69,10 @@ struct wrepl_request {
DATA_BLOB buffer;
+ BOOL disconnect_after_send;
+
+ BOOL send_only;
+
size_t num_read;
struct timed_event *te;
@@ -92,6 +96,16 @@ struct wrepl_associate {
};
/*
+ setup an association
+*/
+struct wrepl_associate_stop {
+ struct {
+ uint32_t assoc_ctx;
+ uint32_t reason;
+ } in;
+};
+
+/*
pull the partner table
*/
struct wrepl_pull_table {
diff --git a/source4/torture/nbt/winsreplication.c b/source4/torture/nbt/winsreplication.c
index 68961ab180..e72ba9c8d6 100644
--- a/source4/torture/nbt/winsreplication.c
+++ b/source4/torture/nbt/winsreplication.c
@@ -53,18 +53,20 @@ static BOOL test_assoc_ctx1(TALLOC_CTX *mem_ctx, const char *address)
struct wrepl_socket *wrepl_socket2;
struct wrepl_associate associate2;
struct wrepl_pull_table pull_table;
+ struct wrepl_packet *rep_packet;
+ struct wrepl_associate_stop assoc_stop;
NTSTATUS status;
printf("Test if assoc_ctx is only valid on the conection it was created on\n");
wrepl_socket1 = wrepl_socket_init(mem_ctx, NULL);
wrepl_socket2 = wrepl_socket_init(mem_ctx, NULL);
-
+
printf("Setup 2 wrepl connections\n");
- status = wrepl_connect(wrepl_socket1, address);
+ status = wrepl_connect(wrepl_socket1, NULL, address);
CHECK_STATUS(status, NT_STATUS_OK);
- status = wrepl_connect(wrepl_socket2, address);
+ status = wrepl_connect(wrepl_socket2, NULL, address);
CHECK_STATUS(status, NT_STATUS_OK);
printf("Send a start association request (conn1)\n");
@@ -79,15 +81,39 @@ static BOOL test_assoc_ctx1(TALLOC_CTX *mem_ctx, const char *address)
printf("association context (conn2): 0x%x\n", associate2.out.assoc_ctx);
- printf("Send a replication table query, with assoc 1 (conn2), should be ignored\n");
+ printf("Send a replication table query, with assoc 1 (conn2), the anwser should be on conn1\n");
pull_table.in.assoc_ctx = associate1.out.assoc_ctx;
req = wrepl_pull_table_send(wrepl_socket2, &pull_table);
- talloc_free(req);
+ req->send_only = True;
+ status = wrepl_request_recv(req, mem_ctx, &rep_packet);
+ CHECK_STATUS(status, NT_STATUS_OK);
printf("Send a association request (conn2), to make sure the last request was ignored\n");
status = wrepl_associate(wrepl_socket2, &associate2);
CHECK_STATUS(status, NT_STATUS_OK);
+ printf("Send a replication table query, with invalid assoc (conn1), receive answer from conn2\n");
+ pull_table.in.assoc_ctx = 0;
+ req = wrepl_pull_table_send(wrepl_socket1, &pull_table);
+ status = wrepl_request_recv(req, mem_ctx, &rep_packet);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ printf("Send a association request (conn1), to make sure the last request was handled correct\n");
+ status = wrepl_associate(wrepl_socket1, &associate2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ assoc_stop.in.assoc_ctx = associate1.out.assoc_ctx;
+ assoc_stop.in.reason = 4;
+ printf("Send a association stop request (conn1), reson: %u\n", assoc_stop.in.reason);
+ status = wrepl_associate_stop(wrepl_socket1, &assoc_stop);
+ CHECK_STATUS(status, NT_STATUS_END_OF_FILE);
+
+ assoc_stop.in.assoc_ctx = associate2.out.assoc_ctx;
+ assoc_stop.in.reason = 0;
+ printf("Send a association stop request (conn2), reson: %u\n", assoc_stop.in.reason);
+ status = wrepl_associate_stop(wrepl_socket2, &assoc_stop);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
done:
printf("Close 2 wrepl connections\n");
talloc_free(wrepl_socket1);
@@ -111,7 +137,7 @@ static BOOL test_assoc_ctx2(TALLOC_CTX *mem_ctx, const char *address)
wrepl_socket = wrepl_socket_init(mem_ctx, NULL);
printf("Setup wrepl connections\n");
- status = wrepl_connect(wrepl_socket, address);
+ status = wrepl_connect(wrepl_socket, NULL, address);
CHECK_STATUS(status, NT_STATUS_OK);
@@ -175,7 +201,7 @@ static BOOL test_wins_replication(TALLOC_CTX *mem_ctx, const char *address)
wrepl_socket = wrepl_socket_init(mem_ctx, NULL);
printf("Setup wrepl connections\n");
- status = wrepl_connect(wrepl_socket, address);
+ status = wrepl_connect(wrepl_socket, NULL, address);
CHECK_STATUS(status, NT_STATUS_OK);
printf("Send a start association request\n");