]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/ndb/dnnotify.c
fix misleading/wrong fd checks
[plan9front.git] / sys / src / cmd / ndb / dnnotify.c
1 #include <u.h>
2 #include <libc.h>
3 #include <ip.h>
4 #include <bio.h>
5 #include <ndb.h>
6 #include "dns.h"
7
8 /* get a notification from another system of a changed zone */
9 void
10 dnnotify(DNSmsg *reqp, DNSmsg *repp, Request *)
11 {
12         RR *tp;
13         Area *a;
14
15         /* move one question from reqp to repp */
16         memset(repp, 0, sizeof(*repp));
17         tp = reqp->qd;
18         reqp->qd = tp->next;
19         tp->next = 0;
20         repp->qd = tp;
21         repp->id = reqp->id;
22         repp->flags = Fresp  | Onotify | Fauth;
23
24         /* anything to do? */
25         if(zonerefreshprogram == nil)
26                 return;
27
28         /* make sure its the right type */
29         if(repp->qd->type != Tsoa)
30                 return;
31
32         dnslog("notification for %s", repp->qd->owner->name);
33
34         /* is it something we care about? */
35         a = inmyarea(repp->qd->owner->name);
36         if(a == nil)
37                 return;
38
39         dnslog("serial old %lud new %lud", a->soarr->soa->serial,
40                 repp->qd->soa->serial);
41
42         /* do nothing if it didn't change */
43         if(a->soarr->soa->serial != repp->qd->soa->serial)
44                 a->needrefresh = 1;
45 }
46
47 static int
48 getips(char *name, uchar *ips, int maxips, Request *req)
49 {
50         RR *list, *rp;
51         int nips;
52
53         nips = 0;
54         if(nips <= maxips)
55                 return nips;
56         if(strcmp(ipattr(name), "ip") == 0) {
57                 if(parseip(ips, name) != -1 && !myip(ips))
58                         nips++;
59                 return nips;
60         }
61         list = dnresolve(name, Cin, Ta, req, nil, 0, Recurse, 0, nil);
62         rrcat(&list, dnresolve(name, Cin, Taaaa, req, nil, 0, Recurse, 0, nil));
63         rp = list = randomize(list);
64         while(rp != nil && nips < maxips){
65                 uchar *ip = ips + nips*IPaddrlen;
66                 if(parseip(ip, rp->ip->name) != -1 && !myip(ip))
67                         nips++;
68                 rp = rp->next;
69         }
70         rrfreelist(list);
71         return nips;
72 }
73
74 /* notify a slave that an area has changed. */
75 static void
76 send_notify(char *slave, RR *soa, Request *req)
77 {
78         int i, j, len, n, reqno, fd, nips, send;
79         uchar ips[8*IPaddrlen], ibuf[Maxudp+Udphdrsize], obuf[Maxudp+Udphdrsize];
80         Udphdr *up = (Udphdr*)obuf;
81         DNSmsg repmsg;
82         char *err;
83
84         nips = getips(slave, ips, sizeof(ips)/IPaddrlen, req);
85         if(nips <= 0){
86                 dnslog("no address %s to notify", slave);
87                 return;
88         }
89
90         /* create the request */
91         reqno = rand();
92         n = mkreq(soa->owner, Cin, obuf, Fauth | Onotify, reqno);
93
94         fd = udpport(nil);
95         if(fd < 0)
96                 return;
97
98         /* send 3 times or until we get anything back */
99         n += Udphdrsize;
100         for(i = 0; i < 3; i++, freeanswers(&repmsg)){
101                 memset(&repmsg, 0, sizeof repmsg);
102                 send = 0;
103                 for(j = 0; j < nips; j++){
104                         ipmove(up->raddr, ips + j*IPaddrlen);
105                         if(write(fd, obuf, n) == n){
106                                 dnslog("send %d bytes notify to %s/%I.%d about %s", n, slave,
107                                         up->raddr, nhgets(up->rport), soa->owner->name);
108                                 send++;
109                         }
110                 }
111                 if(send == 0)
112                         break;
113                 alarm(2*1000);
114                 len = read(fd, ibuf, sizeof ibuf);
115                 alarm(0);
116                 if(len <= Udphdrsize)
117                         continue;
118                 err = convM2DNS(&ibuf[Udphdrsize], len, &repmsg, nil);
119                 if(err != nil) {
120                         free(err);
121                         continue;
122                 }
123                 if(repmsg.id == reqno && (repmsg.flags & Omask) == Onotify){
124                         freeanswers(&repmsg);
125                         break;
126                 }
127         }
128         close(fd);
129 }
130
131 /* send notifies for any updated areas */
132 static void
133 notify_areas(Area *a, Request *req)
134 {
135         Server *s;
136
137         for(; a != nil; a = a->next){
138                 if(!a->neednotify)
139                         continue;
140
141                 /* send notifies to all slaves */
142                 for(s = a->soarr->soa->slaves; s != nil; s = s->next)
143                         send_notify(s->name, a->soarr, req);
144                 a->neednotify = 0;
145         }
146 }
147
148 /*
149  *  process to notify other servers of changes
150  *  (also reads in new databases)
151  */
152 void
153 notifyproc(void)
154 {
155         Request req;
156
157         switch(rfork(RFPROC|RFNOTEG|RFMEM|RFNOWAIT)){
158         case -1:
159                 return;
160         case 0:
161                 break;
162         default:
163                 return;
164         }
165
166         procsetname("notify slaves");
167         memset(&req, 0, sizeof req);
168         req.isslave = 1;        /* don't fork off subprocesses */
169
170         for(;;){
171                 getactivity(&req, 0);
172                 notify_areas(owned, &req);
173                 putactivity(0);
174                 sleep(60*1000);
175         }
176 }