summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
Diffstat (limited to 'source4')
-rw-r--r--source4/auth/kerberos/SConscript6
-rw-r--r--source4/auth/ntlmssp/SConscript5
-rw-r--r--source4/dsdb/SConscript1
-rw-r--r--source4/include/structs.h6
-rw-r--r--source4/lib/charset/SConscript1
-rw-r--r--source4/lib/popt/SConscript1
-rw-r--r--source4/lib/replace/SConscript1
-rw-r--r--source4/lib/socket/SConscript1
-rw-r--r--source4/lib/socket_wrapper/SConscript1
-rw-r--r--source4/libcli/SConscript1
-rw-r--r--source4/libcli/auth/SConscript3
-rw-r--r--source4/libcli/ldap/SConscript5
-rw-r--r--source4/libcli/security/SConscript5
-rw-r--r--source4/librpc/SConscript1
-rw-r--r--source4/nbt_server/defense.c14
-rw-r--r--source4/nbt_server/nodestatus.c6
-rw-r--r--source4/nbt_server/query.c6
-rw-r--r--source4/nbt_server/wins/winsdb.c343
-rw-r--r--source4/nbt_server/wins/winsdb.h12
-rw-r--r--source4/nbt_server/wins/winsserver.c40
-rw-r--r--source4/pidl/lib/Parse/Pidl/Ethereal/NDR.pm1
-rw-r--r--source4/torture/nbt/dgram.c4
-rw-r--r--source4/wrepl_server/config.mk4
-rw-r--r--source4/wrepl_server/wrepl_in_call.c258
-rw-r--r--source4/wrepl_server/wrepl_in_connection.c44
-rw-r--r--source4/wrepl_server/wrepl_out_connection.c212
-rw-r--r--source4/wrepl_server/wrepl_server.c77
-rw-r--r--source4/wrepl_server/wrepl_server.h64
28 files changed, 681 insertions, 442 deletions
diff --git a/source4/auth/kerberos/SConscript b/source4/auth/kerberos/SConscript
index 8272f1c24a..e69de29bb2 100644
--- a/source4/auth/kerberos/SConscript
+++ b/source4/auth/kerberos/SConscript
@@ -1,6 +0,0 @@
-Import('hostenv')
-
-hostenv.StaticLibrary('kerberos',
- ['kerberos.c','clikrb5.c','kerberos_verify.c',
- 'kerberos_util.c','kerberos_pac.c','gssapi_parse.c',
- 'krb5_init_context.c'])
diff --git a/source4/auth/ntlmssp/SConscript b/source4/auth/ntlmssp/SConscript
index 1fb21c02cd..e69de29bb2 100644
--- a/source4/auth/ntlmssp/SConscript
+++ b/source4/auth/ntlmssp/SConscript
@@ -1,5 +0,0 @@
-Import('hostenv')
-
-hostenv.StaticLibrary('gensec_ntlmssp',
- ['ntlmssp_parse.c','ntlmssp.c','ntlmssp_sign.c','ntlmssp_client.c',
- 'ntlmssp_server.c'])
diff --git a/source4/dsdb/SConscript b/source4/dsdb/SConscript
index 9f73bc7673..cdbf146149 100644
--- a/source4/dsdb/SConscript
+++ b/source4/dsdb/SConscript
@@ -1,4 +1,5 @@
Import('hostenv')
+
dsdb_ldb_modules = []
dsdb_ldb_modules.append(
diff --git a/source4/include/structs.h b/source4/include/structs.h
index 2da6205ba8..68cae5d256 100644
--- a/source4/include/structs.h
+++ b/source4/include/structs.h
@@ -277,9 +277,13 @@ struct wreplsrv_partner;
struct wreplsrv_owner;
struct wreplsrv_in_connection;
struct wreplsrv_in_call;
+struct wreplsrv_out_connection;
+struct wreplsrv_pull_table_io;
+struct wreplsrv_pull_names_io;
+struct wreplsrv_pull_cycle_io;
+struct wreplsrv_push_notify_io;
struct winsdb_record;
-struct winsdb_addr;
struct wrepl_packet;
struct wrepl_associate;
diff --git a/source4/lib/charset/SConscript b/source4/lib/charset/SConscript
index 15ee49909c..9bc474ff48 100644
--- a/source4/lib/charset/SConscript
+++ b/source4/lib/charset/SConscript
@@ -1,6 +1,7 @@
#!/usr/bin/env python
# tastes like -*- python -*-
+Import('hostenv')
def _CheckIconvPath(context,path):
# Some systems have iconv in libc, some have it in libiconv (OSF/1 and
diff --git a/source4/lib/popt/SConscript b/source4/lib/popt/SConscript
index 64faff772c..d9a576a031 100644
--- a/source4/lib/popt/SConscript
+++ b/source4/lib/popt/SConscript
@@ -1,4 +1,3 @@
-Import('hostenv')
# tastes like -*- python -*-
Import('hostenv')
diff --git a/source4/lib/replace/SConscript b/source4/lib/replace/SConscript
index 948c33bdc0..cf28102175 100644
--- a/source4/lib/replace/SConscript
+++ b/source4/lib/replace/SConscript
@@ -1,6 +1,5 @@
#!/usr/bin/env python
Import('hostenv defines')
-conf = Configure(hostenv)
rep_files = ['replace.c', 'snprintf.c','dlfcn.c']
diff --git a/source4/lib/socket/SConscript b/source4/lib/socket/SConscript
index 14080fa1b0..73c7eeeeac 100644
--- a/source4/lib/socket/SConscript
+++ b/source4/lib/socket/SConscript
@@ -1,5 +1,6 @@
#!/usr/bin/env python
Import('hostenv defines')
+
if hostenv['configure']:
conf = hostenv.Configure()
for h in ['sys/socket.h','sys/sockio.h','sys/un.h']:
diff --git a/source4/lib/socket_wrapper/SConscript b/source4/lib/socket_wrapper/SConscript
index ab08e3af73..248922bcd7 100644
--- a/source4/lib/socket_wrapper/SConscript
+++ b/source4/lib/socket_wrapper/SConscript
@@ -1,4 +1,5 @@
Import('hostenv')
+
opts = Options(None, ARGUMENTS)
opts.AddOptions(
BoolOption('socket_wrapper','enable socket wrapper',0)
diff --git a/source4/libcli/SConscript b/source4/libcli/SConscript
index 98847d9336..5b600fdcff 100644
--- a/source4/libcli/SConscript
+++ b/source4/libcli/SConscript
@@ -1,4 +1,5 @@
Import('hostenv')
+
hostenv.Subsystem(
'cli_utils',
['util/asn1.c',
diff --git a/source4/libcli/auth/SConscript b/source4/libcli/auth/SConscript
index d527faac30..e69de29bb2 100644
--- a/source4/libcli/auth/SConscript
+++ b/source4/libcli/auth/SConscript
@@ -1,3 +0,0 @@
-Import('hostenv')
-
-hostenv.StaticLibrary('cli_auth',['credentials.c','session.c','smbencrypt.c'])
diff --git a/source4/libcli/ldap/SConscript b/source4/libcli/ldap/SConscript
index eef9a9f41c..e69de29bb2 100644
--- a/source4/libcli/ldap/SConscript
+++ b/source4/libcli/ldap/SConscript
@@ -1,5 +0,0 @@
-Import('hostenv')
-
-hostenv.StaticLibrary('cli_ldap',
- ['ldap.c','ldap_client.c','ldap_bind.c','ldap_msg.c','ldap_ndr.c',
- 'ldap_ildap.c'])
diff --git a/source4/libcli/security/SConscript b/source4/libcli/security/SConscript
index e81051e07e..e69de29bb2 100644
--- a/source4/libcli/security/SConscript
+++ b/source4/libcli/security/SConscript
@@ -1,5 +0,0 @@
-Import('hostenv')
-
-hostenv.StaticLibrary('cli_security',
- ['security_token.c','security_descriptor.c','dom_sid.c',
- 'access_check.c','privilege.c'])
diff --git a/source4/librpc/SConscript b/source4/librpc/SConscript
index 059efab51a..083a84fc36 100644
--- a/source4/librpc/SConscript
+++ b/source4/librpc/SConscript
@@ -1,5 +1,6 @@
#!/usr/bin/python
Import('hostenv')
+
ndr_base_files = ['ndr/ndr.c', 'ndr/ndr_basic.c', 'ndr/ndr_string.c',
'ndr/ndr_obfuscate.c', 'ndr/ndr_misc.c']
diff --git a/source4/nbt_server/defense.c b/source4/nbt_server/defense.c
index 55a345e18d..0819fd4f2f 100644
--- a/source4/nbt_server/defense.c
+++ b/source4/nbt_server/defense.c
@@ -39,17 +39,17 @@ void nbtd_request_defense(struct nbt_name_socket *nbtsock,
struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
struct nbtd_interface);
- NBTD_ASSERT_PACKET(packet, src->addr, packet->qdcount == 1);
- NBTD_ASSERT_PACKET(packet, src->addr, packet->arcount == 1);
- NBTD_ASSERT_PACKET(packet, src->addr,
+ NBTD_ASSERT_PACKET(packet, src, packet->qdcount == 1);
+ NBTD_ASSERT_PACKET(packet, src, packet->arcount == 1);
+ NBTD_ASSERT_PACKET(packet, src,
packet->questions[0].question_type == NBT_QTYPE_NETBIOS);
- NBTD_ASSERT_PACKET(packet, src->addr,
+ NBTD_ASSERT_PACKET(packet, src,
packet->questions[0].question_class == NBT_QCLASS_IP);
- NBTD_ASSERT_PACKET(packet, src->addr,
+ NBTD_ASSERT_PACKET(packet, src,
packet->additional[0].rr_type == NBT_QTYPE_NETBIOS);
- NBTD_ASSERT_PACKET(packet, src->addr,
+ NBTD_ASSERT_PACKET(packet, src,
packet->additional[0].rr_class == NBT_QCLASS_IP);
- NBTD_ASSERT_PACKET(packet, src->addr,
+ NBTD_ASSERT_PACKET(packet, src,
packet->additional[0].rdata.netbios.length == 6);
/* see if we have the requested name on this interface */
diff --git a/source4/nbt_server/nodestatus.c b/source4/nbt_server/nodestatus.c
index ccbdc2b933..efd4720790 100644
--- a/source4/nbt_server/nodestatus.c
+++ b/source4/nbt_server/nodestatus.c
@@ -106,9 +106,9 @@ void nbtd_query_status(struct nbt_name_socket *nbtsock,
struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
struct nbtd_interface);
- NBTD_ASSERT_PACKET(packet, src->addr, packet->qdcount == 1);
- NBTD_ASSERT_PACKET(packet, src->addr, packet->questions[0].question_type == NBT_QTYPE_STATUS);
- NBTD_ASSERT_PACKET(packet, src->addr, packet->questions[0].question_class == NBT_QCLASS_IP);
+ NBTD_ASSERT_PACKET(packet, src, packet->qdcount == 1);
+ NBTD_ASSERT_PACKET(packet, src, packet->questions[0].question_type == NBT_QTYPE_STATUS);
+ NBTD_ASSERT_PACKET(packet, src, packet->questions[0].question_class == NBT_QCLASS_IP);
/* see if we have the requested name on this interface */
name = &packet->questions[0].name;
diff --git a/source4/nbt_server/query.c b/source4/nbt_server/query.c
index c64ac5986a..1d8a610750 100644
--- a/source4/nbt_server/query.c
+++ b/source4/nbt_server/query.c
@@ -45,10 +45,10 @@ void nbtd_request_query(struct nbt_name_socket *nbtsock,
return;
}
- NBTD_ASSERT_PACKET(packet, src->addr, packet->qdcount == 1);
- NBTD_ASSERT_PACKET(packet, src->addr,
+ NBTD_ASSERT_PACKET(packet, src, packet->qdcount == 1);
+ NBTD_ASSERT_PACKET(packet, src,
packet->questions[0].question_type == NBT_QTYPE_NETBIOS);
- NBTD_ASSERT_PACKET(packet, src->addr,
+ NBTD_ASSERT_PACKET(packet, src,
packet->questions[0].question_class == NBT_QCLASS_IP);
/* see if we have the requested name on this interface */
diff --git a/source4/nbt_server/wins/winsdb.c b/source4/nbt_server/wins/winsdb.c
index 50baa50898..7ab8216837 100644
--- a/source4/nbt_server/wins/winsdb.c
+++ b/source4/nbt_server/wins/winsdb.c
@@ -33,6 +33,7 @@
*/
static uint64_t winsdb_allocate_version(struct wins_server *winssrv)
{
+ int trans;
int ret;
struct ldb_context *ldb = winssrv->wins_db;
struct ldb_dn *dn;
@@ -41,12 +42,21 @@ static uint64_t winsdb_allocate_version(struct wins_server *winssrv)
TALLOC_CTX *tmp_ctx = talloc_new(winssrv);
uint64_t maxVersion = 0;
- dn = ldb_dn_explode(tmp_ctx, "CN=VERSION");
- if (!dn) goto failed;
+ trans = ldb_transaction_start(ldb);
+ if (trans != LDB_SUCCESS) goto failed;
dn = ldb_dn_explode(tmp_ctx, "CN=VERSION");
if (!dn) goto failed;
+ /* find the record in the WINS database */
+ ret = ldb_search(ldb, dn, LDB_SCOPE_BASE,
+ NULL, NULL, &res);
+ if (res != NULL) {
+ talloc_steal(tmp_ctx, res);
+ }
+ if (ret < 0) goto failed;
+ if (ret > 1) goto failed;
+
if (ret == 1) {
maxVersion = ldb_msg_find_uint64(res[0], "maxVersion", 0);
}
@@ -57,22 +67,27 @@ static uint64_t winsdb_allocate_version(struct wins_server *winssrv)
msg->dn = dn;
- ret = ldb_msg_add_empty(ldb, msg, "maxVersion", LDB_FLAG_MOD_REPLACE);
+ ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE);
+ if (ret != 0) goto failed;
+ ret = ldb_msg_add_string(msg, "objectClass", "winsMaxVersion");
+ if (ret != 0) goto failed;
+ ret = ldb_msg_add_empty(msg, "maxVersion", LDB_FLAG_MOD_REPLACE);
if (ret != 0) goto failed;
- ret = ldb_msg_add_fmt(ldb, msg, "maxVersion", "%llu", maxVersion);
+ ret = ldb_msg_add_fmt(msg, "maxVersion", "%llu", maxVersion);
if (ret != 0) goto failed;
ret = ldb_modify(ldb, msg);
if (ret != 0) ret = ldb_add(ldb, msg);
if (ret != 0) goto failed;
- talloc_free(tmp_ctx);
- return maxVersion;
+ trans = ldb_transaction_commit(ldb);
+ if (trans != LDB_SUCCESS) goto failed;
talloc_free(tmp_ctx);
return maxVersion;
failed:
+ if (trans == LDB_SUCCESS) ldb_transaction_cancel(ldb);
talloc_free(tmp_ctx);
return 0;
}
@@ -172,177 +187,11 @@ static NTSTATUS winsdb_addr_decode(struct winsdb_record *rec, struct ldb_val *va
if (!p) {
/* support old entries, with only the address */
addr->address = talloc_steal(addr, val->data);
- addr->wins_owner = rec->wins_owner;
- addr->expire_time = rec->expire_time;
- *_addr = addr;
- return NT_STATUS_OK;
- }
-
- *p = '\0';p++;
- addr->address = talloc_strdup(addr, address);
- if (!addr->address) {
- status = NT_STATUS_NO_MEMORY;
- goto failed;
- }
-
- if (strncmp("winsOwner:", p, 10) != 0) {
- status = NT_STATUS_INTERNAL_DB_CORRUPTION;
- goto failed;
- }
- wins_owner = p + 10;
- p = strchr(wins_owner, ';');
- if (!p) {
- status = NT_STATUS_INTERNAL_DB_CORRUPTION;
- goto failed;
- }
-
- *p = '\0';p++;
- addr->wins_owner = talloc_strdup(addr, wins_owner);
- if (!addr->wins_owner) {
- status = NT_STATUS_NO_MEMORY;
- goto failed;
- }
-
- if (strncmp("expireTime:", p, 11) != 0) {
- status = NT_STATUS_INTERNAL_DB_CORRUPTION;
- goto failed;
- }
-
- expire_time = p + 11;
- p = strchr(expire_time, ';');
- if (!p) {
- status = NT_STATUS_INTERNAL_DB_CORRUPTION;
- goto failed;
- }
-
- *p = '\0';p++;
- addr->expire_time = ldap_string_to_time(expire_time);
-
- *_addr = addr;
- return NT_STATUS_OK;
-failed:
- talloc_free(addr);
- return status;
-}
-
-/*
- encode the winsdb_addr("address") attribute like this:
- "172.31.1.1;winsOwner:172.31.9.202;expireTime:20050923032330.0Z"
-*/
-static int ldb_msg_add_winsdb_addr(struct ldb_context *ldb, struct ldb_message *msg,
- const char *attr_name, struct winsdb_addr *addr)
-{
- struct ldb_val val;
- const char *str;
-
- dn = ldb_dn_string_compose(mem_ctx, NULL, "type=%02x", name->type);
-
- addresses[len]->address = talloc_strdup(addresses[len], address);
- if (!addresses[len]->address) {
- talloc_free(addresses);
- return NULL;
- }
-
- addresses[len]->wins_owner = talloc_strdup(addresses[len], wins_owner);
- if (!addresses[len]->wins_owner) {
- talloc_free(addresses);
- return NULL;
- }
-
- addresses[len]->expire_time = expire_time;
-
- addresses[len+1] = NULL;
-
- return addresses;
-}
-
-void winsdb_addr_list_remove(struct winsdb_addr **addresses, const char *address)
-{
- size_t i;
-
- for (i=0; addresses[i]; i++) {
- if (strcmp(addresses[i]->address, address) == 0) {
- break;
- }
- }
- if (!addresses[i]) return;
-
- for (; addresses[i]; i++) {
- addresses[i] = addresses[i+1];
- }
-
- return;
-}
-
-struct winsdb_addr *winsdb_addr_list_check(struct winsdb_addr **addresses, const char *address)
-{
- size_t i;
-
- for (i=0; addresses[i]; i++) {
- if (strcmp(addresses[i]->address, address) == 0) {
- return addresses[i];
- }
- }
-
- return NULL;
-}
-
-size_t winsdb_addr_list_length(struct winsdb_addr **addresses)
-{
- size_t i;
- for (i=0; addresses[i]; i++);
- return i;
-}
-
-const char **winsdb_addr_string_list(TALLOC_CTX *mem_ctx, struct winsdb_addr **addresses)
-{
- size_t len = winsdb_addr_list_length(addresses);
- const char **str_list;
- size_t i;
-
- str_list = talloc_array(mem_ctx, const char *, len + 1);
- if (!str_list) return NULL;
-
- for (i=0; i < len; i++) {
- str_list[i] = talloc_strdup(str_list, addresses[i]->address);
- if (!str_list[i]) {
- talloc_free(str_list);
- return NULL;
+ addr->wins_owner = talloc_reference(addr, rec->wins_owner);
+ if (!addr->wins_owner) {
+ status = NT_STATUS_NO_MEMORY;
+ goto failed;
}
- }
-
- str_list[len] = NULL;
- return str_list;
-}
-
-/*
- decode the winsdb_addr("address") attribute:
- "172.31.1.1" or
- "172.31.1.1;winsOwner:172.31.9.202;expireTime:20050923032330.0Z"
- are valid records
-*/
-static struct winsdb_addr *winsdb_addr_decode(struct winsdb_record *rec, TALLOC_CTX *mem_ctx, struct ldb_val *val)
-{
- NTSTATUS status;
- struct winsdb_addr *addr;
- char *address;
- char *wins_owner;
- char *expire_time;
- char *p;
-
- addr = talloc(mem_ctx, struct winsdb_addr);
- if (!addr) {
- status = NT_STATUS_NO_MEMORY;
- goto failed;
- }
-
- address = (char *)val->data;
-
- p = strchr(address, ';');
- if (!p) {
- /* support old entries, with only the address */
- addr->address = talloc_steal(addr, val->data);
- addr->wins_owner = rec->wins_owner;
addr->expire_time = rec->expire_time;
*_addr = addr;
return NT_STATUS_OK;
@@ -386,7 +235,7 @@ static struct winsdb_addr *winsdb_addr_decode(struct winsdb_record *rec, TALLOC_
}
*p = '\0';p++;
- addr->expire_time = ldap_string_to_time(expire_time);
+ addr->expire_time = ldb_string_to_time(expire_time);
*_addr = addr;
return NT_STATUS_OK;
@@ -399,7 +248,7 @@ failed:
encode the winsdb_addr("address") attribute like this:
"172.31.1.1;winsOwner:172.31.9.202;expireTime:20050923032330.0Z;"
*/
-static int ldb_msg_add_winsdb_addr(struct ldb_context *ldb, struct ldb_message *msg,
+static int ldb_msg_add_winsdb_addr(struct ldb_message *msg,
const char *attr_name, struct winsdb_addr *addr)
{
struct ldb_val val;
@@ -407,13 +256,13 @@ static int ldb_msg_add_winsdb_addr(struct ldb_context *ldb, struct ldb_message *
str = talloc_asprintf(msg, "%s;winsOwner:%s;expireTime:%s;",
addr->address, addr->wins_owner,
- ldap_timestring(msg, addr->expire_time));
+ ldb_timestring(msg, addr->expire_time));
if (!str) return -1;
val.data = discard_const_p(uint8_t, str);
val.length = strlen(str);
- return ldb_msg_add_value(ldb, msg, attr_name, &val);
+ return ldb_msg_add_value(msg, attr_name, &val);
}
struct winsdb_addr **winsdb_addr_list_make(TALLOC_CTX *mem_ctx)
@@ -552,11 +401,11 @@ NTSTATUS winsdb_lookup(struct ldb_context *wins_db,
if (!NT_STATUS_IS_OK(status)) goto failed;
/* see if it has already expired */
- if (rec->state == WINS_REC_ACTIVE &&
+ if (rec->state == WREPL_STATE_ACTIVE &&
rec->expire_time <= time(NULL)) {
DEBUG(5,("WINS: expiring name %s (expired at %s)\n",
nbt_name_string(tmp_ctx, rec->name), timestring(tmp_ctx, rec->expire_time)));
- rec->state = WINS_REC_RELEASED;
+ rec->state = WREPL_STATE_RELEASED;
}
talloc_steal(mem_ctx, rec);
@@ -587,69 +436,35 @@ NTSTATUS winsdb_record(struct ldb_message *msg, struct nbt_name *name, TALLOC_CT
if (!NT_STATUS_IS_OK(status)) goto failed;
}
- /* parse it into a more convenient winsdb_record structure */
- rec->name = name;
- rec->state = ldb_msg_find_int(res[0], "active", WINS_REC_RELEASED);
- rec->nb_flags = ldb_msg_find_int(res[0], "nbFlags", 0);
- rec->expire_time = ldb_string_to_time(ldb_msg_find_string(res[0], "expires", NULL));
- rec->registered_by = ldb_msg_find_string(res[0], "registeredBy", NULL);
- rec->version = ldb_msg_find_uint64(res[0], "version", 0);
- talloc_steal(rec, rec->wins_owner);
- talloc_steal(rec, rec->registered_by);
-
- if (!rec->wins_owner) rec->wins_owner = WINSDB_OWNER_LOCAL;
-
- el = ldb_msg_find_element(msg, "address");
- if (el == NULL) {
+ if (strlen(name->name) > 15) {
status = NT_STATUS_INTERNAL_DB_CORRUPTION;
goto failed;
}
-
- rec->addresses = talloc_array(rec, struct winsdb_addr *, el->num_values+1);
- if (rec->addresses == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto failed;
- }
-
- for (i=0;i<el->num_values;i++) {
- status = winsdb_addr_decode(rec, &el->values[i], rec->addresses, &rec->addresses[i]);
- if (!NT_STATUS_IS_OK(status)) goto failed;
- }
- rec->addresses[i] = NULL;
-
- *_rec = rec;
- return NT_STATUS_OK;
-failed:
- if (NT_STATUS_EQUAL(NT_STATUS_INTERNAL_DB_CORRUPTION, status)) {
- DEBUG(1,("winsdb_record: corrupted record: %s\n", ldb_dn_linearize(rec, msg->dn)));
- }
- talloc_free(rec);
- return status;
-}
-
- rec = talloc(mem_ctx, struct winsdb_record);
- if (rec == NULL) {
- status = NT_STATUS_NO_MEMORY;
+ if (name->scope && strlen(name->scope) > 238) {
+ status = NT_STATUS_INTERNAL_DB_CORRUPTION;
goto failed;
}
- if (!name) {
- status = winsdb_nbt_name(rec, msg->dn, &name);
- if (!NT_STATUS_IS_OK(status)) goto failed;
- }
-
/* parse it into a more convenient winsdb_record structure */
- rec->name = name;
- rec->state = ldb_msg_find_int(msg, "state", WINS_REC_RELEASED);
- rec->nb_flags = ldb_msg_find_int(msg, "nbFlags", 0);
- rec->wins_owner = ldb_msg_find_string(msg, "winsOwner", NULL);
- rec->expire_time = ldap_string_to_time(ldb_msg_find_string(msg, "expireTime", NULL));
- rec->registered_by = ldb_msg_find_string(msg, "registeredBy", NULL);
- rec->version = ldb_msg_find_uint64(msg, "versionID", 0);
+ rec->name = name;
+ rec->type = ldb_msg_find_int(msg, "recordType", WREPL_TYPE_UNIQUE);
+ rec->state = ldb_msg_find_int(msg, "recordState", WREPL_STATE_RELEASED);
+ rec->node = ldb_msg_find_int(msg, "nodeType", WREPL_NODE_B);
+ rec->is_static = ldb_msg_find_int(msg, "isStatic", 0);
+ rec->expire_time = ldb_string_to_time(ldb_msg_find_string(msg, "expireTime", NULL));
+ rec->version = ldb_msg_find_uint64(msg, "versionID", 0);
+ rec->wins_owner = ldb_msg_find_string(msg, "winsOwner", NULL);
+ rec->registered_by = ldb_msg_find_string(msg, "registeredBy", NULL);
talloc_steal(rec, rec->wins_owner);
talloc_steal(rec, rec->registered_by);
- if (!rec->wins_owner) rec->wins_owner = WINSDB_OWNER_LOCAL;
+ if (!rec->wins_owner) {
+ rec->wins_owner = talloc_strdup(rec, WINSDB_OWNER_LOCAL);
+ if (rec->wins_owner == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto failed;
+ }
+ }
el = ldb_msg_find_element(msg, "address");
if (el == NULL) {
@@ -657,56 +472,11 @@ failed:
goto failed;
}
- rec->addresses = talloc_array(rec, struct winsdb_addr *, el->num_values+1);
- if (rec->addresses == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto failed;
- }
-
- for (i=0;i<el->num_values;i++) {
- status = winsdb_addr_decode(rec, &el->values[i], rec->addresses, &rec->addresses[i]);
- if (!NT_STATUS_IS_OK(status)) goto failed;
- }
- rec->addresses[i] = NULL;
-
- *_rec = rec;
- return NT_STATUS_OK;
-failed:
- if (NT_STATUS_EQUAL(NT_STATUS_INTERNAL_DB_CORRUPTION, status)) {
- DEBUG(1,("winsdb_record: corrupted record: %s\n", ldb_dn_linearize(rec, msg->dn)));
- }
- talloc_free(rec);
- return status;
-}
-
- rec = talloc(mem_ctx, struct winsdb_record);
- if (rec == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto failed;
- }
-
- if (!name) {
- status = winsdb_nbt_name(rec, msg->dn, &name);
- if (!NT_STATUS_IS_OK(status)) goto failed;
- }
-
- /* parse it into a more convenient winsdb_record structure */
- rec->name = name;
- rec->state = ldb_msg_find_int(msg, "state", WINS_REC_RELEASED);
- rec->nb_flags = ldb_msg_find_int(msg, "nbFlags", 0);
- rec->wins_owner = ldb_msg_find_string(msg, "winsOwner", NULL);
- rec->expire_time = ldap_string_to_time(ldb_msg_find_string(msg, "expireTime", NULL));
- rec->registered_by = ldb_msg_find_string(msg, "registeredBy", NULL);
- rec->version = ldb_msg_find_uint64(msg, "versionID", 0);
- talloc_steal(rec, rec->wins_owner);
- talloc_steal(rec, rec->registered_by);
-
- if (!rec->wins_owner) rec->wins_owner = WINSDB_OWNER_LOCAL;
-
- el = ldb_msg_find_element(msg, "address");
- if (el == NULL) {
- status = NT_STATUS_INTERNAL_DB_CORRUPTION;
- goto failed;
+ if (rec->type == WREPL_TYPE_UNIQUE || rec->type == WREPL_TYPE_GROUP) {
+ if (el->num_values != 1) {
+ status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ goto failed;
+ }
}
rec->addresses = talloc_array(rec, struct winsdb_addr *, el->num_values+1);
@@ -853,6 +623,9 @@ uint8_t winsdb_delete(struct wins_server *winssrv, struct winsdb_record *rec)
int trans;
int ret;
+ trans = ldb_transaction_start(ldb);
+ if (trans != LDB_SUCCESS) goto failed;
+
dn = winsdb_dn(tmp_ctx, rec->name);
if (dn == NULL) goto failed;
diff --git a/source4/nbt_server/wins/winsdb.h b/source4/nbt_server/wins/winsdb.h
index 2ac1884063..d93d50bdf7 100644
--- a/source4/nbt_server/wins/winsdb.h
+++ b/source4/nbt_server/wins/winsdb.h
@@ -29,15 +29,6 @@ struct winsdb_addr {
time_t expire_time;
};
-#define WINSDB_OWNER_LOCAL "0.0.0.0"
-#define WINSDB_GROUP_ADDRESS "255.255.255.255"
-
-struct winsdb_addr {
- const char *address;
- const char *wins_owner;
- time_t expire_time;
-};
-
/*
each record in the database contains the following information
*/
@@ -47,7 +38,6 @@ struct winsdb_record {
enum wrepl_name_state state;
enum wrepl_name_node node;
BOOL is_static;
- const char *wins_owner;
time_t expire_time;
uint64_t version;
const char *wins_owner;
@@ -55,8 +45,6 @@ struct winsdb_record {
/* only needed for debugging problems */
const char *registered_by;
- struct winsdb_addr **addresses;
- uint64_t version;
};
struct wins_server {
diff --git a/source4/nbt_server/wins/winsserver.c b/source4/nbt_server/wins/winsserver.c
index 0f6717f4a9..38540b87ad 100644
--- a/source4/nbt_server/wins/winsserver.c
+++ b/source4/nbt_server/wins/winsserver.c
@@ -70,13 +70,22 @@ static uint8_t wins_register_new(struct nbt_name_socket *nbtsock,
enum wrepl_name_node node;
BOOL mhomed = ((packet->operation & NBT_OPCODE) == NBT_OPCODE_MULTI_HOME_REG);
- rec.name = name;
- rec.nb_flags = nb_flags;
- rec.state = WINS_REC_ACTIVE;
- rec.wins_owner = WINSDB_OWNER_LOCAL;
- rec.expire_time = time(NULL) + ttl;
- rec.registered_by = src->addr;
- rec.addresses = winsdb_addr_list_make(packet);
+#define WREPL_NODE_NBT_FLAGS(nb_flags) \
+ ((nb_flags & NBT_NM_OWNER_TYPE)>>13)
+
+ type = wrepl_type(nb_flags, name, mhomed);
+ node = WREPL_NODE_NBT_FLAGS(nb_flags);
+
+ rec.name = name;
+ rec.type = type;
+ rec.state = WREPL_STATE_ACTIVE;
+ rec.node = node;
+ rec.is_static = False;
+ rec.expire_time = time(NULL) + ttl;
+ rec.version = 0; /* will allocated later */
+ rec.wins_owner = WINSDB_OWNER_LOCAL;
+ rec.registered_by = src->addr;
+ rec.addresses = winsdb_addr_list_make(packet);
if (rec.addresses == NULL) return NBT_RCODE_SVR;
rec.addresses = winsdb_addr_list_add(rec.addresses,
@@ -148,7 +157,7 @@ static void nbtd_winsserver_register(struct nbt_name_socket *nbtsock,
} else if (!NT_STATUS_IS_OK(status)) {
rcode = NBT_RCODE_SVR;
goto done;
- } else if (rec->state != WINS_REC_ACTIVE) {
+ } else if (rec->state != WREPL_STATE_ACTIVE) {
winsdb_delete(winssrv, rec);
rcode = wins_register_new(nbtsock, packet, src);
goto done;
@@ -164,14 +173,14 @@ static void nbtd_winsserver_register(struct nbt_name_socket *nbtsock,
/* if its an active unique name, and the registration is for a group, then
see if the unique name owner still wants the name */
- if (!(rec->nb_flags & NBT_NM_GROUP) && (nb_flags & NBT_NM_GROUP)) {
+ if (!(rec->type == WREPL_TYPE_GROUP) && (nb_flags & NBT_NM_GROUP)) {
wins_register_wack(nbtsock, packet, rec, src);
return;
}
/* if the registration is for a group, then just update the expiry time
and we are done */
- if (IS_GROUP_NAME(name, nb_flags)) {
+ if (nb_flags & NBT_NM_GROUP) {
wins_update_ttl(nbtsock, packet, rec, src);
goto done;
}
@@ -217,14 +226,15 @@ static void nbtd_winsserver_query(struct nbt_name_socket *nbtsock,
struct nbt_name *name = &packet->questions[0].name;
struct winsdb_record *rec;
const char **addresses;
+ uint16_t nb_flags = 0; /* TODO: ... */
status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
- if (!NT_STATUS_IS_OK(status) || rec->state != WINS_REC_ACTIVE) {
+ if (!NT_STATUS_IS_OK(status) || rec->state != WREPL_STATE_ACTIVE) {
nbtd_negative_name_query_reply(nbtsock, packet, src);
return;
}
- if (IS_GROUP_NAME(name, rec->nb_flags)) {
+ if (rec->type == WREPL_TYPE_GROUP) {
addresses = talloc_array(packet, const char *, 2);
if (addresses == NULL) {
nbtd_negative_name_query_reply(nbtsock, packet, src);
@@ -241,7 +251,7 @@ static void nbtd_winsserver_query(struct nbt_name_socket *nbtsock,
}
nbtd_name_query_reply(nbtsock, packet, src, name,
- 0, rec->nb_flags, addresses);
+ 0, nb_flags, addresses);
}
/*
@@ -260,8 +270,8 @@ static void nbtd_winsserver_release(struct nbt_name_socket *nbtsock,
status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
if (!NT_STATUS_IS_OK(status) ||
- rec->state != WINS_REC_ACTIVE ||
- IS_GROUP_NAME(name, rec->nb_flags)) {
+ rec->state != WREPL_STATE_ACTIVE ||
+ rec->type == WREPL_TYPE_GROUP) {
goto done;
}
diff --git a/source4/pidl/lib/Parse/Pidl/Ethereal/NDR.pm b/source4/pidl/lib/Parse/Pidl/Ethereal/NDR.pm
index c4832e251a..8a4c0ed60c 100644
--- a/source4/pidl/lib/Parse/Pidl/Ethereal/NDR.pm
+++ b/source4/pidl/lib/Parse/Pidl/Ethereal/NDR.pm
@@ -321,7 +321,6 @@ sub Element($$$)
my $call_code = "offset = $dissectorname(tvb, offset, pinfo, tree, drep);";
my $type = find_type($e->{TYPE});
- $hf_used{$hf} = 1;
if (not defined($type)) {
# default settings
diff --git a/source4/torture/nbt/dgram.c b/source4/torture/nbt/dgram.c
index f63ada51ae..82cb62dd74 100644
--- a/source4/torture/nbt/dgram.c
+++ b/source4/torture/nbt/dgram.c
@@ -262,8 +262,8 @@ static BOOL nbt_test_ntlogon(TALLOC_CTX *mem_ctx,
dest.port = 0;
dest.addr = address;
- status = dgram_mailslot_ntlogon_send(dgmsock, &name, &dest,
- &myname, &logon);
+ status = dgram_mailslot_ntlogon_send(dgmsock, DGRAM_DIRECT_UNIQUE,
+ &name, &dest, &myname, &logon);
if (!NT_STATUS_IS_OK(status)) {
printf("Failed to send ntlogon request - %s\n", nt_errstr(status));
goto failed;
diff --git a/source4/wrepl_server/config.mk b/source4/wrepl_server/config.mk
index 18fdcad5e9..8c1202ae94 100644
--- a/source4/wrepl_server/config.mk
+++ b/source4/wrepl_server/config.mk
@@ -7,7 +7,9 @@ INIT_OBJ_FILES = \
wrepl_server/wrepl_server.o \
wrepl_server/wrepl_in_connection.o \
wrepl_server/wrepl_in_call.o \
- wrepl_server/wrepl_out_connection.o
+ wrepl_server/wrepl_out_connection.o \
+ wrepl_server/wrepl_out_helpers.o \
+ wrepl_server/wrepl_apply_records.o
REQUIRED_SUBSYSTEMS = \
LIBCLI_WREPL WINSDB
# End SUBSYSTEM WREPL_SRV
diff --git a/source4/wrepl_server/wrepl_in_call.c b/source4/wrepl_server/wrepl_in_call.c
index 4472a0fede..7ccb52cc20 100644
--- a/source4/wrepl_server/wrepl_in_call.c
+++ b/source4/wrepl_server/wrepl_in_call.c
@@ -29,7 +29,10 @@
#include "lib/messaging/irpc.h"
#include "librpc/gen_ndr/ndr_winsrepl.h"
#include "librpc/gen_ndr/ndr_nbt.h"
+#include "libcli/wrepl/winsrepl.h"
#include "wrepl_server/wrepl_server.h"
+#include "wrepl_server/wrepl_out_helpers.h"
+#include "libcli/composite/composite.h"
#include "nbt_server/wins/winsdb.h"
#include "lib/ldb/include/ldb.h"
@@ -111,42 +114,12 @@ static NTSTATUS wreplsrv_in_table_query(struct wreplsrv_in_call *call)
struct wreplsrv_service *service = call->wreplconn->service;
struct wrepl_replication *repl_out = &call->rep_packet.message.replication;
struct wrepl_table *table_out = &call->rep_packet.message.replication.info.table;
- struct wreplsrv_owner *cur;
- uint64_t local_max_version;
- uint32_t i = 0;
+ const char *our_ip = call->wreplconn->our_ip;
repl_out->command = WREPL_REPL_TABLE_REPLY;
- table_out->partner_count = 0;
- table_out->partners = NULL;
- table_out->initiator = WINSDB_OWNER_LOCAL;
-
- local_max_version = wreplsrv_local_max_version(service);
- if (local_max_version > 0) {
- table_out->partner_count++;
- }
-
- for (cur = service->table; cur; cur = cur->next) {
- table_out->partner_count++;
- }
-
- table_out->partners = talloc_array(call, struct wrepl_wins_owner, table_out->partner_count);
- NT_STATUS_HAVE_NO_MEMORY(table_out->partners);
-
- if (local_max_version > 0) {
- table_out->partners[i].address = call->wreplconn->our_ip;
- table_out->partners[i].min_version = 0;
- table_out->partners[i].max_version = local_max_version;
- table_out->partners[i].type = 1;
- i++;
- }
-
- for (cur = service->table; cur; cur = cur->next) {
- table_out->partners[i] = cur->owner;
- i++;
- }
-
- return NT_STATUS_OK;
+ return wreplsrv_fill_wrepl_table(service, call, table_out,
+ our_ip, our_ip, True);
}
static int wreplsrv_in_sort_wins_name(struct wrepl_wins_name *n1,
@@ -157,42 +130,21 @@ static int wreplsrv_in_sort_wins_name(struct wrepl_wins_name *n1,
return 0;
}
-static NTSTATUS wreplsrv_record2wins_name(TALLOC_CTX *mem_ctx, struct wrepl_wins_name *name, struct winsdb_record *rec)
+static NTSTATUS wreplsrv_record2wins_name(TALLOC_CTX *mem_ctx,
+ const char *our_address,
+ struct wrepl_wins_name *name,
+ struct winsdb_record *rec)
{
- uint8_t *namebuf;
- uint32_t namebuf_len;
- uint32_t name_len;
-
- name_len = strlen(rec->name->name);
- if (name_len > 15) {
- return NT_STATUS_INVALID_PARAMETER_MIX;
- }
-
- namebuf = (uint8_t *)talloc_asprintf(mem_ctx, "%-15s%c%s",
- rec->name->name, 'X',
- (rec->name->scope?rec->name->scope:""));
- NT_STATUS_HAVE_NO_MEMORY(namebuf);
- namebuf_len = strlen((char *)namebuf) + 1;
-
- /*
- * we need to set the type here, and use a place-holder in the talloc_asprintf()
- * as the type can be 0x00, and then the namebuf_len = strlen(namebuf); would give wrong results
- */
- namebuf[15] = rec->name->type;
+ uint32_t num_ips, i;
+ struct wrepl_ip *ips;
- /* oh wow, what a nasty bug in windows ... */
- if (rec->name->type == 0x1b) {
- namebuf[15] = namebuf[0];
- namebuf[0] = 0x1b;
- }
+ name->name = rec->name;
+ talloc_steal(mem_ctx, rec->name);
- name->name_len = namebuf_len;
- name->name = namebuf;
name->id = rec->version;
name->unknown = WINSDB_GROUP_ADDRESS;
- name->flags = rec->nb_flags;
- name->group_flag = 0;
+ name->flags = WREPL_NAME_FLAGS(rec->type, rec->state, rec->node, rec->is_static);
switch (name->flags & 2) {
case 0:
@@ -200,8 +152,24 @@ static NTSTATUS wreplsrv_record2wins_name(TALLOC_CTX *mem_ctx, struct wrepl_wins
talloc_steal(mem_ctx, rec->addresses[0]->address);
break;
case 2:
- name->addresses.addresses.num_ips = 0;
- name->addresses.addresses.ips = NULL;
+ num_ips = winsdb_addr_list_length(rec->addresses);
+ ips = talloc_array(mem_ctx, struct wrepl_ip, num_ips);
+ NT_STATUS_HAVE_NO_MEMORY(ips);
+
+ for (i = 0; i < num_ips; i++) {
+ if (strcasecmp(WINSDB_OWNER_LOCAL, rec->addresses[i]->wins_owner) == 0) {
+ ips[i].owner = talloc_strdup(ips, our_address);
+ NT_STATUS_HAVE_NO_MEMORY(ips[i].owner);
+ } else {
+ ips[i].owner = rec->addresses[i]->wins_owner;
+ talloc_steal(ips, rec->addresses[i]->wins_owner);
+ }
+ ips[i].ip = rec->addresses[i]->address;
+ talloc_steal(ips, rec->addresses[i]->address);
+ }
+
+ name->addresses.addresses.num_ips = num_ips;
+ name->addresses.addresses.ips = ips;
break;
}
@@ -251,7 +219,7 @@ static NTSTATUS wreplsrv_in_send_request(struct wreplsrv_in_call *call)
* if the partner ask for nothing, or give invalid ranges,
* return an empty list.
*/
- if (owner_in->min_version >= owner_in->max_version) {
+ if (owner_in->min_version > owner_in->max_version) {
return NT_STATUS_OK;
}
@@ -259,19 +227,29 @@ static NTSTATUS wreplsrv_in_send_request(struct wreplsrv_in_call *call)
* if the partner has already all records for nothing, or give invalid ranges,
* return an empty list.
*/
- if (owner_in->min_version >= owner->owner.max_version) {
+ if (owner_in->min_version > owner->owner.max_version) {
return NT_STATUS_OK;
}
- filter = talloc_asprintf(call, "(&(winsOwner=%s)(objectClass=winsRecord)(state>=%u)(versionID>=%llu)(versionID<=%llu))",
- owner->owner.address, WINS_REC_ACTIVE, owner_in->min_version, owner_in->max_version);
+ filter = talloc_asprintf(call,
+ "(&(winsOwner=%s)(objectClass=winsRecord)"
+ "(|(recordState=%u)(recordState=%u))"
+ "(versionID>=%llu)(versionID<=%llu))",
+ owner->owner.address,
+ WREPL_STATE_ACTIVE, WREPL_STATE_TOMBSTONE,
+ owner_in->min_version, owner_in->max_version);
NT_STATUS_HAVE_NO_MEMORY(filter);
ret = ldb_search(service->wins_db, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &res);
if (res != NULL) {
talloc_steal(call, res);
}
if (ret < 0) return NT_STATUS_INTERNAL_DB_CORRUPTION;
- if (ret == 0) return NT_STATUS_OK;
+ if (ret == 0) {
+ DEBUG(2,("WINSREPL:reply [%u] records owner[%s] min[%llu] max[%llu] to partner[%s]\n",
+ ret, owner_in->address, owner_in->min_version, owner_in->max_version,
+ call->wreplconn->partner->address));
+ return NT_STATUS_OK;
+ }
names = talloc_array(call, struct wrepl_wins_name, ret);
NT_STATUS_HAVE_NO_MEMORY(names);
@@ -280,7 +258,7 @@ static NTSTATUS wreplsrv_in_send_request(struct wreplsrv_in_call *call)
status = winsdb_record(res[i], NULL, call, &rec);
NT_STATUS_NOT_OK_RETURN(status);
- status = wreplsrv_record2wins_name(names, &names[i], rec);
+ status = wreplsrv_record2wins_name(names, call->wreplconn->our_ip, &names[i], rec);
NT_STATUS_NOT_OK_RETURN(status);
talloc_free(rec);
talloc_free(res[i]);
@@ -289,12 +267,113 @@ static NTSTATUS wreplsrv_in_send_request(struct wreplsrv_in_call *call)
/* sort the names before we send them */
qsort(names, ret, sizeof(struct wrepl_wins_name), (comparison_fn_t)wreplsrv_in_sort_wins_name);
+ DEBUG(2,("WINSREPL:reply [%u] records owner[%s] min[%llu] max[%llu] to partner[%s]\n",
+ ret, owner_in->address, owner_in->min_version, owner_in->max_version,
+ call->wreplconn->partner->address));
+
reply_out->num_names = ret;
reply_out->names = names;
return NT_STATUS_OK;
}
+struct wreplsrv_in_update_state {
+ struct wreplsrv_in_connection *wrepl_in;
+ struct wreplsrv_out_connection *wrepl_out;
+ struct composite_context *creq;
+ struct wreplsrv_pull_cycle_io cycle_io;
+};
+
+static void wreplsrv_in_update_handler(struct composite_context *creq)
+{
+ struct wreplsrv_in_update_state *update_state = talloc_get_type(creq->async.private_data,
+ struct wreplsrv_in_update_state);
+ NTSTATUS status;
+
+ status = wreplsrv_pull_cycle_recv(creq);
+
+ talloc_free(update_state->wrepl_out);
+
+ wreplsrv_terminate_in_connection(update_state->wrepl_in, nt_errstr(status));
+}
+
+static NTSTATUS wreplsrv_in_update(struct wreplsrv_in_call *call)
+{
+ struct wreplsrv_in_connection *wrepl_in = call->wreplconn;
+ struct wreplsrv_out_connection *wrepl_out;
+ struct wrepl_table *update_in = &call->req_packet.message.replication.info.table;
+ struct wreplsrv_in_update_state *update_state;
+
+ DEBUG(2,("WREPL_REPL_UPDATE: partner[%s] initiator[%s] num_owners[%u]\n",
+ call->wreplconn->partner->address,
+ update_in->initiator, update_in->partner_count));
+
+ /*
+ * we need to flip the connection into a client connection
+ * and do a WREPL_REPL_SEND_REQUEST's on the that connection
+ * and then stop this connection
+ */
+ talloc_free(wrepl_in->conn->event.fde);
+ wrepl_in->conn->event.fde = NULL;
+
+ update_state = talloc(wrepl_in, struct wreplsrv_in_update_state);
+ NT_STATUS_HAVE_NO_MEMORY(update_state);
+
+ wrepl_out = talloc(update_state, struct wreplsrv_out_connection);
+ NT_STATUS_HAVE_NO_MEMORY(wrepl_out);
+ wrepl_out->service = wrepl_in->service;
+ wrepl_out->partner = wrepl_in->partner;
+ wrepl_out->assoc_ctx.our_ctx = wrepl_in->assoc_ctx.our_ctx;
+ wrepl_out->assoc_ctx.peer_ctx = wrepl_in->assoc_ctx.peer_ctx;
+ wrepl_out->sock = wrepl_socket_merge(wrepl_out,
+ wrepl_in->conn->event.ctx,
+ wrepl_in->conn->socket);
+ NT_STATUS_HAVE_NO_MEMORY(wrepl_out->sock);
+
+ update_state->wrepl_in = wrepl_in;
+ update_state->wrepl_out = wrepl_out;
+ update_state->cycle_io.in.partner = wrepl_out->partner;
+ update_state->cycle_io.in.num_owners = update_in->partner_count;
+ update_state->cycle_io.in.owners = update_in->partners;
+ talloc_steal(update_state, update_in->partners);
+ update_state->cycle_io.in.wreplconn = wrepl_out;
+ update_state->creq = wreplsrv_pull_cycle_send(update_state, &update_state->cycle_io);
+ if (!update_state->creq) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ update_state->creq->async.fn = wreplsrv_in_update_handler;
+ update_state->creq->async.private_data = update_state;
+
+ return ERROR_INVALID_PARAMETER;
+}
+
+static NTSTATUS wreplsrv_in_update2(struct wreplsrv_in_call *call)
+{
+ return wreplsrv_in_update(call);
+}
+
+static NTSTATUS wreplsrv_in_inform(struct wreplsrv_in_call *call)
+{
+ struct wrepl_table *inform_in = &call->req_packet.message.replication.info.table;
+ NTSTATUS status;
+
+ DEBUG(2,("WREPL_REPL_INFORM: partner[%s] initiator[%s] num_owners[%u]\n",
+ call->wreplconn->partner->address,
+ inform_in->initiator, inform_in->partner_count));
+
+ status = wreplsrv_sched_inform_action(call->wreplconn->partner, inform_in);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ /* we don't reply to WREPL_REPL_INFORM messages */
+ return ERROR_INVALID_PARAMETER;
+}
+
+static NTSTATUS wreplsrv_in_inform2(struct wreplsrv_in_call *call)
+{
+ return wreplsrv_in_inform(call);
+}
+
static NTSTATUS wreplsrv_in_replication(struct wreplsrv_in_call *call)
{
struct wrepl_replication *repl_in = &call->req_packet.message.replication;
@@ -318,6 +397,9 @@ static NTSTATUS wreplsrv_in_replication(struct wreplsrv_in_call *call)
switch (repl_in->command) {
case WREPL_REPL_TABLE_QUERY:
+ if (!(call->wreplconn->partner->type & WINSREPL_PARTNER_PUSH)) {
+ return wreplsrv_in_stop_assoc_ctx(call);
+ }
status = wreplsrv_in_table_query(call);
break;
@@ -325,6 +407,9 @@ static NTSTATUS wreplsrv_in_replication(struct wreplsrv_in_call *call)
return ERROR_INVALID_PARAMETER;
case WREPL_REPL_SEND_REQUEST:
+ if (!(call->wreplconn->partner->type & WINSREPL_PARTNER_PUSH)) {
+ return wreplsrv_in_stop_assoc_ctx(call);
+ }
status = wreplsrv_in_send_request(call);
break;
@@ -332,16 +417,32 @@ static NTSTATUS wreplsrv_in_replication(struct wreplsrv_in_call *call)
return ERROR_INVALID_PARAMETER;
case WREPL_REPL_UPDATE:
- return ERROR_INVALID_PARAMETER;
+ if (!(call->wreplconn->partner->type & WINSREPL_PARTNER_PULL)) {
+ return wreplsrv_in_stop_assoc_ctx(call);
+ }
+ status = wreplsrv_in_update(call);
+ break;
- case WREPL_REPL_5:
- return ERROR_INVALID_PARAMETER;
+ case WREPL_REPL_UPDATE2:
+ if (!(call->wreplconn->partner->type & WINSREPL_PARTNER_PULL)) {
+ return wreplsrv_in_stop_assoc_ctx(call);
+ }
+ status = wreplsrv_in_update2(call);
+ break;
case WREPL_REPL_INFORM:
- return ERROR_INVALID_PARAMETER;
+ if (!(call->wreplconn->partner->type & WINSREPL_PARTNER_PULL)) {
+ return wreplsrv_in_stop_assoc_ctx(call);
+ }
+ status = wreplsrv_in_inform(call);
+ break;
- case WREPL_REPL_9:
- return ERROR_INVALID_PARAMETER;
+ case WREPL_REPL_INFORM2:
+ if (!(call->wreplconn->partner->type & WINSREPL_PARTNER_PULL)) {
+ return wreplsrv_in_stop_assoc_ctx(call);
+ }
+ status = wreplsrv_in_inform2(call);
+ break;
default:
return ERROR_INVALID_PARAMETER;
@@ -406,7 +507,8 @@ NTSTATUS wreplsrv_in_call(struct wreplsrv_in_call *call)
}
if (NT_STATUS_IS_OK(status)) {
- call->rep_packet.opcode = WREPL_OPCODE_BITS;
+ /* let the backend to set some of the opcode bits, but always add the standards */
+ call->rep_packet.opcode |= WREPL_OPCODE_BITS;
call->rep_packet.assoc_ctx = call->wreplconn->assoc_ctx.peer_ctx;
}
diff --git a/source4/wrepl_server/wrepl_in_connection.c b/source4/wrepl_server/wrepl_in_connection.c
index ed9c9998d7..5ba36a5051 100644
--- a/source4/wrepl_server/wrepl_in_connection.c
+++ b/source4/wrepl_server/wrepl_in_connection.c
@@ -32,7 +32,7 @@
#include "nbt_server/wins/winsdb.h"
#include "ldb/include/ldb.h"
-static void wreplsrv_terminate_in_connection(struct wreplsrv_in_connection *wreplconn, const char *reason)
+void wreplsrv_terminate_in_connection(struct wreplsrv_in_connection *wreplconn, const char *reason)
{
stream_terminate_connection(wreplconn->conn, reason);
}
@@ -267,6 +267,48 @@ static const struct stream_server_ops wreplsrv_stream_ops = {
};
/*
+ called when we get a new connection
+*/
+NTSTATUS wreplsrv_in_connection_merge(struct wreplsrv_partner *partner,
+ struct socket_context *sock,
+ struct wreplsrv_in_connection **_wrepl_in)
+{
+ struct wreplsrv_service *service = partner->service;
+ struct wreplsrv_in_connection *wrepl_in;
+ const struct model_ops *model_ops;
+ struct stream_connection *conn;
+ NTSTATUS status;
+
+ /* within the wrepl task we want to be a single process, so
+ ask for the single process model ops and pass these to the
+ stream_setup_socket() call. */
+ model_ops = process_model_byname("single");
+ if (!model_ops) {
+ DEBUG(0,("Can't find 'single' process model_ops"));
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ wrepl_in = talloc_zero(partner, struct wreplsrv_in_connection);
+ NT_STATUS_HAVE_NO_MEMORY(wrepl_in);
+
+ wrepl_in->service = service;
+ wrepl_in->partner = partner;
+ wrepl_in->our_ip = socket_get_my_addr(sock, wrepl_in);
+ NT_STATUS_HAVE_NO_MEMORY(wrepl_in->our_ip);
+
+ status = stream_new_connection_merge(service->task->event_ctx, model_ops,
+ sock, &wreplsrv_stream_ops, service->task->msg_ctx,
+ wrepl_in, &conn);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ wrepl_in->conn = conn;
+ talloc_steal(conn, wrepl_in);
+
+ *_wrepl_in = wrepl_in;
+ return NT_STATUS_OK;
+}
+
+/*
startup the wrepl port 42 server sockets
*/
NTSTATUS wreplsrv_setup_sockets(struct wreplsrv_service *service)
diff --git a/source4/wrepl_server/wrepl_out_connection.c b/source4/wrepl_server/wrepl_out_connection.c
index 39406c7e2a..0d5bfda185 100644
--- a/source4/wrepl_server/wrepl_out_connection.c
+++ b/source4/wrepl_server/wrepl_out_connection.c
@@ -31,15 +31,221 @@
#include "wrepl_server/wrepl_server.h"
#include "nbt_server/wins/winsdb.h"
#include "ldb/include/ldb.h"
+#include "libcli/composite/composite.h"
+#include "libcli/wrepl/winsrepl.h"
+#include "wrepl_server/wrepl_out_helpers.h"
+
+static void wreplsrv_pull_handler_te(struct event_context *ev, struct timed_event *te,
+ struct timeval t, void *ptr);
+
+static void wreplsrv_pull_handler_creq(struct composite_context *creq)
+{
+ struct wreplsrv_partner *partner = talloc_get_type(creq->async.private_data, struct wreplsrv_partner);
+ uint32_t interval;
+
+ partner->pull.last_status = wreplsrv_pull_cycle_recv(partner->pull.creq);
+ partner->pull.creq = NULL;
+ talloc_free(partner->pull.cycle_io);
+ partner->pull.cycle_io = NULL;
+
+ if (!NT_STATUS_IS_OK(partner->pull.last_status)) {
+ interval = partner->pull.error_count * partner->pull.retry_interval;
+ interval = MIN(interval, partner->pull.interval);
+ partner->pull.error_count++;
+
+ DEBUG(1,("wreplsrv_pull_cycle(%s): %s: next: %us\n",
+ partner->address, nt_errstr(partner->pull.last_status),
+ interval));
+ } else {
+ interval = partner->pull.interval;
+ partner->pull.error_count = 0;
+
+ DEBUG(2,("wreplsrv_pull_cycle(%s): %s: next: %us\n",
+ partner->address, nt_errstr(partner->pull.last_status),
+ interval));
+ }
+
+ partner->pull.te = event_add_timed(partner->service->task->event_ctx, partner,
+ timeval_current_ofs(interval, 0),
+ wreplsrv_pull_handler_te, partner);
+ if (!partner->pull.te) {
+ DEBUG(0,("wreplsrv_pull_handler_creq: event_add_timed() failed! no memory!\n"));
+ }
+}
+
+static void wreplsrv_pull_handler_te(struct event_context *ev, struct timed_event *te,
+ struct timeval t, void *ptr)
+{
+ struct wreplsrv_partner *partner = talloc_get_type(ptr, struct wreplsrv_partner);
+
+ partner->pull.te = NULL;
+
+ partner->pull.cycle_io = talloc(partner, struct wreplsrv_pull_cycle_io);
+ if (!partner->pull.cycle_io) {
+ goto requeue;
+ }
+
+ partner->pull.cycle_io->in.partner = partner;
+ partner->pull.cycle_io->in.num_owners = 0;
+ partner->pull.cycle_io->in.owners = NULL;
+ partner->pull.cycle_io->in.wreplconn = NULL;
+ partner->pull.creq = wreplsrv_pull_cycle_send(partner->pull.cycle_io, partner->pull.cycle_io);
+ if (!partner->pull.creq) {
+ DEBUG(1,("wreplsrv_pull_cycle_send(%s) failed\n",
+ partner->address));
+ goto requeue;
+ }
+
+ partner->pull.creq->async.fn = wreplsrv_pull_handler_creq;
+ partner->pull.creq->async.private_data = partner;
+
+ return;
+requeue:
+ talloc_free(partner->pull.cycle_io);
+ partner->pull.cycle_io = NULL;
+ /* retry later */
+ partner->pull.te = event_add_timed(partner->service->task->event_ctx, partner,
+ timeval_add(&t, partner->pull.retry_interval, 0),
+ wreplsrv_pull_handler_te, partner);
+ if (!partner->pull.te) {
+ DEBUG(0,("wreplsrv_pull_handler_te: event_add_timed() failed! no memory!\n"));
+ }
+}
+
+NTSTATUS wreplsrv_sched_inform_action(struct wreplsrv_partner *partner, struct wrepl_table *inform_in)
+{
+ if (partner->pull.creq) {
+ /* there's already a pull in progress, so we're done */
+ return NT_STATUS_OK;
+ }
+
+ /* remove the scheduled pull */
+ talloc_free(partner->pull.te);
+ partner->pull.te = NULL;
+
+ partner->pull.cycle_io = talloc(partner, struct wreplsrv_pull_cycle_io);
+ if (!partner->pull.cycle_io) {
+ goto requeue;
+ }
+
+ partner->pull.cycle_io->in.partner = partner;
+ partner->pull.cycle_io->in.num_owners = inform_in->partner_count;
+ partner->pull.cycle_io->in.owners = inform_in->partners;
+ talloc_steal(partner->pull.cycle_io, inform_in->partners);
+ partner->pull.cycle_io->in.wreplconn = NULL;
+ partner->pull.creq = wreplsrv_pull_cycle_send(partner->pull.cycle_io, partner->pull.cycle_io);
+ if (!partner->pull.creq) {
+ DEBUG(1,("wreplsrv_pull_cycle_send(%s) failed\n",
+ partner->address));
+ goto requeue;
+ }
+
+ partner->pull.creq->async.fn = wreplsrv_pull_handler_creq;
+ partner->pull.creq->async.private_data = partner;
+
+ return NT_STATUS_OK;
+requeue:
+ talloc_free(partner->pull.cycle_io);
+ partner->pull.cycle_io = NULL;
+ /* retry later */
+ partner->pull.te = event_add_timed(partner->service->task->event_ctx, partner,
+ timeval_current_ofs(partner->pull.retry_interval, 0),
+ wreplsrv_pull_handler_te, partner);
+ if (!partner->pull.te) {
+ DEBUG(0,("wreplsrv_pull_handler_te: event_add_timed() failed! no memory!\n"));
+ }
+
+ return NT_STATUS_OK;
+}
+
+static void wreplsrv_push_handler_te(struct event_context *ev, struct timed_event *te,
+ struct timeval t, void *ptr);
+
+static void wreplsrv_push_handler_creq(struct composite_context *creq)
+{
+ struct wreplsrv_partner *partner = talloc_get_type(creq->async.private_data, struct wreplsrv_partner);
+ uint32_t interval;
+
+ partner->push.last_status = wreplsrv_push_notify_recv(partner->push.creq);
+ partner->push.creq = NULL;
+ talloc_free(partner->push.notify_io);
+ partner->push.notify_io = NULL;
+
+ if (!NT_STATUS_IS_OK(partner->push.last_status)) {
+ interval = 15;
+
+ DEBUG(1,("wreplsrv_push_notify(%s): %s: next: %us\n",
+ partner->address, nt_errstr(partner->push.last_status),
+ interval));
+ } else {
+ interval = 100;
+
+ DEBUG(2,("wreplsrv_push_notify(%s): %s: next: %us\n",
+ partner->address, nt_errstr(partner->push.last_status),
+ interval));
+ }
+
+ partner->push.te = event_add_timed(partner->service->task->event_ctx, partner,
+ timeval_current_ofs(interval, 0),
+ wreplsrv_push_handler_te, partner);
+ if (!partner->push.te) {
+ DEBUG(0,("wreplsrv_push_handler_creq: event_add_timed() failed! no memory!\n"));
+ }
+}
+
+static void wreplsrv_push_handler_te(struct event_context *ev, struct timed_event *te,
+ struct timeval t, void *ptr)
+{
+ struct wreplsrv_partner *partner = talloc_get_type(ptr, struct wreplsrv_partner);
+
+ partner->push.te = NULL;
+
+ partner->push.notify_io = talloc(partner, struct wreplsrv_push_notify_io);
+ if (!partner->push.notify_io) {
+ goto requeue;
+ }
+
+ partner->push.notify_io->in.partner = partner;
+ partner->push.notify_io->in.inform = False;
+ partner->push.notify_io->in.propagate = False;
+ partner->push.creq = wreplsrv_push_notify_send(partner->push.notify_io, partner->push.notify_io);
+ if (!partner->push.creq) {
+ DEBUG(1,("wreplsrv_push_notify_send(%s) failed\n",
+ partner->address));
+ goto requeue;
+ }
+
+ partner->push.creq->async.fn = wreplsrv_push_handler_creq;
+ partner->push.creq->async.private_data = partner;
+
+ return;
+requeue:
+ talloc_free(partner->push.notify_io);
+ partner->push.notify_io = NULL;
+ /* retry later */
+ partner->push.te = event_add_timed(partner->service->task->event_ctx, partner,
+ timeval_add(&t, 5, 0),
+ wreplsrv_push_handler_te, partner);
+ if (!partner->push.te) {
+ DEBUG(0,("wreplsrv_push_handler_te: event_add_timed() failed! no memory!\n"));
+ }
+}
NTSTATUS wreplsrv_setup_out_connections(struct wreplsrv_service *service)
{
struct wreplsrv_partner *cur;
for (cur = service->partners; cur; cur = cur->next) {
- if (!(cur->type & WINSREPL_PARTNER_PULL)) continue;
-
- DEBUG(0,("TODO: pull from: %s\n", cur->address));
+ if (cur->type & WINSREPL_PARTNER_PULL) {
+ cur->pull.te = event_add_timed(service->task->event_ctx, cur,
+ timeval_zero(), wreplsrv_pull_handler_te, cur);
+ NT_STATUS_HAVE_NO_MEMORY(cur->pull.te);
+ }
+ if (cur->type & WINSREPL_PARTNER_PUSH) {
+ cur->push.te = event_add_timed(service->task->event_ctx, cur,
+ timeval_zero(), wreplsrv_push_handler_te, cur);
+ NT_STATUS_HAVE_NO_MEMORY(cur->push.te);
+ }
}
return NT_STATUS_OK;
diff --git a/source4/wrepl_server/wrepl_server.c b/source4/wrepl_server/wrepl_server.c
index 97fa23cdf1..b044ef8296 100644
--- a/source4/wrepl_server/wrepl_server.c
+++ b/source4/wrepl_server/wrepl_server.c
@@ -80,14 +80,17 @@ static NTSTATUS wreplsrv_load_partners(struct wreplsrv_service *service)
for (i=0; i < ret; i++) {
struct wreplsrv_partner *partner;
- partner = talloc(service, struct wreplsrv_partner);
+ partner = talloc_zero(service, struct wreplsrv_partner);
if (partner == NULL) goto failed;
+ partner->service = service;
partner->address = ldb_msg_find_string(res[i], "address", NULL);
if (!partner->address) goto failed;
partner->name = ldb_msg_find_string(res[i], "name", partner->address);
partner->type = ldb_msg_find_int(res[i], "type", WINSREPL_PARTNER_BOTH);
partner->pull.interval = ldb_msg_find_int(res[i], "pullInterval", WINSREPL_DEFAULT_PULL_INTERVAL);
+ partner->pull.retry_interval = ldb_msg_find_int(res[i], "pullRetryInterval",
+ WINSREPL_DEFAULT_PULL_RETRY_INTERVAL);
partner->our_address = ldb_msg_find_string(res[i], "ourAddress", NULL);
talloc_steal(partner, partner->address);
@@ -104,6 +107,29 @@ failed:
return NT_STATUS_FOOBAR;
}
+BOOL wreplsrv_is_our_address(struct wreplsrv_service *service, const char *address)
+{
+ const char *our_address;
+
+ if (lp_interfaces() && lp_bind_interfaces_only()) {
+ int num_interfaces = iface_count();
+ int i;
+ for(i = 0; i < num_interfaces; i++) {
+ our_address = iface_n_ip(i);
+ if (strcasecmp(our_address, address) == 0) {
+ return True;
+ }
+ }
+ } else {
+ our_address = lp_socket_address();
+ if (strcasecmp(our_address, address) == 0) {
+ return True;
+ }
+ }
+
+ return False;
+}
+
uint64_t wreplsrv_local_max_version(struct wreplsrv_service *service)
{
int ret;
@@ -134,6 +160,49 @@ failed:
return maxVersion;
}
+NTSTATUS wreplsrv_fill_wrepl_table(struct wreplsrv_service *service,
+ TALLOC_CTX *mem_ctx,
+ struct wrepl_table *table_out,
+ const char *our_ip,
+ const char *initiator,
+ BOOL full_table)
+{
+ struct wreplsrv_owner *cur;
+ uint64_t local_max_version;
+ uint32_t i = 0;
+
+ table_out->partner_count = 0;
+ table_out->partners = NULL;
+ table_out->initiator = initiator;
+
+ local_max_version = wreplsrv_local_max_version(service);
+ if (local_max_version > 0) {
+ table_out->partner_count++;
+ }
+
+ for (cur = service->table; full_table && cur; cur = cur->next) {
+ table_out->partner_count++;
+ }
+
+ table_out->partners = talloc_array(mem_ctx, struct wrepl_wins_owner, table_out->partner_count);
+ NT_STATUS_HAVE_NO_MEMORY(table_out->partners);
+
+ if (local_max_version > 0) {
+ table_out->partners[i].address = our_ip;
+ table_out->partners[i].min_version = 0;
+ table_out->partners[i].max_version = local_max_version;
+ table_out->partners[i].type = 1;
+ i++;
+ }
+
+ for (cur = service->table; full_table && cur; cur = cur->next) {
+ table_out->partners[i] = cur->owner;
+ i++;
+ }
+
+ return NT_STATUS_OK;
+}
+
struct wreplsrv_owner *wreplsrv_find_owner(struct wreplsrv_owner *table, const char *wins_owner)
{
struct wreplsrv_owner *cur;
@@ -151,9 +220,9 @@ struct wreplsrv_owner *wreplsrv_find_owner(struct wreplsrv_owner *table, const c
update the wins_owner_table max_version, if the given version is the highest version
if no entry for the wins_owner exists yet, create one
*/
-static NTSTATUS wreplsrv_add_table(struct wreplsrv_service *service,
- TALLOC_CTX *mem_ctx, struct wreplsrv_owner **_table,
- const char *wins_owner, uint64_t version)
+NTSTATUS wreplsrv_add_table(struct wreplsrv_service *service,
+ TALLOC_CTX *mem_ctx, struct wreplsrv_owner **_table,
+ const char *wins_owner, uint64_t version)
{
struct wreplsrv_owner *table = *_table;
struct wreplsrv_owner *cur;
diff --git a/source4/wrepl_server/wrepl_server.h b/source4/wrepl_server/wrepl_server.h
index 278b15fbb7..63603c823d 100644
--- a/source4/wrepl_server/wrepl_server.h
+++ b/source4/wrepl_server/wrepl_server.h
@@ -92,16 +92,38 @@ struct wreplsrv_in_connection {
state of an outcoming wrepl connection
*/
struct wreplsrv_out_connection {
+ /* our global service context */
+ struct wreplsrv_service *service;
+
+ /*
+ * the partner that connects us,
+ * can be NULL, when we got a connection
+ * from an unknown address
+ */
struct wreplsrv_partner *partner;
+
+ /* keep track of the assoc_ctx's */
+ struct {
+ uint32_t our_ctx;
+ uint32_t peer_ctx;
+ } assoc_ctx;
+
+ /*
+ * the client socket to the partner,
+ * NULL if not yet connected
+ */
+ struct wrepl_socket *sock;
};
enum winsrepl_partner_type {
+ WINSREPL_PARTNER_NONE = 0x0,
WINSREPL_PARTNER_PULL = 0x1,
WINSREPL_PARTNER_PUSH = 0x2,
WINSREPL_PARTNER_BOTH = (WINSREPL_PARTNER_PULL | WINSREPL_PARTNER_PUSH)
};
#define WINSREPL_DEFAULT_PULL_INTERVAL (30*60)
+#define WINSREPL_DEFAULT_PULL_RETRY_INTERVAL (30)
/*
this represents one of our configured partners
@@ -109,6 +131,9 @@ enum winsrepl_partner_type {
struct wreplsrv_partner {
struct wreplsrv_partner *prev,*next;
+ /* our global service context */
+ struct wreplsrv_service *service;
+
/* the netbios name of the partner, mostly just for debugging */
const char *name;
@@ -129,12 +154,51 @@ struct wreplsrv_partner {
/* the interval between 2 pull replications to the partner */
uint32_t interval;
+ /* the retry_interval if a pull cycle failed to the partner */
+ uint32_t retry_interval;
+
+ /* the error count till the last success */
+ uint32_t error_count;
+
+ /* the status of the last pull cycle */
+ NTSTATUS last_status;
+
/* this is a list of each wins_owner the partner knows about */
struct wreplsrv_owner *table;
/* the outgoing connection to the partner */
struct wreplsrv_out_connection *wreplconn;
+
+ /* the current pending pull cycle request */
+ struct composite_context *creq;
+
+ /* the pull cycle io params */
+ struct wreplsrv_pull_cycle_io *cycle_io;
+
+ /* the current timed_event to the next pull cycle */
+ struct timed_event *te;
} pull;
+
+ /* push specific options */
+ struct {
+ /* change count till push notification */
+ uint32_t change_count;
+
+ /* the status of the last push cycle */
+ NTSTATUS last_status;
+
+ /* the outgoing connection to the partner */
+ struct wreplsrv_out_connection *wreplconn;
+
+ /* the current push notification */
+ struct composite_context *creq;
+
+ /* the pull cycle io params */
+ struct wreplsrv_push_notify_io *notify_io;
+
+ /* the current timed_event to the next push notify */
+ struct timed_event *te;
+ } push;
};
struct wreplsrv_owner {