+ // Send hello
+ if (tunnel[t].state == TUNNELOPEN && tunnel[t].lastrec < config->current_time + 600)
+ {
+ controlt *c = controlnew(6); // sending HELLO
+ controladd(c, t, 0); // send the message
+ log(3, tunnel[t].ip, 0, t, "Sending HELLO message\n");
+ }
+ }
+
+ // Check for sessions that have been killed from the CLI
+ if (cli_session_kill[0])
+ {
+ int i;
+ for (i = 0; i < MAXSESSION && cli_session_kill[i]; i++)
+ {
+ log(2, 0, cli_session_kill[i], 0, "Dropping session by CLI\n");
+ sessionshutdown(cli_session_kill[i], "Requested by administrator");
+ cli_session_kill[i] = 0;
+ }
+ }
+ // Check for tunnels that have been killed from the CLI
+ if (cli_tunnel_kill[0])
+ {
+ int i;
+ for (i = 1; i < MAXTUNNEL && cli_tunnel_kill[i]; i++)
+ {
+ log(2, 0, cli_tunnel_kill[i], 0, "Dropping tunnel by CLI\n");
+ tunnelshutdown(cli_tunnel_kill[i], "Requested by administrator");
+ cli_tunnel_kill[i] = 0;
+ }
+ }
+
+ count = 0;
+ for (i = 1; i < config->cluster_highest_sessionid; i++)
+ {
+
+ s++;
+ if (s >= config->cluster_highest_sessionid)
+ s = 1;
+
+ if (!session[s].tunnel) // Session isn't in use
+ continue;
+
+ if (!session[s].die && session[s].ip && !(session[s].flags & SF_IPCP_ACKED) )
+ {
+ // IPCP has not completed yet. Resend
+ log(3, session[s].ip, s, session[s].tunnel, "No ACK for initial IPCP ConfigReq... resending\n");
+ sendipcp(session[s].tunnel, s);
+ }
+
+ // check for expired sessions
+ if (session[s].die && session[s].die <= config->current_time)
+ {
+ sessionkill(s, "Expired");
+ if (++count >= MAX_ACTIONS) break;
+ continue;
+ }
+
+ // Drop sessions who have not responded within IDLE_TIMEOUT seconds
+ if (session[s].last_packet && (time_now - session[s].last_packet >= IDLE_TIMEOUT))
+ {
+ sessionkill(s, "No response to LCP ECHO requests");
+ STAT(session_timeout);
+ if (++count >= MAX_ACTIONS) break;
+ continue;
+ }
+
+ // No data in IDLE_TIMEOUT seconds, send LCP ECHO
+ if (session[s].user[0] && (time_now - session[s].last_packet >= ECHO_TIMEOUT))
+ {
+ u8 b[MAXCONTROL] = {0};
+
+ u8 *q = makeppp(b, sizeof(b), 0, 0, session[s].tunnel, s, PPPLCP);
+ if (!q) {
+ log(3, session[s].ip, s, t, "failed to send ECHO packet.\n");
+ continue;
+ }
+
+ *q = EchoReq;
+ *(u8 *)(q + 1) = (time_now % 255); // ID
+ *(u16 *)(q + 2) = htons(8); // Length
+ *(u32 *)(q + 4) = 0; // Magic Number (not supported)
+
+ log(4, session[s].ip, s, session[s].tunnel, "No data in %d seconds, sending LCP ECHO\n",
+ (int)(time_now - session[s].last_packet));
+ tunnelsend(b, 24, session[s].tunnel); // send it
+ if (++count >= MAX_ACTIONS) break;
+ continue;
+ }
+ }
+ if (config->accounting_dir && next_acct <= config->current_time)
+ {
+ // Dump accounting data
+ next_acct = config->current_time + ACCT_TIME;
+ dump_acct_info();
+ }
+
+ if (count >= MAX_ACTIONS)
+ return 1; // Didn't finish!
+
+ log(3, 0, 0, 0, "End regular cleanup (%d actions), next in %d seconds\n", count, config->cleanup_interval);
+ return 0;
+}
+
+
+//
+// Are we in the middle of a tunnel update, or radius
+// requests??
+//
+int still_busy(void)
+{
+ int i;
+ static int last_talked = 0;
+ for (i = config->cluster_highest_tunnelid ; i > 0 ; --i) {
+ if (!tunnel[i].controlc)
+ continue;
+
+ if (last_talked != config->current_time) {
+ log(2,0,0,0, "Tunnel %d still has an-acked control messages.\n", i);
+ last_talked = config->current_time;
+ }
+ return 1;
+ }
+
+ for (i = 1; i < MAXRADIUS; i++)
+ {
+ if (radius[i].state == RADIUSNULL)
+ continue;
+ if (radius[i].state == RADIUSWAIT)
+ continue;
+
+ if (last_talked != config->current_time) {
+ log(2,0,0,0, "Radius session %d is still busy (sid %d)\n", i, radius[i].session);
+ last_talked = config->current_time;
+ }
+ return 1;
+ }
+
+ return 0;
+}
+
+// main loop - gets packets on tap or udp and processes them
+void mainloop(void)
+{
+ fd_set cr;
+ int cn, i;
+ u8 buf[65536];
+ struct timeval to;
+ time_t next_cluster_ping = 0; // default 1 second pings.
+ clockt next_clean = time_now + config->cleanup_interval;
+
+ log(4, 0, 0, 0, "Beginning of main loop. udpfd=%d, tapfd=%d, cluster_sockfd=%d, controlfd=%d\n",
+ udpfd, tapfd, cluster_sockfd, controlfd);
+
+ FD_ZERO(&cr);
+ FD_SET(udpfd, &cr);
+ FD_SET(tapfd, &cr);
+ FD_SET(controlfd, &cr);
+ FD_SET(clifd, &cr);
+ if (cluster_sockfd) FD_SET(cluster_sockfd, &cr);
+ cn = udpfd;
+ if (cn < tapfd) cn = tapfd;
+ if (cn < controlfd) cn = controlfd;
+ if (cn < clifd) cn = clifd;
+ if (cn < cluster_sockfd) cn = cluster_sockfd;
+ for (i = 0; i < config->num_radfds; i++)
+ {
+ if (!radfds[i]) continue;
+ FD_SET(radfds[i], &cr);
+ if (radfds[i] > cn)
+ cn = radfds[i];
+ }
+
+ while (!main_quit || still_busy())
+ {
+ fd_set r;
+ int n = cn;
+#ifdef BGP
+ fd_set w;
+ int bgp_set[BGP_NUM_PEERS];
+#endif /* BGP */
+
+ if (config->reload_config)
+ {
+ // Update the config state based on config settings
+ update_config();
+ }
+
+ memcpy(&r, &cr, sizeof(fd_set));
+ to.tv_sec = 0;
+ to.tv_usec = 100000; // 1/10th of a second.
+
+#ifdef BGP
+ FD_ZERO(&w);
+ for (i = 0; i < BGP_NUM_PEERS; i++)
+ {
+ bgp_set[i] = bgp_select_state(&bgp_peers[i]);
+ if (bgp_set[i] & 1)
+ {
+ FD_SET(bgp_peers[i].sock, &r);
+ if (bgp_peers[i].sock > n)
+ n = bgp_peers[i].sock;
+ }
+
+ if (bgp_set[i] & 2)
+ {
+ FD_SET(bgp_peers[i].sock, &w);
+ if (bgp_peers[i].sock > n)
+ n = bgp_peers[i].sock;
+ }
+ }
+
+ n = select(n + 1, &r, &w, 0, &to);
+#else /* BGP */
+ n = select(n + 1, &r, 0, 0, &to);
+#endif /* BGP */
+
+ config->current_time = now();
+ if (n < 0)
+ {
+ if (errno == EINTR)
+ continue;
+
+ log(0, 0, 0, 0, "Error returned from select(): %s\n", strerror(errno));
+ main_quit++;
+ break;
+ }