Minor comment updates ...
[Samba/gebeck_regimport.git] / source3 / wrepld / process.c
blob1f96dc996cd79aecd917df7f264f805dd4fdd1fe
1 /*
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.
21 #include "includes.h"
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];
29 int partner_count;
31 TALLOC_CTX *mem_ctx;
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)
46 if (g==NULL)
47 return;
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)
59 int i,j;
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));
67 DEBUG(10,("\n"));
70 /*******************************************************************
71 start association
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 */
87 r->sa_rp.min_ver=1;
88 r->sa_rp.maj_ver=1;
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)
98 int i;
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);
104 return;
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);
110 return;
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"));
120 return;
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);
133 return;
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"));
140 return;
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)
154 int i=1,j=0,k;
155 char **partner = str_list_make(lp_wins_partners(), NULL);
157 if (partner==NULL) {
158 DEBUG(0,("wrepld: no partner list in smb.conf, exiting\n"));
159 exit_server("normal exit");
160 return(0);
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;
180 i++;
181 j++;
184 for (k=1; k<i;k++)
185 for (j=0; j<i; j++)
186 global_wins_table[k][j]=global_wins_table[0][j];
188 str_list_free (&partner);
190 return i;
193 /****************************************************************************
194 read the last ID from the wins tdb file.
195 ****************************************************************************/
196 static void get_our_last_id(WINS_OWNER *wins_owner)
198 TDB_CONTEXT *tdb;
200 tdb = tdb_open_log(lock_path(WINS_LIST), 0, TDB_DEFAULT, O_RDONLY, 0600);
201 if (!tdb) {
202 DEBUG(2,("get_our_last_id: Can't open wins database file %s. Error was %s\n", WINS_LIST, strerror(errno) ));
203 return;
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);
209 tdb_close(tdb);
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)
217 int i;
218 int s_ctx=get_server_assoc(q->header.assoc_ctx);
220 if (s_ctx==0) {
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);
223 return;
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);
244 return;
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];
254 r->rep.msg_type=1;
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)
265 int server;
266 int other;
267 SMB_BIG_UINT temp;
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;
288 temp=0;
290 for (other=1; other<partner_count; other++) {
291 /* skip the partner itself */
292 if (other==partner)
293 continue;
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;
323 return True;
326 return False;
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)
334 fstring peer;
335 struct in_addr addr;
336 int i,j,k,l;
337 int s_ctx=get_server_assoc(q->header.assoc_ctx);
339 if (s_ctx==0) {
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);
342 return;
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);
360 return;
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;
385 dump_global_table();
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))
395 return;
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;
407 int i;
408 int current=*max_names;
410 temp_list=talloc_realloc(mem_ctx, *wins_name, (current+1)*sizeof(WINS_NAME));
411 if (temp_list==NULL)
412 return False;
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;
425 else
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)
436 return False;
438 for (i=0; i<num_ips; i++)
439 temp_list[current].others[i].s_addr=ip_list[i].s_addr;
441 } else
442 temp_list[current].num_ip=1;
444 temp_list[current].foo=0xffffffff;
446 *wins_name=temp_list;
448 return True;
451 /****************************************************************************
452 send the list of name we have.
453 ****************************************************************************/
454 static void send_entry_request(GENERIC_PACKET *q, GENERIC_PACKET *r)
456 int max_names=0;
457 int i;
458 time_t time_now = time(NULL);
459 WINS_OWNER *wins_owner;
460 TDB_CONTEXT *tdb;
461 TDB_DATA kbuf, dbuf, newkey;
462 int s_ctx=get_server_assoc(q->header.assoc_ctx);
463 int num_interfaces = iface_count();
465 if (s_ctx==0) {
466 DEBUG(1, ("send_entry_request: request for a partner not in our table\n"));
467 stop_packet(q, r, STOP_REASON_USER_REASON);
468 return;
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");
488 break;
492 tdb = tdb_open_log(lock_path(WINS_LIST), 0, TDB_DEFAULT, O_RDONLY, 0600);
493 if (!tdb) {
494 DEBUG(2,("send_entry_request: Can't open wins database file %s. Error was %s\n", WINS_LIST, strerror(errno) ));
495 return;
498 for (kbuf = tdb_firstkey(tdb);
499 kbuf.dptr;
500 newkey = tdb_nextkey(tdb, kbuf), safe_free(kbuf.dptr), kbuf=newkey) {
501 fstring name_type;
502 pstring name, ip_str;
503 char *p;
504 int type = 0;
505 int nb_flags;
506 int ttl;
507 unsigned int num_ips;
508 int low, high;
509 SMB_BIG_UINT version;
510 struct in_addr wins_ip;
511 struct in_addr *ip_list;
512 int wins_flags;
513 int len;
515 if (strncmp(kbuf.dptr, ENTRY_PREFIX, strlen(ENTRY_PREFIX)) != 0)
516 continue;
519 dbuf = tdb_fetch(tdb, kbuf);
520 if (!dbuf.dptr)
521 continue;
523 fstrcpy(name_type, kbuf.dptr+strlen(ENTRY_PREFIX));
524 pstrcpy(name, name_type);
526 if((p = strchr(name,'#')) != NULL) {
527 *p = 0;
528 sscanf(p+1,"%x",&type);
531 len = tdb_unpack(dbuf.dptr, dbuf.dsize, "dddfddd",
532 &nb_flags,
533 &high,
534 &low,
535 ip_str,
536 &ttl,
537 &num_ips,
538 &wins_flags);
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"));
546 return;
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)
559 ttl -= time_now;
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))
570 return;
571 max_names++;
574 } else {
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));
580 tdb_close(tdb);
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)
594 int i,j,k,l;
595 UPDATE_NOTIFY_REQUEST *u;
596 int s_ctx=get_server_assoc(q->header.assoc_ctx);
598 if (s_ctx==0) {
599 DEBUG(4, ("update_notify_request: request for a partner not in our table\n"));
600 stop_packet(q, r, STOP_REASON_USER_REASON);
601 return;
604 u=&q->rep.un_rq;
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));
616 break;
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:
627 * 0 1 2
628 * 0 10 20 30
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:
635 * 0 1 2 3
636 * 0 10 20 30
638 * 2 15 40 50
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:
643 * 0 1 2 3
644 * 0 10 20 40 50
646 * 2 15 40 50
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;
674 dump_global_table();
676 stop_packet(q, r, STOP_REASON_USER_REASON);
679 /****************************************************************************
681 ****************************************************************************/
682 static void send_entry_reply(GENERIC_PACKET *q, GENERIC_PACKET *r)
684 int i,j,k;
685 struct in_addr partner, server;
686 pid_t pid;
687 int s_ctx=get_server_assoc(q->header.assoc_ctx);
688 WINS_RECORD record;
690 if (s_ctx==0) {
691 DEBUG(1, ("send_entry_reply: request for a partner not in our table\n"));
692 stop_packet(q, r, STOP_REASON_USER_REASON);
693 return;
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));
708 break;
712 pid = pidfile_pid("nmbd");
713 if (pid == 0) {
714 DEBUG(0,("send_entry_reply: Can't find pid for nmbd\n"));
715 return;
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;
732 else
733 for (i=0; i<record.num_ips; i++)
734 record.ip[i]=q->rep.se_rp.wins_name[k].others[i];
736 record.nb_flags=0;
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);
750 dump_global_table();
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) {
772 case 0:
773 /* add version number map table request */
774 send_version_number_map_table(q, r);
775 break;
776 case 1:
777 receive_version_number_map_table(q, r);
778 break;
779 case 2:
780 /* send entry request */
781 send_entry_request(q, r);
782 break;
783 case 3:
784 /* send entry reply */
785 send_entry_reply(q, r);
786 break;
787 case 4:
788 /* update notification request */
789 update_notify_request(q, r);
790 break;
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) {
800 case 0:
801 /* Start association type */
802 start_assoc_process(q, r);
803 return True;
804 break;
805 case 1:
806 /* start association reply */
807 start_assoc_reply(q, r);
808 return True;
809 break;
810 case 2:
811 /* stop association message */
812 return False;
813 break;
814 case 3:
815 /* replication message */
816 replicate(q, r);
817 return True;
818 break;
821 return False;
825 /****************************************************************************
826 construct a reply to the incoming packet
827 ****************************************************************************/
828 void construct_reply(struct wins_packet_struct *p)
830 GENERIC_PACKET r;
831 struct BUFFER buffer;
833 buffer.buffer=NULL;
834 buffer.offset=0;
835 buffer.length=0;
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)) {
842 fstring peer;
843 struct in_addr addr;
844 int i;
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))
850 break;
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);
855 p->stop_packet=True;
856 encode_generic_packet(&buffer, &r);
857 if (!send_smb(p->fd, buffer.buffer))
858 exit_server("process_smb: send_smb failed.");
859 return;
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);
878 p->stop_packet=True;
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*/
888 int i, s;
889 struct BUFFER buffer;
890 GENERIC_PACKET p;
892 buffer.buffer=NULL;
893 buffer.offset=0;
894 buffer.length=0;
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;
905 p.sa_rq.min_ver=1;
906 p.sa_rq.maj_ver=1;
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);
914 if (s==-1) {
915 DEBUG(0,("run_pull_replication: can't contact wins server %s.\n", inet_ntoa(global_wins_table[0][i].address)));
916 return;
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 */
939 int i, s;
940 struct BUFFER buffer;
941 GENERIC_PACKET p;
943 buffer.buffer=NULL;
944 buffer.offset=0;
945 buffer.length=0;
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;
956 p.sa_rq.min_ver=1;
957 p.sa_rq.maj_ver=1;
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);
965 if (s==-1) {
966 DEBUG(0,("run_push_replication: can't contact wins server %s.\n", inet_ntoa(global_wins_table[0][i].address)));
967 return;
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);