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(0,("\n%d ", i
));
63 for (j
=0; global_wins_table
[i
][j
].address
.s_addr
!=0; j
++)
64 DEBUG(0,("%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(0,("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(0,("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
= lp_list_make(lp_wins_partners());
157 DEBUG(0, ("init_wins_partner_table: partners: %s\n", lp_wins_partners()));
159 global_wins_table
[0][0].address
=*iface_n_ip(0);
160 global_wins_table
[0][0].max_version
=0;
161 global_wins_table
[0][0].min_version
=0;
162 global_wins_table
[0][0].type
=0;
164 while (partner
[j
]!=NULL
) {
165 DEBUG(0,("init_wins_partner_table, adding partner: %s\n", partner
[j
]));
167 global_wins_table
[0][i
].address
=*interpret_addr2(partner
[j
]);
168 global_wins_table
[0][i
].max_version
=0;
169 global_wins_table
[0][i
].min_version
=0;
170 global_wins_table
[0][i
].type
=0;
171 global_wins_table
[0][i
].last_pull
=0;
172 global_wins_table
[0][i
].last_push
=0;
180 global_wins_table
[k
][j
]=global_wins_table
[0][j
];
182 lp_list_free (&partner
);
187 /****************************************************************************
188 read the last ID from the wins tdb file.
189 ****************************************************************************/
190 static void get_our_last_id(WINS_OWNER
*wins_owner
)
194 tdb
= tdb_open_log(lock_path(WINS_LIST
), 0, TDB_DEFAULT
, O_RDONLY
, 0600);
196 DEBUG(2,("get_our_last_id: Can't open wins database file %s. Error was %s\n", WINS_LIST
, strerror(errno
) ));
200 wins_owner
->max_version
=((SMB_BIG_UINT
)tdb_fetch_int(tdb
, INFO_ID_HIGH
))<<32 |
201 (SMB_BIG_UINT
)tdb_fetch_int(tdb
, INFO_ID_LOW
);
206 /****************************************************************************
207 send the list of wins server we know.
208 ****************************************************************************/
209 static void send_version_number_map_table(GENERIC_PACKET
*q
, GENERIC_PACKET
*r
)
212 int s_ctx
=get_server_assoc(q
->header
.assoc_ctx
);
215 DEBUG(0, ("send_entry_reply: request for a partner not in our table\n"));
216 stop_packet(q
, r
, STOP_REASON_USER_REASON
);
221 * return an array of wins servers, we are partner with.
222 * each entry contains the IP address and the version info
223 * version: ID of the last entry we've got
226 /* the first wins server must be self */
229 * get our last ID from the wins database
230 * it can have been updated since last read
231 * as nmbd got registration/release.
233 get_our_last_id(&global_wins_table
[0][0]);
235 r
->rep
.avmt_rep
.wins_owner
=(WINS_OWNER
*)talloc(mem_ctx
, partner_count
*sizeof(WINS_OWNER
));
236 if (r
->rep
.avmt_rep
.wins_owner
==NULL
) {
237 stop_packet(q
, r
, STOP_REASON_USER_REASON
);
241 DEBUG(0,("send_version_number_map_table: partner_count: %d\n", partner_count
));
243 for (i
=0; i
<partner_count
; i
++) {
244 DEBUG(0,("send_version_number_map_table, partner: %d -> %s, \n", i
, inet_ntoa(global_wins_table
[0][i
].address
)));
245 r
->rep
.avmt_rep
.wins_owner
[i
]=global_wins_table
[0][i
];
249 r
->rep
.avmt_rep
.partner_count
=partner_count
;
250 r
->rep
.avmt_rep
.initiating_wins_server
.s_addr
=0; /* blatant lie, NT4/w2K do the same ! */
251 fill_header(r
, OPCODE_NON_NBT
, s_ctx
, MESSAGE_TYPE_REPLICATE
);
254 /****************************************************************************
255 for a given partner, ask it to send entries we don't have.
256 ****************************************************************************/
257 static BOOL
check_partners_and_send_entries(GENERIC_PACKET
*q
, GENERIC_PACKET
*r
, int partner
)
262 SMB_BIG_UINT current
;
266 * we check if our partner has more records than us.
267 * we need to check more than our direct partners as
268 * we can have this case:
269 * us: A, partners: B,C, indirect partner: D
270 * A<->B, A<->C, B<->D, C<->D
272 * So if we're talking to B, we need to check if between
273 * B and C, which one have more records about D.
274 * and also check if we don't already have the records.
278 /* check all servers even indirect */
279 for (server
=1; global_wins_table
[0][server
].address
.s_addr
!=0; server
++) {
280 current
= global_wins_table
[partner
][server
].max_version
;
284 for (other
=1; other
<partner_count
; other
++) {
285 /* skip the partner itself */
289 if (global_wins_table
[other
][server
].max_version
> temp
)
290 temp
=global_wins_table
[other
][server
].max_version
;
293 if (current
>= temp
&& current
> global_wins_table
[0][server
].max_version
) {
295 * it has more records than every body else and more than us,
296 * ask it the difference between what we have and what it has
298 fill_header(r
, OPCODE_NON_NBT
, get_server_assoc(q
->header
.assoc_ctx
), MESSAGE_TYPE_REPLICATE
);
300 r
->rep
.msg_type
=MESSAGE_REP_SEND_ENTRIES_REQUEST
;
301 r
->rep
.se_rq
.wins_owner
.address
=global_wins_table
[partner
][server
].address
;
303 r
->rep
.se_rq
.wins_owner
.max_version
=global_wins_table
[partner
][server
].max_version
;
304 r
->rep
.se_rq
.wins_owner
.min_version
=global_wins_table
[0][server
].max_version
;
305 r
->rep
.se_rq
.wins_owner
.type
=0;
307 write_server_assoc_table(q
->header
.assoc_ctx
, global_wins_table
[0][partner
].address
, global_wins_table
[partner
][server
].address
);
310 * and we update our version for this server
311 * as we can't use the IDs returned in the send_entries function
312 * the max ID can be larger than the largest ID returned
315 global_wins_table
[0][server
].max_version
=global_wins_table
[partner
][server
].max_version
;
323 /****************************************************************************
324 receive the list of wins server we know.
325 ****************************************************************************/
326 static void receive_version_number_map_table(GENERIC_PACKET
*q
, GENERIC_PACKET
*r
)
331 int s_ctx
=get_server_assoc(q
->header
.assoc_ctx
);
334 DEBUG(0, ("receive_version_number_map_table: request for a partner not in our table\n"));
335 stop_packet(q
, r
, STOP_REASON_USER_REASON
);
339 fstrcpy(peer
,get_socket_addr(q
->fd
));
340 addr
=*interpret_addr2(peer
);
342 get_our_last_id(&global_wins_table
[0][0]);
344 DEBUG(0,("receive_version_number_map_table: received a map of %d server from: %s\n",
345 q
->rep
.avmt_rep
.partner_count
,inet_ntoa(q
->rep
.avmt_rep
.initiating_wins_server
)));
346 DEBUG(0,("real peer is: %s\n", peer
));
348 for (i
=0; global_wins_table
[0][i
].address
.s_addr
!=addr
.s_addr
&& i
<partner_count
;i
++)
351 if (i
==partner_count
) {
352 DEBUG(0,("receive_version_number_map_table: unknown partner: %s\n", peer
));
353 stop_packet(q
, r
, STOP_REASON_USER_REASON
);
357 for (j
=0; j
<q
->rep
.avmt_rep
.partner_count
;j
++) {
359 * search if we already have this entry or if it's a new one
360 * it can be a new one in case of propagation
362 for (k
=0; global_wins_table
[0][k
].address
.s_addr
!=0 &&
363 global_wins_table
[0][k
].address
.s_addr
!=q
->rep
.avmt_rep
.wins_owner
[j
].address
.s_addr
; k
++);
365 global_wins_table
[i
][k
].address
.s_addr
=q
->rep
.avmt_rep
.wins_owner
[j
].address
.s_addr
;
366 global_wins_table
[i
][k
].max_version
=q
->rep
.avmt_rep
.wins_owner
[j
].max_version
;
367 global_wins_table
[i
][k
].min_version
=q
->rep
.avmt_rep
.wins_owner
[j
].min_version
;
368 global_wins_table
[i
][k
].type
=q
->rep
.avmt_rep
.wins_owner
[j
].type
;
371 * in case it's a new one, rewrite the address for all the partner
372 * to reserve the slot.
375 for(l
=0; l
<partner_count
; l
++)
376 global_wins_table
[l
][k
].address
.s_addr
=q
->rep
.avmt_rep
.wins_owner
[j
].address
.s_addr
;
382 * if this server have newer records than what we have
383 * for several wins servers, we need to ask it.
384 * Alas a send entry request is only on one server.
385 * So in the send entry reply, we'll ask for the next server is required.
388 if (check_partners_and_send_entries(q
, r
, i
))
391 /* it doesn't have more entries than us */
392 stop_packet(q
, r
, STOP_REASON_USER_REASON
);
395 /****************************************************************************
396 add an entry to the wins list we'll send.
397 ****************************************************************************/
398 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
)
400 WINS_NAME
*temp_list
;
402 int current
=*max_names
;
404 temp_list
=talloc_realloc(mem_ctx
, *wins_name
, (current
+1)*sizeof(WINS_NAME
));
408 temp_list
[current
].name_len
=0x11;
410 safe_strcpy(temp_list
[current
].name
, name
, 15);
412 temp_list
[current
].type
=type
;
413 temp_list
[current
].empty
=0;
415 temp_list
[current
].name_flag
=wins_flags
;
417 if ( (wins_flags
&0x03) == 1 || (wins_flags
&0x03)==2)
418 temp_list
[current
].group_flag
=0x01000000;
420 temp_list
[current
].group_flag
=0x00000000;
422 temp_list
[current
].id
=id
;
424 temp_list
[current
].owner
.s_addr
=ip_list
[0].s_addr
;
426 if (temp_list
[current
].name_flag
& 2) {
427 temp_list
[current
].num_ip
=num_ips
;
428 temp_list
[current
].others
=(struct in_addr
*)talloc(mem_ctx
, sizeof(struct in_addr
)*num_ips
);
429 if (temp_list
[current
].others
==NULL
)
432 for (i
=0; i
<num_ips
; i
++)
433 temp_list
[current
].others
[i
].s_addr
=ip_list
[i
].s_addr
;
436 temp_list
[current
].num_ip
=1;
438 temp_list
[current
].foo
=0xffffffff;
440 *wins_name
=temp_list
;
445 /****************************************************************************
446 send the list of name we have.
447 ****************************************************************************/
448 static void send_entry_request(GENERIC_PACKET
*q
, GENERIC_PACKET
*r
)
452 time_t time_now
= time(NULL
);
453 WINS_OWNER
*wins_owner
;
455 TDB_DATA kbuf
, dbuf
, newkey
;
456 int s_ctx
=get_server_assoc(q
->header
.assoc_ctx
);
457 int num_interfaces
= iface_count();
460 DEBUG(0, ("send_entry_request: request for a partner not in our table\n"));
461 stop_packet(q
, r
, STOP_REASON_USER_REASON
);
466 wins_owner
=&q
->rep
.se_rq
.wins_owner
;
467 r
->rep
.se_rp
.wins_name
=NULL
;
469 DEBUG(0,("send_entry_request: we have been asked to send the list of wins records\n"));
470 DEBUGADD(0,("owned by: %s and between min: %d and max: %d\n", inet_ntoa(wins_owner
->address
),
471 (int)wins_owner
->min_version
, (int)wins_owner
->max_version
));
474 * if we are asked to send records owned by us
475 * we overwrite the wins ip with 0.0.0.0
476 * to make it easy in case of multihomed
479 for (i
=0; i
<num_interfaces
; i
++)
480 if (ip_equal(wins_owner
->address
, *iface_n_ip(i
))) {
481 wins_owner
->address
=*interpret_addr2("0.0.0.0");
486 tdb
= tdb_open_log(lock_path(WINS_LIST
), 0, TDB_DEFAULT
, O_RDONLY
, 0600);
488 DEBUG(2,("send_entry_request: Can't open wins database file %s. Error was %s\n", WINS_LIST
, strerror(errno
) ));
492 for (kbuf
= tdb_firstkey(tdb
);
494 newkey
= tdb_nextkey(tdb
, kbuf
), safe_free(kbuf
.dptr
), kbuf
=newkey
) {
495 pstring name_type
, name
, ip_str
;
500 unsigned int num_ips
;
502 SMB_BIG_UINT version
;
503 struct in_addr wins_ip
;
504 struct in_addr
*ip_list
;
508 if (strncmp(kbuf
.dptr
, ENTRY_PREFIX
, strlen(ENTRY_PREFIX
)) != 0)
512 dbuf
= tdb_fetch(tdb
, kbuf
);
516 fstrcpy(name_type
, kbuf
.dptr
+strlen(ENTRY_PREFIX
));
517 pstrcpy(name
, name_type
);
519 if((p
= strchr(name
,'#')) != NULL
) {
521 sscanf(p
+1,"%x",&type
);
524 len
= tdb_unpack(dbuf
.dptr
, dbuf
.dsize
, "dddfddd",
533 wins_ip
=*interpret_addr2(ip_str
);
535 /* Allocate the space for the ip_list. */
536 if((ip_list
= (struct in_addr
*)talloc(mem_ctx
, num_ips
* sizeof(struct in_addr
))) == NULL
) {
537 DEBUG(0,("initialise_wins: talloc fail !\n"));
541 for (i
= 0; i
< num_ips
; i
++) {
542 len
+= tdb_unpack(dbuf
.dptr
+len
, dbuf
.dsize
-len
, "f", ip_str
);
543 ip_list
[i
] = *interpret_addr2(ip_str
);
546 /* add all entries that have 60 seconds or more to live */
547 if ((ttl
- 60) > time_now
|| ttl
== PERMANENT_TTL
) {
548 if(ttl
!= PERMANENT_TTL
)
551 DEBUG( 4, ("send_entry_request: add name: %s#%02x ttl = %d first IP %s flags = %2x\n",
552 name
, type
, ttl
, inet_ntoa(ip_list
[0]), nb_flags
));
554 /* add the record to the list to send */
555 version
=((SMB_BIG_UINT
)high
)<<32 | low
;
557 if (wins_owner
->min_version
<=version
&& wins_owner
->max_version
>=version
&&
558 wins_owner
->address
.s_addr
==wins_ip
.s_addr
) {
559 if(!add_record_to_winsname(&r
->rep
.se_rp
.wins_name
, &max_names
, name
, type
, wins_flags
, version
, ip_list
, num_ips
))
565 DEBUG(4, ("send_entry_request: not adding name (ttl problem) %s#%02x ttl = %d first IP %s flags = %2x\n",
566 name
, type
, ttl
, inet_ntoa(ip_list
[0]), nb_flags
));
572 DEBUG(0,("send_entry_request, sending %d records\n", max_names
));
573 fill_header(r
, OPCODE_NON_NBT
, s_ctx
, MESSAGE_TYPE_REPLICATE
);
574 r
->rep
.msg_type
=MESSAGE_REP_SEND_ENTRIES_REPLY
; /* reply */
575 r
->rep
.se_rp
.max_names
=max_names
;
579 /****************************************************************************
581 ****************************************************************************/
582 static void update_notify_request(GENERIC_PACKET
*q
, GENERIC_PACKET
*r
)
585 UPDATE_NOTIFY_REQUEST
*u
;
586 int s_ctx
=get_server_assoc(q
->header
.assoc_ctx
);
589 DEBUG(0, ("send_entry_reply: request for a partner not in our table\n"));
590 stop_packet(q
, r
, STOP_REASON_USER_REASON
);
596 /* check if we already have the range of records */
598 DEBUG(0,("update_notify_request: wins server: %s offered this list of %d records:\n",
599 inet_ntoa(u
->initiating_wins_server
), u
->partner_count
));
601 get_our_last_id(&global_wins_table
[0][0]);
603 for (i
=0; i
<partner_count
; i
++) {
604 if (global_wins_table
[0][i
].address
.s_addr
==u
->initiating_wins_server
.s_addr
) {
605 DEBUG(0,("update_notify_request: found initiator at index %d\n", i
));
611 * some explanation is required, before someone say it's crap.
613 * let's take an example, we have 2 wins partners, we already now
614 * that our max id is 10, partner 1 ID is 20 and partner 2 ID is 30
615 * the array looks like:
622 * we receive an update from partner 2 saying he has: 1:15, 2:40, 3:50
623 * we must enlarge the array to add partner 3, it will look like:
630 * now we know, we should pull from partner 2, the records 30->40 of 2 and 0->50 of 3.
631 * once the pull will be over, our table will look like:
641 for (j
=0; j
<u
->partner_count
;j
++) {
643 * search if we already have this entry or if it's a new one
644 * it can be a new one in case of propagation
647 for (k
=0; global_wins_table
[0][k
].address
.s_addr
!=0 &&
648 global_wins_table
[0][k
].address
.s_addr
!=u
->wins_owner
[j
].address
.s_addr
; k
++);
650 global_wins_table
[i
][k
].address
.s_addr
=u
->wins_owner
[j
].address
.s_addr
;
651 global_wins_table
[i
][k
].max_version
=u
->wins_owner
[j
].max_version
;
652 global_wins_table
[i
][k
].min_version
=u
->wins_owner
[j
].min_version
;
653 global_wins_table
[i
][k
].type
=u
->wins_owner
[j
].type
;
656 * in case it's a new one, rewrite the address for all the partner
657 * to reserve the slot.
660 for(l
=0; l
<partner_count
; l
++)
661 global_wins_table
[l
][k
].address
.s_addr
=u
->wins_owner
[j
].address
.s_addr
;
666 stop_packet(q
, r
, STOP_REASON_USER_REASON
);
669 /****************************************************************************
671 ****************************************************************************/
672 static void send_entry_reply(GENERIC_PACKET
*q
, GENERIC_PACKET
*r
)
675 struct in_addr partner
, server
;
677 int s_ctx
=get_server_assoc(q
->header
.assoc_ctx
);
681 DEBUG(0, ("send_entry_reply: request for a partner not in our table\n"));
682 stop_packet(q
, r
, STOP_REASON_USER_REASON
);
686 DEBUG(0,("send_entry_reply:got %d new records\n", q
->rep
.se_rp
.max_names
));
688 /* we got records from a wins partner but that can be from another wins server */
689 /* hopefully we track that */
691 /* and the only doc available from MS is wrong ! */
693 get_server_assoc_table(q
->header
.assoc_ctx
, &partner
, &server
);
695 for (j
=0; global_wins_table
[0][j
].address
.s_addr
!=0; j
++) {
696 if (global_wins_table
[0][j
].address
.s_addr
==server
.s_addr
) {
697 DEBUG(0,("send_entry_reply: found server at index %d\n", j
));
702 pid
= pidfile_pid("nmbd");
704 DEBUG(0,("send_entry_reply: Can't find pid for nmbd\n"));
708 for (k
=0; k
<q
->rep
.se_rp
.max_names
; k
++) {
709 DEBUG(0,("send_entry_reply: %s<%02x> %d\n", q
->rep
.se_rp
.wins_name
[k
].name
, q
->rep
.se_rp
.wins_name
[k
].type
,
710 (int)q
->rep
.se_rp
.wins_name
[k
].id
));
712 safe_strcpy(record
.name
, q
->rep
.se_rp
.wins_name
[k
].name
, 16);
713 record
.type
=q
->rep
.se_rp
.wins_name
[k
].type
;
714 record
.id
=q
->rep
.se_rp
.wins_name
[k
].id
;
715 record
.wins_flags
=q
->rep
.se_rp
.wins_name
[k
].name_flag
&0x00ff;
716 record
.num_ips
=q
->rep
.se_rp
.wins_name
[k
].num_ip
;
718 record
.wins_ip
.s_addr
=server
.s_addr
;
720 if (record
.num_ips
==1)
721 record
.ip
[0]=q
->rep
.se_rp
.wins_name
[k
].owner
;
723 for (i
=0; i
<record
.num_ips
; i
++)
724 record
.ip
[i
]=q
->rep
.se_rp
.wins_name
[k
].others
[i
];
728 if (record
.wins_flags
&WINS_NGROUP
|| record
.wins_flags
&WINS_SGROUP
)
729 record
.nb_flags
|=NB_GROUP
;
731 if (record
.wins_flags
&WINS_ACTIVE
)
732 record
.nb_flags
|=NB_ACTIVE
;
734 record
.nb_flags
|=record
.wins_flags
&WINS_HNODE
;
736 message_send_pid(pid
, MSG_WINS_NEW_ENTRY
, &record
, sizeof(record
), False
);
743 * we got some entries,
744 * ask the partner to send us the map table again
745 * to get the other servers entries.
747 * we're getting the map table 1 time more than really
748 * required. We could remove that call, but that
749 * would complexify the code. I prefer this trade-of.
751 fill_header(r
, OPCODE_NON_NBT
, s_ctx
, MESSAGE_TYPE_REPLICATE
);
753 r
->rep
.msg_type
=MESSAGE_REP_ADD_VERSION_REQUEST
;
756 /****************************************************************************
757 decode the replication message and reply.
758 ****************************************************************************/
759 static void replicate(GENERIC_PACKET
*q
, GENERIC_PACKET
*r
)
761 switch (q
->rep
.msg_type
) {
763 /* add version number map table request */
764 send_version_number_map_table(q
, r
);
767 receive_version_number_map_table(q
, r
);
770 /* send entry request */
771 send_entry_request(q
, r
);
774 /* send entry reply */
775 send_entry_reply(q
, r
);
778 /* update notification request */
779 update_notify_request(q
, r
);
784 /****************************************************************************
785 do a switch on the message type, and return the response size
786 ****************************************************************************/
787 static BOOL
switch_message(GENERIC_PACKET
*q
, GENERIC_PACKET
*r
)
789 switch (q
->header
.mess_type
) {
791 /* Start association type */
792 start_assoc_process(q
, r
);
796 /* start association reply */
797 start_assoc_reply(q
, r
);
801 /* stop association message */
803 * remove the partner from the list and
804 * reply false to NOT send a packet
806 remove_partner(q
->header
.assoc_ctx
);
810 /* replication message */
820 /****************************************************************************
821 construct a reply to the incoming packet
822 ****************************************************************************/
823 void construct_reply(struct wins_packet_struct
*p
)
826 struct BUFFER buffer
;
832 DEBUG(0,("dump: received packet\n"));
833 dump_generic_packet(p
->packet
);
835 /* Verify if the request we got is from a listed partner */
836 if (!check_partner(p
->packet
->header
.assoc_ctx
)) {
840 fstrcpy(peer
,get_socket_addr(p
->fd
));
841 addr
=*interpret_addr2(peer
);
843 for (i
=1; i
<partner_count
; i
++)
844 if (ip_equal(addr
, global_wins_table
[0][i
].address
))
847 if (i
==partner_count
) {
848 DEBUG(0,("construct_reply: got a request from a non peer machine: %s\n", peer
));
849 stop_packet(p
->packet
, &r
, STOP_REASON_AUTH_FAILED
);
851 encode_generic_packet(&buffer
, &r
);
852 if (!send_smb(p
->fd
, buffer
.buffer
))
853 exit_server("process_smb: send_smb failed.");
858 if (switch_message(p
->packet
, &r
)) {
859 encode_generic_packet(&buffer
, &r
);
860 DEBUG(0,("dump: sending packet\n"));
861 dump_generic_packet(&r
);
863 if(buffer
.offset
> 0) {
864 if (!send_smb(p
->fd
, buffer
.buffer
))
865 exit_server("process_smb: send_smb failed.");
869 /* if we got a stop assoc or if we send a stop assoc, close the fd after */
870 if (p
->packet
->header
.mess_type
==MESSAGE_TYPE_STOP_ASSOC
||
871 r
.header
.mess_type
==MESSAGE_TYPE_STOP_ASSOC
)
875 /****************************************************************************
876 contact periodically our wins partner to do a pull replication
877 ****************************************************************************/
878 void run_pull_replication(time_t t
)
880 /* we pull every 30 minutes to query about new records*/
882 struct BUFFER buffer
;
889 for (i
=1; i
<partner_count
; i
++) {
890 if (global_wins_table
[0][i
].last_pull
< t
) {
891 global_wins_table
[0][i
].last_pull
=t
+30*60; /* next in 30 minutes */
893 /* contact the wins server */
894 p
.header
.mess_type
=MESSAGE_TYPE_START_ASSOC_REQUEST
;
895 p
.header
.opcode
=OPCODE_NON_NBT
;
896 p
.header
.assoc_ctx
=0;
897 p
.sa_rq
.assoc_ctx
=(int)t
;
901 DEBUG(3,("run_pull_replication: contacting wins server %s.\n", inet_ntoa(global_wins_table
[0][i
].address
)));
902 encode_generic_packet(&buffer
, &p
);
903 dump_generic_packet(&p
);
905 /* send the packet to the server and add the descriptor to receive answers */
906 s
=open_socket_out(SOCK_STREAM
, &global_wins_table
[0][i
].address
, 42, LONG_CONNECT_TIMEOUT
);
908 DEBUG(0,("run_pull_replication: can't contact wins server %s.\n", inet_ntoa(global_wins_table
[0][i
].address
)));
912 if(buffer
.offset
> 0) {
913 if (!send_smb(s
, buffer
.buffer
))
914 exit_server("run_pull_replication: send_smb failed.");
917 add_fd_to_sock_array(s
);
918 FD_SET(s
, listen_set
);
920 /* add ourself as a client */
921 add_partner((int)t
, 0, True
, False
);
926 /****************************************************************************
927 contact periodically our wins partner to do a push replication
928 ****************************************************************************/
929 void run_push_replication(time_t t
)
931 /* we push every 30 minutes or 25 new entries */