]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - zhm/zhm_server.c
81dea0ef2b31204526a58b13619737b49885fc42
[1ts-debian.git] / 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: zhm_server.c,v 1.17 1999/10/14 18:37:35 ghudson Exp $
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: zhm_server.c,v 1.17 1999/10/14 18:37:35 ghudson Exp $";
18 #endif /* SABER */
19 #endif /* lint */
20
21 static void boot_timeout __P((void *));
22
23 static Timer *boot_timer = NULL;
24
25 int serv_loop = 0;
26 extern u_short cli_port;
27 extern struct sockaddr_in serv_sin, from;
28 extern int timeout_type, hmdebug, nservchang, booting, nserv, no_server;
29 extern int deactivated, rebootflag;
30 extern int numserv;
31 extern char **serv_list;
32 extern char cur_serv[], prim_serv[];
33 extern void die_gracefully();
34
35 void hm_control(), send_back(), new_server();
36
37 /* Argument is whether we are actually booting, or just attaching
38  * after a server switch */
39 void
40 send_boot_notice(op)
41 char *op;
42 {
43      ZNotice_t notice;
44      Code_t ret;
45   
46      /* Set up server notice */
47      notice.z_kind = HMCTL;
48      notice.z_port = cli_port;
49      notice.z_class = ZEPHYR_CTL_CLASS;
50      notice.z_class_inst = ZEPHYR_CTL_HM;
51      notice.z_opcode = op;
52      notice.z_sender = "HM";
53      notice.z_recipient = "";
54      notice.z_default_format = "";
55      notice.z_num_other_fields = 0;
56      notice.z_message_len = 0;
57   
58      /* Notify server that this host is here */
59      if ((ret = ZSetDestAddr(&serv_sin)) != ZERR_NONE) {
60           Zperr(ret);
61           com_err("hm", ret, "setting destination");
62      }
63      if ((ret = ZSendNotice(&notice, ZNOAUTH)) != ZERR_NONE) {
64           Zperr(ret);
65           com_err("hm", ret, "sending startup notice");
66      }
67      boot_timer = timer_set_rel(SERV_TIMEOUT, boot_timeout, NULL);
68 }
69
70 /* Argument is whether we are detaching or really going down */
71 void
72 send_flush_notice(op)
73 char *op;
74 {
75      ZNotice_t notice;
76      Code_t ret;
77      
78      /* Set up server notice */
79      notice.z_kind = HMCTL;
80      notice.z_port = cli_port;
81      notice.z_class = ZEPHYR_CTL_CLASS;
82      notice.z_class_inst = ZEPHYR_CTL_HM;
83      notice.z_opcode = op;
84      notice.z_sender = "HM";
85      notice.z_recipient = "";
86      notice.z_default_format = "";
87      notice.z_num_other_fields = 0;
88      notice.z_message_len = 0;
89
90      /* Tell server to lose us */
91      if ((ret = ZSetDestAddr(&serv_sin)) != ZERR_NONE) {
92           Zperr(ret);
93           com_err("hm", ret, "setting destination");
94      }
95      if ((ret = ZSendNotice(&notice, ZNOAUTH)) != ZERR_NONE) {
96           Zperr(ret);
97           com_err("hm", ret, "sending flush notice");
98      }
99 }
100
101 void
102 find_next_server(sugg_serv)
103 char *sugg_serv;
104 {
105      struct hostent *hp;
106      int done = 0;
107      char **parse = serv_list;
108      char *new_serv;
109   
110      if (sugg_serv) {
111           do {
112                if (!strcmp(*parse, sugg_serv))
113                     done = 1;
114           } while ((done == 0) && (*++parse != NULL));
115      }
116      if (done) {
117           if ((hp = gethostbyname(sugg_serv)) != NULL) {
118                DPR2 ("Server = %s\n", sugg_serv);       
119                (void)strncpy(cur_serv, sugg_serv, MAXHOSTNAMELEN);
120                cur_serv[MAXHOSTNAMELEN - 1] = '\0';
121                if (hmdebug)
122                     syslog(LOG_DEBUG, "Suggested server: %s\n", sugg_serv);
123           } else {
124                done = 0; 
125           }
126      }
127      while (!done) {
128          if ((++serv_loop > 3) && (strcmp(cur_serv, prim_serv))) {
129              serv_loop = 0;
130              if ((hp = gethostbyname(prim_serv)) != NULL) {
131                  DPR2 ("Server = %s\n", prim_serv);
132                  (void)strncpy(cur_serv, prim_serv, MAXHOSTNAMELEN);
133                  cur_serv[MAXHOSTNAMELEN - 1] = '\0';
134                  done = 1;
135                  break;
136              }
137          }
138
139          switch (numserv) {
140          case 1:
141              if ((hp = gethostbyname(*serv_list)) != NULL) {
142                  DPR2 ("Server = %s\n", *serv_list);
143                  (void)strncpy(cur_serv, *serv_list, MAXHOSTNAMELEN);
144                  cur_serv[MAXHOSTNAMELEN - 1] = '\0';
145                  done = 1;
146                  break;
147              }
148              /* fall through */
149          case 0:
150              if (rebootflag)
151                  die_gracefully();
152              else
153                  sleep(1);
154              break;
155          default:
156              do {
157                  new_serv = serv_list[random() % numserv];
158              } while (!strcmp(new_serv, cur_serv));
159
160              if ((hp = gethostbyname(new_serv)) != NULL) {
161                  DPR2 ("Server = %s\n", new_serv);
162                  (void)strncpy(cur_serv, new_serv, MAXHOSTNAMELEN);
163                  cur_serv[MAXHOSTNAMELEN - 1] = '\0';
164                  done = 1;
165              } else
166                  sleep(1);
167
168              break;
169          }
170      }
171      (void) memcpy((char *)&serv_sin.sin_addr, hp->h_addr, 4);
172      nservchang++;
173 }
174
175 void
176 server_manager(notice)
177 ZNotice_t *notice;
178 {
179     if (memcmp((char *)&serv_sin.sin_addr, (char *)&from.sin_addr, 4) ||
180         (serv_sin.sin_port != from.sin_port)) {
181         syslog (LOG_INFO, "Bad notice from port %u.", notice->z_port);
182     } else {
183         /* This is our server, handle the notice */
184         booting = 0;
185         if (boot_timer) {
186             timer_reset(boot_timer);
187             boot_timer = NULL;
188         }
189         DPR ("A notice came in from the server.\n");
190         nserv++;
191         switch(notice->z_kind) {
192         case HMCTL:
193             hm_control(notice);
194             break;
195         case SERVNAK:
196         case SERVACK:
197             send_back(notice);
198             break;
199         default:
200             syslog (LOG_INFO, "Bad notice kind!?");
201             break;
202         }
203     }
204 }
205
206 void
207 hm_control(notice)
208 ZNotice_t *notice;
209 {
210     Code_t ret;
211     struct hostent *hp;
212     char suggested_server[MAXHOSTNAMELEN];
213     unsigned long addr;
214      
215     DPR("Control message!\n");
216     if (!strcmp(notice->z_opcode, SERVER_SHUTDOWN)) {
217         if (notice->z_message_len) {
218             addr = inet_addr(notice->z_message);
219             hp = gethostbyaddr((char *) &addr, sizeof(addr), AF_INET);
220             if (hp != NULL) {
221                 strncpy(suggested_server, hp->h_name, sizeof(suggested_server));
222                 suggested_server[sizeof(suggested_server) - 1] = '\0';
223                 new_server(suggested_server);
224             } else {
225                 new_server(NULL);
226             }
227         } else {
228             new_server((char *)NULL);
229         }
230     } else if (!strcmp(notice->z_opcode, SERVER_PING)) {
231         notice->z_kind = HMACK;
232         if ((ret = ZSetDestAddr(&serv_sin)) != ZERR_NONE) {
233             Zperr(ret);
234             com_err("hm", ret, "setting destination");
235         }
236         if ((ret = send_outgoing(notice)) != ZERR_NONE) {
237             Zperr(ret);
238             com_err("hm", ret, "sending ACK");
239         }
240         if (no_server) {
241             no_server = 0;
242             retransmit_queue(&serv_sin);
243         }
244     } else {
245         syslog (LOG_INFO, "Bad control message.");
246     }
247 }
248
249 void
250 send_back(notice)
251 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(sugg_serv)
290 char *sugg_serv;
291 {
292     no_server = 1;
293     syslog (LOG_INFO, "Server went down, finding new server.");
294     send_flush_notice(HM_DETACH);
295     find_next_server(sugg_serv);
296     if (booting) {
297         send_boot_notice(HM_BOOT);
298         deactivated = 0;
299     } else {
300         send_boot_notice(HM_ATTACH);
301     }
302     disable_queue_retransmits();
303 }
304
305 static void boot_timeout(arg)
306 void *arg;
307 {
308     new_server(NULL);
309 }
310