2005-12-14 22:19:43 +03:00
/*
Unix SMB / CIFS implementation .
WINS Replication server
Copyright ( C ) Stefan Metzmacher 2005
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
2007-07-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2005-12-14 22:19:43 +03:00
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
2007-07-10 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2005-12-14 22:19:43 +03:00
*/
# include "includes.h"
2006-03-16 03:23:11 +03:00
# include "librpc/gen_ndr/winsrepl.h"
2005-12-14 22:19:43 +03:00
# include "wrepl_server/wrepl_server.h"
# include "libcli/composite/composite.h"
2006-01-02 19:14:08 +03:00
# include "nbt_server/wins/winsdb.h"
2005-12-14 22:19:43 +03:00
static void wreplsrv_out_partner_push ( struct wreplsrv_partner * partner , BOOL propagate ) ;
static void wreplsrv_push_handler_creq ( struct composite_context * creq )
{
struct wreplsrv_partner * partner = talloc_get_type ( creq - > async . private_data , struct wreplsrv_partner ) ;
2005-12-17 22:24:13 +03:00
struct wreplsrv_push_notify_io * old_notify_io ;
2005-12-14 22:19:43 +03:00
partner - > push . last_status = wreplsrv_push_notify_recv ( partner - > push . creq ) ;
partner - > push . creq = NULL ;
2005-12-17 22:24:13 +03:00
old_notify_io = partner - > push . notify_io ;
partner - > push . notify_io = NULL ;
2005-12-14 22:19:43 +03:00
if ( NT_STATUS_IS_OK ( partner - > push . last_status ) ) {
partner - > push . error_count = 0 ;
DEBUG ( 2 , ( " wreplsrv_push_notify(%s): %s \n " ,
partner - > address , nt_errstr ( partner - > push . last_status ) ) ) ;
2005-12-17 22:24:13 +03:00
goto done ;
2005-12-14 22:19:43 +03:00
}
partner - > push . error_count + + ;
if ( partner - > push . error_count > 1 ) {
DEBUG ( 1 , ( " wreplsrv_push_notify(%s): %s: error_count: %u: giving up \n " ,
partner - > address , nt_errstr ( partner - > push . last_status ) ,
partner - > push . error_count ) ) ;
2005-12-17 22:24:13 +03:00
goto done ;
2005-12-14 22:19:43 +03:00
}
DEBUG ( 1 , ( " wreplsrv_push_notify(%s): %s: error_count: %u: retry \n " ,
partner - > address , nt_errstr ( partner - > push . last_status ) ,
partner - > push . error_count ) ) ;
2005-12-17 22:24:13 +03:00
wreplsrv_out_partner_push ( partner , old_notify_io - > in . propagate ) ;
done :
talloc_free ( old_notify_io ) ;
2005-12-14 22:19:43 +03:00
}
static void wreplsrv_out_partner_push ( struct wreplsrv_partner * partner , BOOL propagate )
{
/* a push for this partner is currently in progress, so we're done */
if ( partner - > push . creq ) return ;
/* now prepare the push notify */
partner - > push . notify_io = talloc ( partner , struct wreplsrv_push_notify_io ) ;
if ( ! partner - > push . notify_io ) {
goto nomem ;
}
partner - > push . notify_io - > in . partner = partner ;
partner - > push . notify_io - > in . inform = partner - > push . use_inform ;
partner - > push . notify_io - > in . propagate = propagate ;
partner - > push . creq = wreplsrv_push_notify_send ( partner - > push . notify_io , partner - > push . notify_io ) ;
if ( ! partner - > push . creq ) {
2005-12-20 03:33:41 +03:00
DEBUG ( 1 , ( " wreplsrv_push_notify_send(%s) failed nomem? \n " ,
2005-12-14 22:19:43 +03:00
partner - > address ) ) ;
goto nomem ;
}
partner - > push . creq - > async . fn = wreplsrv_push_handler_creq ;
partner - > push . creq - > async . private_data = partner ;
return ;
nomem :
talloc_free ( partner - > push . notify_io ) ;
partner - > push . notify_io = NULL ;
2005-12-20 03:33:41 +03:00
DEBUG ( 1 , ( " wreplsrv_out_partner_push(%s,%u) failed nomem? (ignoring) \n " ,
partner - > address , propagate ) ) ;
2005-12-14 22:19:43 +03:00
return ;
}
2006-01-24 20:36:13 +03:00
static uint32_t wreplsrv_calc_change_count ( struct wreplsrv_partner * partner , uint64_t maxVersionID )
2005-12-14 22:19:43 +03:00
{
2005-12-31 12:44:04 +03:00
uint64_t tmp_diff = UINT32_MAX ;
/* catch an overflow */
2006-01-24 20:36:13 +03:00
if ( partner - > push . maxVersionID > maxVersionID ) {
2005-12-31 12:44:04 +03:00
goto done ;
}
2006-01-24 20:36:13 +03:00
tmp_diff = maxVersionID - partner - > push . maxVersionID ;
2005-12-31 12:44:04 +03:00
if ( tmp_diff > UINT32_MAX ) {
tmp_diff = UINT32_MAX ;
goto done ;
}
done :
2006-01-24 20:36:13 +03:00
partner - > push . maxVersionID = maxVersionID ;
2005-12-31 12:44:04 +03:00
return ( uint32_t ) ( tmp_diff & UINT32_MAX ) ;
2005-12-14 22:19:43 +03:00
}
2005-12-20 00:52:37 +03:00
NTSTATUS wreplsrv_out_push_run ( struct wreplsrv_service * service )
2005-12-14 22:19:43 +03:00
{
struct wreplsrv_partner * partner ;
2005-12-31 12:44:04 +03:00
uint64_t seqnumber ;
2005-12-14 22:19:43 +03:00
uint32_t change_count ;
2006-01-24 20:36:13 +03:00
seqnumber = winsdb_get_maxVersion ( service - > wins_db ) ;
2005-12-31 12:44:04 +03:00
2005-12-14 22:19:43 +03:00
for ( partner = service - > partners ; partner ; partner = partner - > next ) {
/* if it's not a push partner, go to the next partner */
if ( ! ( partner - > type & WINSREPL_PARTNER_PUSH ) ) continue ;
/* if push notifies are disabled for this partner, go to the next partner */
if ( partner - > push . change_count = = 0 ) continue ;
/* get the actual change count for the partner */
2005-12-31 12:44:04 +03:00
change_count = wreplsrv_calc_change_count ( partner , seqnumber ) ;
2005-12-14 22:19:43 +03:00
/* if the configured change count isn't reached, go to the next partner */
if ( change_count < partner - > push . change_count ) continue ;
wreplsrv_out_partner_push ( partner , False ) ;
}
2005-12-20 00:52:37 +03:00
return NT_STATUS_OK ;
2005-12-14 22:19:43 +03:00
}