+ for (r = 1; r < MAXRADIUS; r++)
+ {
+ if (!radius[r].state)
+ continue;
+ if (radius[r].retry)
+ {
+ if (radius[r].retry <= TIME)
+ radiusretry(r);
+ } else
+ radius[r].retry = backoff(radius[r].try+1); // Is this really needed? --mo
+ }
+ for (t = 1; t < config->cluster_highest_tunnelid; t++)
+ {
+ // check for expired tunnels
+ if (tunnel[t].die && tunnel[t].die <= TIME)
+ {
+ STAT(tunnel_timeout);
+ tunnelkill(t, "Expired");
+ continue;
+ }
+ // check for message resend
+ if (tunnel[t].retry && tunnel[t].controlc)
+ {
+ // resend pending messages as timeout on reply
+ if (tunnel[t].retry <= TIME)
+ {
+ controlt *c = tunnel[t].controls;
+ u8 w = tunnel[t].window;
+ tunnel[t].try++; // another try
+ if (tunnel[t].try > 5)
+ tunnelkill(t, "Timeout on control message"); // game over
+ else
+ while (c && w--)
+ {
+ tunnelsend(c->buf, c->length, t);
+ c = c->next;
+ }
+ }
+ }
+ // Send hello
+ if (tunnel[t].state == TUNNELOPEN && tunnel[t].lastrec < 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 <= 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 <= TIME)
+ {
+ // Dump accounting data
+ next_acct = 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 != TIME) {
+ log(2,0,0,0, "Tunnel %d still has un-acked control messages.\n", i);
+ last_talked = TIME;
+ }
+ return 1;
+ }
+
+ for (i = 1; i < MAXRADIUS; i++)
+ {
+ if (radius[i].state == RADIUSNULL)
+ continue;
+ if (radius[i].state == RADIUSWAIT)
+ continue;
+
+ if (last_talked != TIME) {
+ log(2,0,0,0, "Radius session %d is still busy (sid %d)\n", i, radius[i].session);
+ last_talked = 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;