]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - zephyr/zhm/zhm_server.c
47b2d5933968c3f1c8a629e5e7606ddbe8775efe
[1ts-debian.git] / zephyr / zhm / zhm_server.c
1 /* This file is part of the Project Athena Zephyr Notification System.
2  * It contains the hostmanager <--> server interaction routines.
3  *
4  *      Created by:     David C. Jedlinsky
5  *
6  *      $Id$
7  *
8  *      Copyright (c) 1987 by the Massachusetts Institute of Technology.
9  *      For copying and distribution information, see the file
10  *      "mit-copyright.h". 
11  */
12
13 #include "zhm.h"
14
15 #ifndef lint
16 #ifndef SABER
17 static char rcsid_hm_server_c[] = "$Id$";
18 #endif /* SABER */
19 #endif /* lint */
20
21 static void boot_timeout __P((void *));
22 static int get_serv_timeout __P((void));
23
24 static Timer *boot_timer = NULL;
25 static int serv_rexmit_times[] = { 5, 10, 20, 40 };
26 static int serv_timeouts = 0;
27
28 int serv_loop = 0;
29 extern u_short cli_port;
30 extern struct sockaddr_in serv_sin, from;
31 extern int timeout_type, hmdebug, nservchang, booting, nserv, no_server;
32 extern int deactivated, rebootflag;
33 extern int numserv;
34 extern char **serv_list;
35 extern char cur_serv[], prim_serv[];
36 extern void die_gracefully(void);
37
38 void hm_control(ZNotice_t *);
39 void send_back(ZNotice_t *);
40 void new_server(char *);
41
42 /* Argument is whether we are actually booting, or just attaching
43  * after a server switch */
44 void
45 send_boot_notice(char *op)
46 {
47      ZNotice_t notice;
48      Code_t ret;
49   
50      /* Set up server notice */
51      notice.z_kind = HMCTL;
52      notice.z_port = cli_port;
53      notice.z_class = ZEPHYR_CTL_CLASS;
54      notice.z_class_inst = ZEPHYR_CTL_HM;
55      notice.z_opcode = op;
56      notice.z_sender = "HM";
57      notice.z_recipient = "";
58      notice.z_default_format = "";
59      notice.z_num_other_fields = 0;
60      notice.z_message_len = 0;
61   
62      /* Notify server that this host is here */
63      if ((ret = ZSetDestAddr(&serv_sin)) != ZERR_NONE) {
64           Zperr(ret);
65           com_err("hm", ret, "setting destination");
66      }
67      if ((ret = ZSendNotice(&notice, ZNOAUTH)) != ZERR_NONE) {
68           Zperr(ret);
69           com_err("hm", ret, "sending startup notice");
70      }
71      boot_timer = timer_set_rel(get_serv_timeout(), boot_timeout, NULL);
72 }
73
74 /* Argument is whether we are detaching or really going down */
75 void
76 send_flush_notice(char *op)
77 {
78      ZNotice_t notice;
79      Code_t ret;
80      
81      /* Set up server notice */
82      notice.z_kind = HMCTL;
83      notice.z_port = cli_port;
84      notice.z_class = ZEPHYR_CTL_CLASS;
85      notice.z_class_inst = ZEPHYR_CTL_HM;
86      notice.z_opcode = op;
87      notice.z_sender = "HM";
88      notice.z_recipient = "";
89      notice.z_default_format = "";
90      notice.z_num_other_fields = 0;
91      notice.z_message_len = 0;
92
93      /* Tell server to lose us */
94      if ((ret = ZSetDestAddr(&serv_sin)) != ZERR_NONE) {
95           Zperr(ret);
96           com_err("hm", ret, "setting destination");
97      }
98      if ((ret = ZSendNotice(&notice, ZNOAUTH)) != ZERR_NONE) {
99           Zperr(ret);
100           com_err("hm", ret, "sending flush notice");
101      }
102 }
103
104 void
105 find_next_server(char *sugg_serv)
106 {
107      struct hostent *hp;
108      int done = 0;
109      char **parse = serv_list;
110      char *new_serv;
111   
112      if (sugg_serv) {
113           do {
114                if (!strcmp(*parse, sugg_serv))
115                     done = 1;
116           } while ((done == 0) && (*++parse != NULL));
117      }
118      if (done) {
119           if ((hp = gethostbyname(sugg_serv)) != NULL) {
120                DPR2 ("Server = %s\n", sugg_serv);       
121                (void)strncpy(cur_serv, sugg_serv, MAXHOSTNAMELEN);
122                cur_serv[MAXHOSTNAMELEN - 1] = '\0';
123                if (hmdebug)
124                     syslog(LOG_DEBUG, "Suggested server: %s\n", sugg_serv);
125           } else {
126                done = 0; 
127           }
128      }
129      while (!done) {
130          if ((++serv_loop > 3) && (strcmp(cur_serv, prim_serv))) {
131              serv_loop = 0;
132              if ((hp = gethostbyname(prim_serv)) != NULL) {
133                  DPR2 ("Server = %s\n", prim_serv);
134                  (void)strncpy(cur_serv, prim_serv, MAXHOSTNAMELEN);
135                  cur_serv[MAXHOSTNAMELEN - 1] = '\0';
136                  done = 1;
137                  break;
138              }
139          }
140
141          switch (numserv) {
142          case 1:
143              if ((hp = gethostbyname(*serv_list)) != NULL) {
144                  DPR2 ("Server = %s\n", *serv_list);
145                  (void)strncpy(cur_serv, *serv_list, MAXHOSTNAMELEN);
146                  cur_serv[MAXHOSTNAMELEN - 1] = '\0';
147                  done = 1;
148                  break;
149              }
150              /* fall through */
151          case 0:
152              if (rebootflag)
153                  die_gracefully();
154              else
155                  sleep(1);
156              break;
157          default:
158              do {
159                  new_serv = serv_list[random() % numserv];
160              } while (!strcmp(new_serv, cur_serv));
161
162              if ((hp = gethostbyname(new_serv)) != NULL) {
163                  DPR2 ("Server = %s\n", new_serv);
164                  (void)strncpy(cur_serv, new_serv, MAXHOSTNAMELEN);
165                  cur_serv[MAXHOSTNAMELEN - 1] = '\0';
166                  done = 1;
167              } else
168                  sleep(1);
169
170              break;
171          }
172      }
173      (void) memcpy((char *)&serv_sin.sin_addr, hp->h_addr, 4);
174      nservchang++;
175 }
176
177 void
178 server_manager(ZNotice_t *notice)
179 {
180     if (memcmp((char *)&serv_sin.sin_addr, (char *)&from.sin_addr, 4) ||
181         (serv_sin.sin_port != from.sin_port)) {
182         syslog (LOG_INFO, "Bad notice from port %u.", notice->z_port);
183     } else {
184         /* This is our server, handle the notice */
185         booting = 0;
186         serv_timeouts = 0;
187         if (boot_timer) {
188             timer_reset(boot_timer);
189             boot_timer = NULL;
190         }
191         DPR ("A notice came in from the server.\n");
192         nserv++;
193         switch(notice->z_kind) {
194         case HMCTL:
195             hm_control(notice);
196             break;
197         case SERVNAK:
198         case SERVACK:
199             send_back(notice);
200             break;
201         default:
202             syslog (LOG_INFO, "Bad notice kind!?");
203             break;
204         }
205     }
206 }
207
208 void
209 hm_control(ZNotice_t *notice)
210 {
211     Code_t ret;
212     struct hostent *hp;
213     char suggested_server[MAXHOSTNAMELEN];
214     unsigned long addr;
215      
216     DPR("Control message!\n");
217     if (!strcmp(notice->z_opcode, SERVER_SHUTDOWN)) {
218         if (notice->z_message_len) {
219             addr = inet_addr(notice->z_message);
220             hp = gethostbyaddr((char *) &addr, sizeof(addr), AF_INET);
221             if (hp != NULL) {
222                 strncpy(suggested_server, hp->h_name, sizeof(suggested_server));
223                 suggested_server[sizeof(suggested_server) - 1] = '\0';
224                 new_server(suggested_server);
225             } else {
226                 new_server(NULL);
227             }
228         } else {
229             new_server((char *)NULL);
230         }
231     } else if (!strcmp(notice->z_opcode, SERVER_PING)) {
232         notice->z_kind = HMACK;
233         if ((ret = ZSetDestAddr(&serv_sin)) != ZERR_NONE) {
234             Zperr(ret);
235             com_err("hm", ret, "setting destination");
236         }
237         if ((ret = send_outgoing(notice)) != ZERR_NONE) {
238             Zperr(ret);
239             com_err("hm", ret, "sending ACK");
240         }
241         if (no_server) {
242             no_server = 0;
243             retransmit_queue(&serv_sin);
244         }
245     } else {
246         syslog (LOG_INFO, "Bad control message.");
247     }
248 }
249
250 void
251 send_back(ZNotice_t *notice)
252 {
253     ZNotice_Kind_t kind;
254     struct sockaddr_in repl;
255     Code_t ret;
256   
257     if (!strcmp(notice->z_opcode, HM_BOOT) ||
258         !strcmp(notice->z_opcode, HM_ATTACH)) {
259         /* ignore message, just an ack from boot, but exit if we
260          * are rebooting.
261          */
262         if (rebootflag)
263             die_gracefully();
264     } else {
265         if (remove_notice_from_queue(notice, &kind, &repl) != ZERR_NONE) {
266             syslog (LOG_INFO, "Hey! This packet isn't in my queue!");
267         } else {
268             /* check if client wants an ACK, and send it */
269             if (kind == ACKED) {
270                 DPR2 ("Client ACK port: %u\n", ntohs(repl.sin_port));
271                 if ((ret = ZSetDestAddr(&repl)) != ZERR_NONE) {
272                     Zperr(ret);
273                     com_err("hm", ret, "setting destination");
274                 }
275                 if ((ret = send_outgoing(notice)) != ZERR_NONE) {
276                     Zperr(ret);
277                     com_err("hm", ret, "sending ACK");
278                 }
279             }
280         }
281     }
282     if (no_server) {
283         no_server = 0;
284         retransmit_queue(&serv_sin);
285     }
286 }
287
288 void
289 new_server(char *sugg_serv)
290 {
291     no_server = 1;
292     syslog (LOG_INFO, "Server went down, finding new server.");
293     send_flush_notice(HM_DETACH);
294     find_next_server(sugg_serv);
295     if (booting) {
296         send_boot_notice(HM_BOOT);
297         deactivated = 0;
298     } else {
299         send_boot_notice(HM_ATTACH);
300     }
301     disable_queue_retransmits();
302 }
303
304 static void
305 boot_timeout(void *arg)
306 {
307     serv_timeouts++;
308     new_server(NULL);
309 }
310
311 static int get_serv_timeout(void)
312 {
313     int ind, ntimeouts;
314
315     ind = (numserv == 0) ? serv_timeouts : serv_timeouts / numserv;
316     ntimeouts = sizeof(serv_rexmit_times) / sizeof(*serv_rexmit_times);
317     if (ind >= ntimeouts)
318         ind = ntimeouts - 1;
319     return serv_rexmit_times[ind];
320 }