2 Unix SMB/CIFS implementation.
3 process incoming packets - main loop
4 Copyright (C) Jean François Micouleau 1998-2002.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "wins_repl.h"
24 extern fd_set
*listen_set
;
25 extern int listen_number
;
26 extern int *sock_array
;
28 WINS_OWNER global_wins_table
[64][64];
33 #define WINS_LIST "wins.tdb"
34 #define INFO_VERSION "INFO/version"
35 #define INFO_COUNT "INFO/num_entries"
36 #define INFO_ID_HIGH "INFO/id_high"
37 #define INFO_ID_LOW "INFO/id_low"
38 #define ENTRY_PREFIX "ENTRY/"
41 /*******************************************************************
42 fill the header of a reply.
43 ********************************************************************/
44 static void fill_header(GENERIC_PACKET
*g
, int opcode
, int ctx
, int mess
)
49 g
->header
.opcode
=opcode
;
50 g
->header
.assoc_ctx
=ctx
;
51 g
->header
.mess_type
=mess
;
54 /*******************************************************************
55 dump the global table, that's a debug code.
56 ********************************************************************/
57 static void dump_global_table(void)
61 for (i
=0;i
<partner_count
;i
++) {
62 DEBUG(10,("\n%d ", i
));
63 for (j
=0; global_wins_table
[i
][j
].address
.s_addr
!=0; j
++)
64 DEBUG(10,("%s:%d \t", inet_ntoa(global_wins_table
[i
][j
].address
),
65 (int)global_wins_table
[i
][j
].max_version
));
70 /*******************************************************************
72 ********************************************************************/
73 static void start_assoc_process(GENERIC_PACKET
*q
, GENERIC_PACKET
*r
)
76 * add this request to our current wins partners list
77 * this list is used to know with who we are in contact
80 r
->sa_rp
.assoc_ctx
=time(NULL
);
81 fill_header(r
, OPCODE_NON_NBT
, q
->sa_rq
.assoc_ctx
, MESSAGE_TYPE_START_ASSOC_REPLY
);
83 /* reply we are a NT4 server */
85 /* w2K is min=2, maj=5 */
90 add_partner(r
->sa_rp
.assoc_ctx
, q
->sa_rq
.assoc_ctx
, False
, False
);
93 /*******************************************************************
94 start association reply
95 ********************************************************************/
96 static void start_assoc_reply(GENERIC_PACKET
*q
, GENERIC_PACKET
*r
)
100 /* check if we have already registered this client */
101 if (!check_partner(q
->header
.assoc_ctx
)) {
102 DEBUG(0,("start_assoc_reply: unknown client\n"));
103 stop_packet(q
, r
, STOP_REASON_USER_REASON
);
107 if (!update_server_partner(q
->header
.assoc_ctx
, q
->sa_rp
.assoc_ctx
)) {
108 DEBUG(0,("start_assoc_reply: can't update server ctx\n"));
109 stop_packet(q
, r
, STOP_REASON_USER_REASON
);
113 /* if pull, request map table */
114 if (check_pull_partner(q
->header
.assoc_ctx
)) {
115 fill_header(r
, OPCODE_NON_NBT
, get_server_assoc(q
->header
.assoc_ctx
), MESSAGE_TYPE_REPLICATE
);
117 r
->rep
.msg_type
=MESSAGE_REP_ADD_VERSION_REQUEST
;
118 DEBUG(5,("start_assoc_reply: requesting map table\n"));
123 /* if push, send our table */
124 if (check_push_partner(q
->header
.assoc_ctx
)) {
125 fill_header(r
, OPCODE_NON_NBT
, get_server_assoc(q
->header
.assoc_ctx
), MESSAGE_TYPE_REPLICATE
);
126 r
->rep
.msg_type
=MESSAGE_REP_UPDATE_NOTIFY_REQUEST
;
127 r
->rep
.un_rq
.partner_count
=partner_count
;
129 r
->rep
.un_rq
.wins_owner
=(WINS_OWNER
*)talloc(mem_ctx
, partner_count
*sizeof(WINS_OWNER
));
130 if (r
->rep
.un_rq
.wins_owner
==NULL
) {
131 DEBUG(0,("start_assoc_reply: can't alloc memory\n"));
132 stop_packet(q
, r
, STOP_REASON_USER_REASON
);
136 for (i
=0; i
<partner_count
; i
++)
137 r
->rep
.un_rq
.wins_owner
[i
]=global_wins_table
[0][i
];
139 DEBUG(5,("start_assoc_reply: sending update table\n"));
143 /* neither push/pull, stop */
144 /* we should not come here */
145 DEBUG(0,("we have a partner which is neither push nor pull !\n"));
146 stop_packet(q
, r
, STOP_REASON_USER_REASON
);
149 /****************************************************************************
150 initialise and fill the in-memory partner table.
151 ****************************************************************************/
152 int init_wins_partner_table(void)
155 char **partner
= str_list_make(lp_wins_partners(), NULL
);
158 DEBUG(0,("wrepld: no partner list in smb.conf, exiting\n"));
159 exit_server("normal exit");
163 DEBUG(4, ("init_wins_partner_table: partners: %s\n", lp_wins_partners()));
165 global_wins_table
[0][0].address
=*iface_n_ip(0);
166 global_wins_table
[0][0].max_version
=0;
167 global_wins_table
[0][0].min_version
=0;
168 global_wins_table
[0][0].type
=0;
170 while (partner
[j
]!=NULL
) {
171 DEBUG(3,("init_wins_partner_table, adding partner: %s\n", partner
[j
]));
173 global_wins_table
[0][i
].address
=*interpret_addr2(partner
[j
]);
174 global_wins_table
[0][i
].max_version
=0;
175 global_wins_table
[0][i
].min_version
=0;
176 global_wins_table
[0][i
].type
=0;
177 global_wins_table
[0][i
].last_pull
=0;
178 global_wins_table
[0][i
].last_push
=0;
186 global_wins_table
[k
][j
]=global_wins_table
[0][j
];
188 str_list_free (&partner
);
193 /****************************************************************************
194 read the last ID from the wins tdb file.
195 ****************************************************************************/
196 static void get_our_last_id(WINS_OWNER
*wins_owner
)
200 tdb
= tdb_open_log(lock_path(WINS_LIST
), 0, TDB_DEFAULT
, O_RDONLY
, 0600);
202 DEBUG(2,("get_our_last_id: Can't open wins database file %s. Error was %s\n", WINS_LIST
, strerror(errno
) ));
206 wins_owner
->max_version
=((SMB_BIG_UINT
)tdb_fetch_int32(tdb
, INFO_ID_HIGH
))<<32 |
207 (SMB_BIG_UINT
)tdb_fetch_int32(tdb
, INFO_ID_LOW
);
212 /****************************************************************************
213 send the list of wins server we know.
214 ****************************************************************************/
215 static void send_version_number_map_table(GENERIC_PACKET
*q
, GENERIC_PACKET
*r
)
218 int s_ctx
=get_server_assoc(q
->header
.assoc_ctx
);
221 DEBUG(5, ("send_version_number_map_table: request for a partner not in our table\n"));
222 stop_packet(q
, r
, STOP_REASON_USER_REASON
);
227 * return an array of wins servers, we are partner with.
228 * each entry contains the IP address and the version info
229 * version: ID of the last entry we've got
232 /* the first wins server must be self */
235 * get our last ID from the wins database
236 * it can have been updated since last read
237 * as nmbd got registration/release.
239 get_our_last_id(&global_wins_table
[0][0]);
241 r
->rep
.avmt_rep
.wins_owner
=(WINS_OWNER
*)talloc(mem_ctx
, partner_count
*sizeof(WINS_OWNER
));
242 if (r
->rep
.avmt_rep
.wins_owner
==NULL
) {
243 stop_packet(q
, r
, STOP_REASON_USER_REASON
);
247 DEBUG(5,("send_version_number_map_table: partner_count: %d\n", partner_count
));
249 for (i
=0; i
<partner_count
; i
++) {
250 DEBUG(5,("send_version_number_map_table, partner: %d -> %s, \n", i
, inet_ntoa(global_wins_table
[0][i
].address
)));
251 r
->rep
.avmt_rep
.wins_owner
[i
]=global_wins_table
[0][i
];
255 r
->rep
.avmt_rep
.partner_count
=partner_count
;
256 r
->rep
.avmt_rep
.initiating_wins_server
.s_addr
=0; /* blatant lie, NT4/w2K do the same ! */
257 fill_header(r
, OPCODE_NON_NBT
, s_ctx
, MESSAGE_TYPE_REPLICATE
);
260 /****************************************************************************
261 for a given partner, ask it to send entries we don't have.
262 ****************************************************************************/
263 static BOOL
check_partners_and_send_entries(GENERIC_PACKET
*q
, GENERIC_PACKET
*r
, int partner
)
268 SMB_BIG_UINT current
;
272 * we check if our partner has more records than us.
273 * we need to check more than our direct partners as
274 * we can have this case:
275 * us: A, partners: B,C, indirect partner: D
276 * A<->B, A<->C, B<->D, C<->D
278 * So if we're talking to B, we need to check if between
279 * B and C, which one have more records about D.
280 * and also check if we don't already have the records.
284 /* check all servers even indirect */
285 for (server
=1; global_wins_table
[0][server
].address
.s_addr
!=0; server
++) {
286 current
= global_wins_table
[partner
][server
].max_version
;
290 for (other
=1; other
<partner_count
; other
++) {
291 /* skip the partner itself */
295 if (global_wins_table
[other
][server
].max_version
> temp
)
296 temp
=global_wins_table
[other
][server
].max_version
;
299 if (current
>= temp
&& current
> global_wins_table
[0][server
].max_version
) {
301 * it has more records than every body else and more than us,
302 * ask it the difference between what we have and what it has
304 fill_header(r
, OPCODE_NON_NBT
, get_server_assoc(q
->header
.assoc_ctx
), MESSAGE_TYPE_REPLICATE
);
306 r
->rep
.msg_type
=MESSAGE_REP_SEND_ENTRIES_REQUEST
;
307 r
->rep
.se_rq
.wins_owner
.address
=global_wins_table
[partner
][server
].address
;
309 r
->rep
.se_rq
.wins_owner
.max_version
=global_wins_table
[partner
][server
].max_version
;
310 r
->rep
.se_rq
.wins_owner
.min_version
=global_wins_table
[0][server
].max_version
;
311 r
->rep
.se_rq
.wins_owner
.type
=0;
313 write_server_assoc_table(q
->header
.assoc_ctx
, global_wins_table
[0][partner
].address
, global_wins_table
[partner
][server
].address
);
316 * and we update our version for this server
317 * as we can't use the IDs returned in the send_entries function
318 * the max ID can be larger than the largest ID returned
321 global_wins_table
[0][server
].max_version
=global_wins_table
[partner
][server
].max_version
;
329 /****************************************************************************
330 receive the list of wins server we know.
331 ****************************************************************************/
332 static void receive_version_number_map_table(GENERIC_PACKET
*q
, GENERIC_PACKET
*r
)
337 int s_ctx
=get_server_assoc(q
->header
.assoc_ctx
);
340 DEBUG(5, ("receive_version_number_map_table: request for a partner not in our table\n"));
341 stop_packet(q
, r
, STOP_REASON_USER_REASON
);
345 fstrcpy(peer
,get_socket_addr(q
->fd
));
346 addr
=*interpret_addr2(peer
);
348 get_our_last_id(&global_wins_table
[0][0]);
350 DEBUG(5,("receive_version_number_map_table: received a map of %d server from: %s\n",
351 q
->rep
.avmt_rep
.partner_count
,inet_ntoa(q
->rep
.avmt_rep
.initiating_wins_server
)));
352 DEBUG(5,("real peer is: %s\n", peer
));
354 for (i
=0; global_wins_table
[0][i
].address
.s_addr
!=addr
.s_addr
&& i
<partner_count
;i
++)
357 if (i
==partner_count
) {
358 DEBUG(5,("receive_version_number_map_table: unknown partner: %s\n", peer
));
359 stop_packet(q
, r
, STOP_REASON_USER_REASON
);
363 for (j
=0; j
<q
->rep
.avmt_rep
.partner_count
;j
++) {
365 * search if we already have this entry or if it's a new one
366 * it can be a new one in case of propagation
368 for (k
=0; global_wins_table
[0][k
].address
.s_addr
!=0 &&
369 global_wins_table
[0][k
].address
.s_addr
!=q
->rep
.avmt_rep
.wins_owner
[j
].address
.s_addr
; k
++);
371 global_wins_table
[i
][k
].address
.s_addr
=q
->rep
.avmt_rep
.wins_owner
[j
].address
.s_addr
;
372 global_wins_table
[i
][k
].max_version
=q
->rep
.avmt_rep
.wins_owner
[j
].max_version
;
373 global_wins_table
[i
][k
].min_version
=q
->rep
.avmt_rep
.wins_owner
[j
].min_version
;
374 global_wins_table
[i
][k
].type
=q
->rep
.avmt_rep
.wins_owner
[j
].type
;
377 * in case it's a new one, rewrite the address for all the partner
378 * to reserve the slot.
381 for(l
=0; l
<partner_count
; l
++)
382 global_wins_table
[l
][k
].address
.s_addr
=q
->rep
.avmt_rep
.wins_owner
[j
].address
.s_addr
;
388 * if this server have newer records than what we have
389 * for several wins servers, we need to ask it.
390 * Alas a send entry request is only on one server.
391 * So in the send entry reply, we'll ask for the next server if required.
394 if (check_partners_and_send_entries(q
, r
, i
))
397 /* it doesn't have more entries than us */
398 stop_packet(q
, r
, STOP_REASON_USER_REASON
);
401 /****************************************************************************
402 add an entry to the wins list we'll send.
403 ****************************************************************************/
404 static BOOL
add_record_to_winsname(WINS_NAME
**wins_name
, int *max_names
, char *name
, int type
, int wins_flags
, int id
, struct in_addr
*ip_list
, int num_ips
)
406 WINS_NAME
*temp_list
;
408 int current
=*max_names
;
410 temp_list
=talloc_realloc(mem_ctx
, *wins_name
, (current
+1)*sizeof(WINS_NAME
));
414 temp_list
[current
].name_len
=0x11;
416 safe_strcpy(temp_list
[current
].name
, name
, 15);
418 temp_list
[current
].type
=type
;
419 temp_list
[current
].empty
=0;
421 temp_list
[current
].name_flag
=wins_flags
;
423 if ( (wins_flags
&0x03) == 1 || (wins_flags
&0x03)==2)
424 temp_list
[current
].group_flag
=0x01000000;
426 temp_list
[current
].group_flag
=0x00000000;
428 temp_list
[current
].id
=id
;
430 temp_list
[current
].owner
.s_addr
=ip_list
[0].s_addr
;
432 if (temp_list
[current
].name_flag
& 2) {
433 temp_list
[current
].num_ip
=num_ips
;
434 temp_list
[current
].others
=(struct in_addr
*)talloc(mem_ctx
, sizeof(struct in_addr
)*num_ips
);
435 if (temp_list
[current
].others
==NULL
)
438 for (i
=0; i
<num_ips
; i
++)
439 temp_list
[current
].others
[i
].s_addr
=ip_list
[i
].s_addr
;
442 temp_list
[current
].num_ip
=1;
444 temp_list
[current
].foo
=0xffffffff;
446 *wins_name
=temp_list
;
451 /****************************************************************************
452 send the list of name we have.
453 ****************************************************************************/
454 static void send_entry_request(GENERIC_PACKET
*q
, GENERIC_PACKET
*r
)
458 time_t time_now
= time(NULL
);
459 WINS_OWNER
*wins_owner
;
461 TDB_DATA kbuf
, dbuf
, newkey
;
462 int s_ctx
=get_server_assoc(q
->header
.assoc_ctx
);
463 int num_interfaces
= iface_count();
466 DEBUG(1, ("send_entry_request: request for a partner not in our table\n"));
467 stop_packet(q
, r
, STOP_REASON_USER_REASON
);
472 wins_owner
=&q
->rep
.se_rq
.wins_owner
;
473 r
->rep
.se_rp
.wins_name
=NULL
;
475 DEBUG(3,("send_entry_request: we have been asked to send the list of wins records\n"));
476 DEBUGADD(3,("owned by: %s and between min: %d and max: %d\n", inet_ntoa(wins_owner
->address
),
477 (int)wins_owner
->min_version
, (int)wins_owner
->max_version
));
480 * if we are asked to send records owned by us
481 * we overwrite the wins ip with 0.0.0.0
482 * to make it easy in case of multihomed
485 for (i
=0; i
<num_interfaces
; i
++)
486 if (ip_equal(wins_owner
->address
, *iface_n_ip(i
))) {
487 wins_owner
->address
=*interpret_addr2("0.0.0.0");
492 tdb
= tdb_open_log(lock_path(WINS_LIST
), 0, TDB_DEFAULT
, O_RDONLY
, 0600);
494 DEBUG(2,("send_entry_request: Can't open wins database file %s. Error was %s\n", WINS_LIST
, strerror(errno
) ));
498 for (kbuf
= tdb_firstkey(tdb
);
500 newkey
= tdb_nextkey(tdb
, kbuf
), safe_free(kbuf
.dptr
), kbuf
=newkey
) {
502 pstring name
, ip_str
;
507 unsigned int num_ips
;
509 SMB_BIG_UINT version
;
510 struct in_addr wins_ip
;
511 struct in_addr
*ip_list
;
515 if (strncmp(kbuf
.dptr
, ENTRY_PREFIX
, strlen(ENTRY_PREFIX
)) != 0)
519 dbuf
= tdb_fetch(tdb
, kbuf
);
523 fstrcpy(name_type
, kbuf
.dptr
+strlen(ENTRY_PREFIX
));
524 pstrcpy(name
, name_type
);
526 if((p
= strchr(name
,'#')) != NULL
) {
528 sscanf(p
+1,"%x",&type
);
531 len
= tdb_unpack(dbuf
.dptr
, dbuf
.dsize
, "dddfddd",
540 wins_ip
=*interpret_addr2(ip_str
);
542 /* Allocate the space for the ip_list. */
543 if((ip_list
= (struct in_addr
*)talloc(mem_ctx
, num_ips
* sizeof(struct in_addr
))) == NULL
) {
544 SAFE_FREE(dbuf
.dptr
);
545 DEBUG(0,("initialise_wins: talloc fail !\n"));
549 for (i
= 0; i
< num_ips
; i
++) {
550 len
+= tdb_unpack(dbuf
.dptr
+len
, dbuf
.dsize
-len
, "f", ip_str
);
551 ip_list
[i
] = *interpret_addr2(ip_str
);
554 SAFE_FREE(dbuf
.dptr
);
556 /* add all entries that have 60 seconds or more to live */
557 if ((ttl
- 60) > time_now
|| ttl
== PERMANENT_TTL
) {
558 if(ttl
!= PERMANENT_TTL
)
561 DEBUG( 4, ("send_entry_request: add name: %s#%02x ttl = %d first IP %s flags = %2x\n",
562 name
, type
, ttl
, inet_ntoa(ip_list
[0]), nb_flags
));
564 /* add the record to the list to send */
565 version
=((SMB_BIG_UINT
)high
)<<32 | low
;
567 if (wins_owner
->min_version
<=version
&& wins_owner
->max_version
>=version
&&
568 wins_owner
->address
.s_addr
==wins_ip
.s_addr
) {
569 if(!add_record_to_winsname(&r
->rep
.se_rp
.wins_name
, &max_names
, name
, type
, wins_flags
, version
, ip_list
, num_ips
))
575 DEBUG(4, ("send_entry_request: not adding name (ttl problem) %s#%02x ttl = %d first IP %s flags = %2x\n",
576 name
, type
, ttl
, inet_ntoa(ip_list
[0]), nb_flags
));
582 DEBUG(4,("send_entry_request, sending %d records\n", max_names
));
583 fill_header(r
, OPCODE_NON_NBT
, s_ctx
, MESSAGE_TYPE_REPLICATE
);
584 r
->rep
.msg_type
=MESSAGE_REP_SEND_ENTRIES_REPLY
; /* reply */
585 r
->rep
.se_rp
.max_names
=max_names
;
589 /****************************************************************************
591 ****************************************************************************/
592 static void update_notify_request(GENERIC_PACKET
*q
, GENERIC_PACKET
*r
)
595 UPDATE_NOTIFY_REQUEST
*u
;
596 int s_ctx
=get_server_assoc(q
->header
.assoc_ctx
);
599 DEBUG(4, ("update_notify_request: request for a partner not in our table\n"));
600 stop_packet(q
, r
, STOP_REASON_USER_REASON
);
606 /* check if we already have the range of records */
608 DEBUG(5,("update_notify_request: wins server: %s offered this list of %d records:\n",
609 inet_ntoa(u
->initiating_wins_server
), u
->partner_count
));
611 get_our_last_id(&global_wins_table
[0][0]);
613 for (i
=0; i
<partner_count
; i
++) {
614 if (global_wins_table
[0][i
].address
.s_addr
==u
->initiating_wins_server
.s_addr
) {
615 DEBUG(5,("update_notify_request: found initiator at index %d\n", i
));
621 * some explanation is required, before someone say it's crap.
623 * let's take an example, we have 2 wins partners, we already now
624 * that our max id is 10, partner 1 ID is 20 and partner 2 ID is 30
625 * the array looks like:
632 * we receive an update from partner 2 saying he has: 1:15, 2:40, 3:50
633 * we must enlarge the array to add partner 3, it will look like:
640 * now we know, we should pull from partner 2, the records 30->40 of 2 and 0->50 of 3.
641 * once the pull will be over, our table will look like:
651 for (j
=0; j
<u
->partner_count
;j
++) {
653 * search if we already have this entry or if it's a new one
654 * it can be a new one in case of propagation
657 for (k
=0; global_wins_table
[0][k
].address
.s_addr
!=0 &&
658 global_wins_table
[0][k
].address
.s_addr
!=u
->wins_owner
[j
].address
.s_addr
; k
++);
660 global_wins_table
[i
][k
].address
.s_addr
=u
->wins_owner
[j
].address
.s_addr
;
661 global_wins_table
[i
][k
].max_version
=u
->wins_owner
[j
].max_version
;
662 global_wins_table
[i
][k
].min_version
=u
->wins_owner
[j
].min_version
;
663 global_wins_table
[i
][k
].type
=u
->wins_owner
[j
].type
;
666 * in case it's a new one, rewrite the address for all the partner
667 * to reserve the slot.
670 for(l
=0; l
<partner_count
; l
++)
671 global_wins_table
[l
][k
].address
.s_addr
=u
->wins_owner
[j
].address
.s_addr
;
676 stop_packet(q
, r
, STOP_REASON_USER_REASON
);
679 /****************************************************************************
681 ****************************************************************************/
682 static void send_entry_reply(GENERIC_PACKET
*q
, GENERIC_PACKET
*r
)
685 struct in_addr partner
, server
;
687 int s_ctx
=get_server_assoc(q
->header
.assoc_ctx
);
691 DEBUG(1, ("send_entry_reply: request for a partner not in our table\n"));
692 stop_packet(q
, r
, STOP_REASON_USER_REASON
);
696 DEBUG(5,("send_entry_reply:got %d new records\n", q
->rep
.se_rp
.max_names
));
698 /* we got records from a wins partner but that can be from another wins server */
699 /* hopefully we track that */
701 /* and the only doc available from MS is wrong ! */
703 get_server_assoc_table(q
->header
.assoc_ctx
, &partner
, &server
);
705 for (j
=0; global_wins_table
[0][j
].address
.s_addr
!=0; j
++) {
706 if (global_wins_table
[0][j
].address
.s_addr
==server
.s_addr
) {
707 DEBUG(5,("send_entry_reply: found server at index %d\n", j
));
712 pid
= pidfile_pid("nmbd");
714 DEBUG(0,("send_entry_reply: Can't find pid for nmbd\n"));
718 for (k
=0; k
<q
->rep
.se_rp
.max_names
; k
++) {
719 DEBUG(5,("send_entry_reply: %s<%02x> %d\n", q
->rep
.se_rp
.wins_name
[k
].name
, q
->rep
.se_rp
.wins_name
[k
].type
,
720 (int)q
->rep
.se_rp
.wins_name
[k
].id
));
722 safe_strcpy(record
.name
, q
->rep
.se_rp
.wins_name
[k
].name
, 16);
723 record
.type
=q
->rep
.se_rp
.wins_name
[k
].type
;
724 record
.id
=q
->rep
.se_rp
.wins_name
[k
].id
;
725 record
.wins_flags
=q
->rep
.se_rp
.wins_name
[k
].name_flag
&0x00ff;
726 record
.num_ips
=q
->rep
.se_rp
.wins_name
[k
].num_ip
;
728 record
.wins_ip
.s_addr
=server
.s_addr
;
730 if (record
.num_ips
==1)
731 record
.ip
[0]=q
->rep
.se_rp
.wins_name
[k
].owner
;
733 for (i
=0; i
<record
.num_ips
; i
++)
734 record
.ip
[i
]=q
->rep
.se_rp
.wins_name
[k
].others
[i
];
738 if (record
.wins_flags
&WINS_NGROUP
|| record
.wins_flags
&WINS_SGROUP
)
739 record
.nb_flags
|=NB_GROUP
;
741 if (record
.wins_flags
&WINS_ACTIVE
)
742 record
.nb_flags
|=NB_ACTIVE
;
744 record
.nb_flags
|=record
.wins_flags
&WINS_HNODE
;
746 message_send_pid(pid
, MSG_WINS_NEW_ENTRY
, &record
, sizeof(record
), False
);
753 * we got some entries,
754 * ask the partner to send us the map table again
755 * to get the other servers entries.
757 * we're getting the map table 1 time more than really
758 * required. We could remove that call, but that
759 * would complexify the code. I prefer this trade-of.
761 fill_header(r
, OPCODE_NON_NBT
, s_ctx
, MESSAGE_TYPE_REPLICATE
);
763 r
->rep
.msg_type
=MESSAGE_REP_ADD_VERSION_REQUEST
;
766 /****************************************************************************
767 decode the replication message and reply.
768 ****************************************************************************/
769 static void replicate(GENERIC_PACKET
*q
, GENERIC_PACKET
*r
)
771 switch (q
->rep
.msg_type
) {
773 /* add version number map table request */
774 send_version_number_map_table(q
, r
);
777 receive_version_number_map_table(q
, r
);
780 /* send entry request */
781 send_entry_request(q
, r
);
784 /* send entry reply */
785 send_entry_reply(q
, r
);
788 /* update notification request */
789 update_notify_request(q
, r
);
794 /****************************************************************************
795 do a switch on the message type, and return the response size
796 ****************************************************************************/
797 static BOOL
switch_message(GENERIC_PACKET
*q
, GENERIC_PACKET
*r
)
799 switch (q
->header
.mess_type
) {
801 /* Start association type */
802 start_assoc_process(q
, r
);
806 /* start association reply */
807 start_assoc_reply(q
, r
);
811 /* stop association message */
815 /* replication message */
825 /****************************************************************************
826 construct a reply to the incoming packet
827 ****************************************************************************/
828 void construct_reply(struct wins_packet_struct
*p
)
831 struct BUFFER buffer
;
837 DEBUG(5,("dump: received packet\n"));
838 dump_generic_packet(p
->packet
);
840 /* Verify if the request we got is from a listed partner */
841 if (!check_partner(p
->packet
->header
.assoc_ctx
)) {
845 fstrcpy(peer
,get_socket_addr(p
->fd
));
846 addr
=*interpret_addr2(peer
);
848 for (i
=1; i
<partner_count
; i
++)
849 if (ip_equal(addr
, global_wins_table
[0][i
].address
))
852 if (i
==partner_count
) {
853 DEBUG(1,("construct_reply: got a request from a non peer machine: %s\n", peer
));
854 stop_packet(p
->packet
, &r
, STOP_REASON_AUTH_FAILED
);
856 encode_generic_packet(&buffer
, &r
);
857 if (!send_smb(p
->fd
, buffer
.buffer
))
858 exit_server("process_smb: send_smb failed.");
863 if (switch_message(p
->packet
, &r
)) {
864 encode_generic_packet(&buffer
, &r
);
865 DEBUG(5,("dump: sending packet\n"));
866 dump_generic_packet(&r
);
868 if(buffer
.offset
> 0) {
869 if (!send_smb(p
->fd
, buffer
.buffer
))
870 exit_server("process_smb: send_smb failed.");
874 /* if we got a stop assoc or if we send a stop assoc, close the fd after */
875 if (p
->packet
->header
.mess_type
==MESSAGE_TYPE_STOP_ASSOC
||
876 r
.header
.mess_type
==MESSAGE_TYPE_STOP_ASSOC
) {
877 remove_partner(p
->packet
->header
.assoc_ctx
);
882 /****************************************************************************
883 contact periodically our wins partner to do a pull replication
884 ****************************************************************************/
885 void run_pull_replication(time_t t
)
887 /* we pull every 30 minutes to query about new records*/
889 struct BUFFER buffer
;
896 for (i
=1; i
<partner_count
; i
++) {
897 if (global_wins_table
[0][i
].last_pull
< t
) {
898 global_wins_table
[0][i
].last_pull
=t
+30*60; /* next in 30 minutes */
900 /* contact the wins server */
901 p
.header
.mess_type
=MESSAGE_TYPE_START_ASSOC_REQUEST
;
902 p
.header
.opcode
=OPCODE_NON_NBT
;
903 p
.header
.assoc_ctx
=0;
904 p
.sa_rq
.assoc_ctx
=(int)t
;
908 DEBUG(3,("run_pull_replication: contacting wins server %s.\n", inet_ntoa(global_wins_table
[0][i
].address
)));
909 encode_generic_packet(&buffer
, &p
);
910 dump_generic_packet(&p
);
912 /* send the packet to the server and add the descriptor to receive answers */
913 s
=open_socket_out(SOCK_STREAM
, &global_wins_table
[0][i
].address
, 42, LONG_CONNECT_TIMEOUT
);
915 DEBUG(0,("run_pull_replication: can't contact wins server %s.\n", inet_ntoa(global_wins_table
[0][i
].address
)));
919 if(buffer
.offset
> 0) {
920 if (!send_smb(s
, buffer
.buffer
))
921 exit_server("run_pull_replication: send_smb failed.");
924 add_fd_to_sock_array(s
);
925 FD_SET(s
, listen_set
);
927 /* add ourself as a client */
928 add_partner((int)t
, 0, True
, False
);
933 /****************************************************************************
934 contact periodically our wins partner to do a push replication
935 ****************************************************************************/
936 void run_push_replication(time_t t
)
938 /* we push every 30 minutes or 25 new entries */
940 struct BUFFER buffer
;
947 for (i
=1; i
<partner_count
; i
++) {
948 if (global_wins_table
[0][i
].last_pull
< t
) {
949 global_wins_table
[0][i
].last_pull
=t
+30*60; /* next in 30 minutes */
951 /* contact the wins server */
952 p
.header
.mess_type
=MESSAGE_TYPE_START_ASSOC_REQUEST
;
953 p
.header
.opcode
=OPCODE_NON_NBT
;
954 p
.header
.assoc_ctx
=0;
955 p
.sa_rq
.assoc_ctx
=(int)t
;
959 DEBUG(3,("run_push_replication: contacting wins server %s.\n", inet_ntoa(global_wins_table
[0][i
].address
)));
960 encode_generic_packet(&buffer
, &p
);
961 dump_generic_packet(&p
);
963 /* send the packet to the server and add the descriptor to receive answers */
964 s
=open_socket_out(SOCK_STREAM
, &global_wins_table
[0][i
].address
, 42, LONG_CONNECT_TIMEOUT
);
966 DEBUG(0,("run_push_replication: can't contact wins server %s.\n", inet_ntoa(global_wins_table
[0][i
].address
)));
970 if(buffer
.offset
> 0) {
971 if (!send_smb(s
, buffer
.buffer
))
972 exit_server("run_push_replication: send_smb failed.");
975 add_fd_to_sock_array(s
);
976 FD_SET(s
, listen_set
);
978 /* add ourself as a client */
979 add_partner((int)t
, 0, False
, True
);