summaryrefslogtreecommitdiff
path: root/accel-pppd/session.c
diff options
context:
space:
mode:
Diffstat (limited to 'accel-pppd/session.c')
-rw-r--r--accel-pppd/session.c256
1 files changed, 256 insertions, 0 deletions
diff --git a/accel-pppd/session.c b/accel-pppd/session.c
new file mode 100644
index 00000000..0064f54f
--- /dev/null
+++ b/accel-pppd/session.c
@@ -0,0 +1,256 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <arpa/inet.h>
+#include <features.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <linux/if.h>
+
+#include "triton.h"
+#include "log.h"
+#include "events.h"
+#include "ap_session.h"
+#include "mempool.h"
+#include "memdebug.h"
+
+int conf_sid_ucase;
+pthread_rwlock_t __export ses_lock = PTHREAD_RWLOCK_INITIALIZER;
+__export LIST_HEAD(ses_list);
+
+int __export sock_fd;
+int __export sock6_fd;
+int __export urandom_fd;
+int __export ap_shutdown;
+
+static long long unsigned seq;
+
+struct ap_session_stat __export ap_session_stat;
+
+static void generate_sessionid(struct ap_session *ses);
+
+void __export ap_session_init(struct ap_session *ses)
+{
+ memset(ses, 0, sizeof(*ses));
+ INIT_LIST_HEAD(&ses->pd_list);
+}
+
+int __export ap_session_starting(struct ap_session *ses)
+{
+ struct ifreq ifr;
+
+ ses->start_time = time(NULL);
+
+ memset(&ifr, 0, sizeof(ifr));
+ strcpy(ifr.ifr_name, ses->ifname);
+
+ if (ioctl(sock_fd, SIOCGIFINDEX, &ifr)) {
+ log_ppp_error("ioctl(SIOCGIFINDEX): %s\n", strerror(errno));
+ return -1;
+ }
+ ses->ifindex = ifr.ifr_ifindex;
+
+ generate_sessionid(ses);
+
+ ses->state = AP_STATE_STARTING;
+ __sync_add_and_fetch(&ap_session_stat.starting, 1);
+
+ pthread_rwlock_wrlock(&ses_lock);
+ list_add_tail(&ses->entry, &ses_list);
+ pthread_rwlock_unlock(&ses_lock);
+
+ triton_event_fire(EV_SES_STARTING, ses);
+
+ return 0;
+}
+
+void __export ap_session_activate(struct ap_session *ses)
+{
+ ses->state = AP_STATE_ACTIVE;
+ __sync_sub_and_fetch(&ap_session_stat.starting, 1);
+ __sync_add_and_fetch(&ap_session_stat.active, 1);
+ ap_session_ifup(ses);
+}
+
+void __export ap_session_finished(struct ap_session *ses)
+{
+ ses->terminated = 1;
+
+ pthread_rwlock_wrlock(&ses_lock);
+ list_del(&ses->entry);
+ pthread_rwlock_unlock(&ses_lock);
+
+ switch (ses->state) {
+ case AP_STATE_ACTIVE:
+ __sync_sub_and_fetch(&ap_session_stat.active, 1);
+ break;
+ case AP_STATE_STARTING:
+ __sync_sub_and_fetch(&ap_session_stat.starting, 1);
+ break;
+ case AP_STATE_FINISHING:
+ __sync_sub_and_fetch(&ap_session_stat.finishing, 1);
+ break;
+ }
+
+ triton_event_fire(EV_SES_FINISHED, ses);
+ ses->ctrl->finished(ses);
+
+ if (ses->username) {
+ _free(ses->username);
+ ses->username = NULL;
+ }
+
+ if (ses->ipv4_pool_name) {
+ _free(ses->ipv4_pool_name);
+ ses->ipv4_pool_name = NULL;
+ }
+
+ if (ses->ipv6_pool_name) {
+ _free(ses->ipv6_pool_name);
+ ses->ipv6_pool_name = NULL;
+ }
+
+ if (ap_shutdown && !ap_session_stat.starting && !ap_session_stat.active && !ap_session_stat.finishing)
+ kill(getpid(), SIGTERM);
+}
+
+void __export ap_session_terminate(struct ap_session *ses, int cause, int hard)
+{
+ if (ses->terminated)
+ return;
+
+ if (!ses->stop_time)
+ time(&ses->stop_time);
+
+ if (!ses->terminate_cause)
+ ses->terminate_cause = cause;
+
+ if (ses->terminating) {
+ if (hard)
+ ses->ctrl->terminate(ses, hard);
+ return;
+ }
+
+ ses->terminating = 1;
+ ses->state = AP_STATE_FINISHING;
+
+ if (ses->state == AP_STATE_ACTIVE)
+ __sync_sub_and_fetch(&ap_session_stat.active, 1);
+ else
+ __sync_sub_and_fetch(&ap_session_stat.starting, 1);
+ __sync_add_and_fetch(&ap_session_stat.finishing, 1);
+
+ log_ppp_debug("terminate\n");
+
+ ap_session_ifdown(ses);
+
+ triton_event_fire(EV_SES_FINISHING, ses);
+
+ ses->ctrl->terminate(ses, hard);
+}
+
+void ap_shutdown_soft(void)
+{
+ ap_shutdown = 1;
+
+ if (!ap_session_stat.starting && !ap_session_stat.active && !ap_session_stat.finishing)
+ kill(getpid(), SIGTERM);
+}
+
+static void generate_sessionid(struct ap_session *ses)
+{
+ unsigned long long sid;
+
+#if __WORDSIZE == 32
+ spin_lock(&seq_lock);
+ sid = ++seq;
+ spin_unlock(&seq_lock);
+#else
+ sid = __sync_add_and_fetch(&seq, 1);
+#endif
+
+ if (conf_sid_ucase)
+ sprintf(ses->sessionid, "%016llX", sid);
+ else
+ sprintf(ses->sessionid, "%016llx", sid);
+}
+
+static void save_seq(void)
+{
+ FILE *f;
+ char *opt = conf_get_opt("ppp", "seq-file");
+ if (!opt)
+ opt = "/var/run/accel-ppp/seq";
+
+ f = fopen(opt, "w");
+ if (f) {
+ fprintf(f, "%llu", seq);
+ fclose(f);
+ }
+}
+
+static void load_config(void)
+{
+ char *opt;
+
+ opt = conf_get_opt("common", "sid-case");
+ if (opt) {
+ if (!strcmp(opt, "upper"))
+ conf_sid_ucase = 1;
+ else if (strcmp(opt, "lower"))
+ log_emerg("sid-case: invalid format\n");
+ }
+}
+
+static void init(void)
+{
+ const char *opt;
+ FILE *f;
+
+ sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock_fd < 0) {
+ perror("socket");
+ _exit(EXIT_FAILURE);
+ }
+
+ fcntl(sock_fd, F_SETFD, fcntl(sock_fd, F_GETFD) | FD_CLOEXEC);
+
+ sock6_fd = socket(AF_INET6, SOCK_DGRAM, 0);
+ if (sock6_fd < 0)
+ log_warn("ppp: kernel doesn't support ipv6\n");
+ else
+ fcntl(sock6_fd, F_SETFD, fcntl(sock6_fd, F_GETFD) | FD_CLOEXEC);
+
+ urandom_fd = open("/dev/urandom", O_RDONLY);
+ if (urandom_fd < 0) {
+ log_emerg("failed to open /dev/urandom: %s\n", strerror(errno));
+ return;
+ }
+
+ fcntl(urandom_fd, F_SETFD, fcntl(urandom_fd, F_GETFD) | FD_CLOEXEC);
+
+ opt = conf_get_opt("session", "seq-file");
+ if (!opt)
+ opt = "/var/run/accel-ppp/seq";
+
+ f = fopen(opt, "r");
+ if (f) {
+ fscanf(f, "%llu", &seq);
+ fclose(f);
+ } else
+ seq = (unsigned long long)random() * (unsigned long long)random();
+
+ load_config();
+ triton_event_register_handler(EV_CONFIG_RELOAD, (triton_event_func)load_config);
+
+ atexit(save_seq);
+}
+
+DEFINE_INIT(2, init);
+