1 /* This file is part of the Project Athena Zephyr Notification System.
2 * It contains the hostmanager <--> server interaction routines.
4 * Created by: David C. Jedlinsky
8 * Copyright (c) 1987 by the Massachusetts Institute of Technology.
9 * For copying and distribution information, see the file
17 static char rcsid_hm_server_c[] = "$Id$";
21 static void boot_timeout __P((void *));
22 static int get_serv_timeout __P((void));
24 static Timer *boot_timer = NULL;
25 static int serv_rexmit_times[] = { 5, 10, 20, 40 };
26 static int serv_timeouts = 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;
34 extern char **serv_list;
35 extern char cur_serv[], prim_serv[];
36 extern void die_gracefully(void);
38 void hm_control(ZNotice_t *);
39 void send_back(ZNotice_t *);
40 void new_server(char *);
42 /* Argument is whether we are actually booting, or just attaching
43 * after a server switch */
45 send_boot_notice(char *op)
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;
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;
62 /* Notify server that this host is here */
63 if ((ret = ZSetDestAddr(&serv_sin)) != ZERR_NONE) {
65 com_err("hm", ret, "setting destination");
67 if ((ret = ZSendNotice(¬ice, ZNOAUTH)) != ZERR_NONE) {
69 com_err("hm", ret, "sending startup notice");
71 boot_timer = timer_set_rel(get_serv_timeout(), boot_timeout, NULL);
74 /* Argument is whether we are detaching or really going down */
76 send_flush_notice(char *op)
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;
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;
93 /* Tell server to lose us */
94 if ((ret = ZSetDestAddr(&serv_sin)) != ZERR_NONE) {
96 com_err("hm", ret, "setting destination");
98 if ((ret = ZSendNotice(¬ice, ZNOAUTH)) != ZERR_NONE) {
100 com_err("hm", ret, "sending flush notice");
105 find_next_server(char *sugg_serv)
109 char **parse = serv_list;
114 if (!strcmp(*parse, sugg_serv))
116 } while ((done == 0) && (*++parse != NULL));
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';
124 syslog(LOG_DEBUG, "Suggested server: %s\n", sugg_serv);
130 if ((++serv_loop > 3) && (strcmp(cur_serv, prim_serv))) {
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';
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';
159 new_serv = serv_list[random() % numserv];
160 } while (!strcmp(new_serv, cur_serv));
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';
173 (void) memcpy((char *)&serv_sin.sin_addr, hp->h_addr, 4);
178 server_manager(ZNotice_t *notice)
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);
184 /* This is our server, handle the notice */
188 timer_reset(boot_timer);
191 DPR ("A notice came in from the server.\n");
193 switch(notice->z_kind) {
202 syslog (LOG_INFO, "Bad notice kind!?");
209 hm_control(ZNotice_t *notice)
213 char suggested_server[MAXHOSTNAMELEN];
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);
222 strncpy(suggested_server, hp->h_name, sizeof(suggested_server));
223 suggested_server[sizeof(suggested_server) - 1] = '\0';
224 new_server(suggested_server);
229 new_server((char *)NULL);
231 } else if (!strcmp(notice->z_opcode, SERVER_PING)) {
232 notice->z_kind = HMACK;
233 if ((ret = ZSetDestAddr(&serv_sin)) != ZERR_NONE) {
235 com_err("hm", ret, "setting destination");
237 if ((ret = send_outgoing(notice)) != ZERR_NONE) {
239 com_err("hm", ret, "sending ACK");
243 retransmit_queue(&serv_sin);
246 syslog (LOG_INFO, "Bad control message.");
251 send_back(ZNotice_t *notice)
254 struct sockaddr_in repl;
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
265 if (remove_notice_from_queue(notice, &kind, &repl) != ZERR_NONE) {
266 syslog (LOG_INFO, "Hey! This packet isn't in my queue!");
268 /* check if client wants an ACK, and send it */
270 DPR2 ("Client ACK port: %u\n", ntohs(repl.sin_port));
271 if ((ret = ZSetDestAddr(&repl)) != ZERR_NONE) {
273 com_err("hm", ret, "setting destination");
275 if ((ret = send_outgoing(notice)) != ZERR_NONE) {
277 com_err("hm", ret, "sending ACK");
284 retransmit_queue(&serv_sin);
289 new_server(char *sugg_serv)
292 syslog (LOG_INFO, "Server went down, finding new server.");
293 send_flush_notice(HM_DETACH);
294 find_next_server(sugg_serv);
296 send_boot_notice(HM_BOOT);
299 send_boot_notice(HM_ATTACH);
301 disable_queue_retransmits();
305 boot_timeout(void *arg)
311 static int get_serv_timeout(void)
315 ind = (numserv == 0) ? serv_timeouts : serv_timeouts / numserv;
316 ntimeouts = sizeof(serv_rexmit_times) / sizeof(*serv_rexmit_times);
317 if (ind >= ntimeouts)
319 return serv_rexmit_times[ind];