This shows you the differences between two versions of the page.
— |
sdk:scripts:dynamic-operator [2015/05/05 15:04] (current) |
||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ====== SDK Script dynamic-operator.are ====== | ||
+ | <code c dynamic-operator.are> | ||
+ | /* DESC: This script will scan Mobile2 and dial the appropriate SIM on Mobile1 | ||
+ | * Copyright (C) 2013 NetModule AG, Switzerland | ||
+ | * | ||
+ | */ | ||
+ | |||
+ | template operator { | ||
+ | prio; | ||
+ | sim; | ||
+ | lai; | ||
+ | apn; | ||
+ | username; | ||
+ | password; | ||
+ | |||
+ | int operator (int p, int s, string l, string a, string usr, string pwd) { | ||
+ | this.prio = p; | ||
+ | this.sim = s; | ||
+ | this.lai = l; | ||
+ | this.apn = a; | ||
+ | this.username = usr; | ||
+ | this.password = pwd; | ||
+ | return 0; | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | ME = argv[0]; /* script path */ | ||
+ | ARGV1 = argv[1]; /* 1st script argument */ | ||
+ | FORCE = 0; /* force operator switch even if wanlink is up */ | ||
+ | VALID_ONLY = 1; /* only register to networks which are allowed by SIM */ | ||
+ | SCAN_INTERVAL = 30; /* network scan interval in seconds */ | ||
+ | TEST = 0; /* run test */ | ||
+ | |||
+ | /* example list of operators */ | ||
+ | OPCNT = 0; | ||
+ | OPERATORS = mkarray(); | ||
+ | |||
+ | OPERATORS[OPCNT++] = new operator | ||
+ | (1, /* prio */ | ||
+ | 0, /* SIM1 */ | ||
+ | "22801", /* lai */ | ||
+ | "corporate.swisscom.ch", /* apn */ | ||
+ | "testprofil", /* username */ | ||
+ | "temporary" /* password */ | ||
+ | ); | ||
+ | OPERATORS[OPCNT++] = new operator | ||
+ | (2, /* prio */ | ||
+ | 1, /* SIM2 */ | ||
+ | "22802", /* lai */ | ||
+ | "internet", /* apn */ | ||
+ | "internet", /* username */ | ||
+ | "internet" /* password */ | ||
+ | ); | ||
+ | OPERATORS[OPCNT++] = new operator | ||
+ | (3, /* prio */ | ||
+ | 2, /* EXT1 */ | ||
+ | "26201", /* lai */ | ||
+ | "internet.telekom", /* apn */ | ||
+ | "tm", /* username */ | ||
+ | "" /* password */ | ||
+ | ); | ||
+ | |||
+ | |||
+ | /* creates file at path */ | ||
+ | int touch (string path) | ||
+ | { | ||
+ | fd = open(path, O_CREAT | O_WRONLY); | ||
+ | if (fd < 0) return -1; | ||
+ | close(fd); | ||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | /* checks if path exists */ | ||
+ | int exists (string path) | ||
+ | { | ||
+ | fd = open(path, O_RDONLY); | ||
+ | if (fd < 0) return 0; | ||
+ | close(fd); | ||
+ | return 1; | ||
+ | } | ||
+ | |||
+ | /* copies a file */ | ||
+ | int copy (string from, string to) | ||
+ | { | ||
+ | fpin = fopen(from, "r"); | ||
+ | if (is_void(fpin)) { | ||
+ | nb_syslog("unable to open %s", from); | ||
+ | return -1; | ||
+ | } | ||
+ | fpout = fopen(to, "w+"); | ||
+ | if (is_void(fpout)) { | ||
+ | fclose(fpin); | ||
+ | nb_syslog("unable to open %s", to); | ||
+ | return -1; | ||
+ | } | ||
+ | while (1) { | ||
+ | buf = fread(fpin, 1024); | ||
+ | if (is_void(buf)) break; | ||
+ | |||
+ | len = strlen(buf); | ||
+ | if (len == 0) break; | ||
+ | | ||
+ | fwrite(fpout, buf, len); | ||
+ | } | ||
+ | fclose(fpin); | ||
+ | fclose(fpout); | ||
+ | |||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | /* mkdir -p */ | ||
+ | int makedir (string path, int mode) | ||
+ | { | ||
+ | pc = explode(path); | ||
+ | |||
+ | if (pc[0] != "/") { | ||
+ | nb_syslog("no absolute directory given"); | ||
+ | return -1; | ||
+ | } | ||
+ | |||
+ | len = length(pc); | ||
+ | if (pc[len-1] != "/") pc[len++] = "/"; | ||
+ | p = ""; | ||
+ | |||
+ | for (i = 0; i < len; i++) { | ||
+ | if (pc[i] == "/" && i > 0) { | ||
+ | mkdir(p, mode); | ||
+ | } | ||
+ | p = strcat(p, pc[i]); | ||
+ | } | ||
+ | |||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | /* returns operator index for specified lai */ | ||
+ | int find_operator (string lai) | ||
+ | { | ||
+ | if (lai != "") { | ||
+ | /* search by lai first */ | ||
+ | for (o = 0; o < OPCNT; o++) { | ||
+ | if (OPERATORS[o].lai == lai) return o; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | return -1; /* not a known operator */ | ||
+ | } | ||
+ | |||
+ | /* returns wwan interface index for specified sim index */ | ||
+ | int find_wwan_interface (int sim) | ||
+ | { | ||
+ | for (o = 0; o < OPCNT; o++) { | ||
+ | op = OPERATORS[o]; | ||
+ | |||
+ | if (op.sim == sim) { | ||
+ | return o; | ||
+ | } | ||
+ | } | ||
+ | return -1; /* no wwan interface with this sim */ | ||
+ | } | ||
+ | |||
+ | /* returns current wwan interface index */ | ||
+ | int current_operator () | ||
+ | { | ||
+ | n = nb_config_get("wanlink.0.name"); | ||
+ | if (strlen(n) >= 5 && left(n, 4) == "wwan") { | ||
+ | return (int)substr(n, 4, 1); | ||
+ | } | ||
+ | |||
+ | return -1; /* not configured */ | ||
+ | } | ||
+ | |||
+ | /* activates specified operator */ | ||
+ | int activate_operator (int op) | ||
+ | { | ||
+ | current = current_operator(); | ||
+ | |||
+ | if (current != -1 && current == op) { | ||
+ | nb_syslog("wwan%d is already active", op); | ||
+ | return 0; | ||
+ | } | ||
+ | nb_syslog("switching to wwan%d", op); | ||
+ | |||
+ | if (nb_config_set(sprintf("wanlink.0.name=wwan%d", op)) != 0) { | ||
+ | nb_syslog("unable to activate wwan%d", op); | ||
+ | return -1; | ||
+ | } | ||
+ | /* re-configuration triggered */ | ||
+ | nb_syslog("activated wwan%d", op); | ||
+ | |||
+ | /* give modem some time to register */ | ||
+ | nb_syslog("waiting for wwan%d to come up", op); | ||
+ | sleep(30); /* needed for SIM switch */ | ||
+ | |||
+ | /* wait for wanlink to come up */ | ||
+ | for (i = 0; i < 20; i++) { | ||
+ | sleep(10); | ||
+ | |||
+ | nb_syslog("checking if wwan%d has come up", op); | ||
+ | st = nb_status("wan"); | ||
+ | |||
+ | ifc = struct_get(st, "WANLINK1_INTERFACE"); | ||
+ | if (ifc != sprintf("WWAN%d", op+1)) { | ||
+ | nb_syslog("wwan%d is not yet active"); | ||
+ | continue; | ||
+ | } | ||
+ | state = struct_get(st, "WANLINK1_STATE"); | ||
+ | if (state == "up") { | ||
+ | nb_syslog("wwan%d is up now", op); | ||
+ | return 0; | ||
+ | } | ||
+ | attempts = (int) struct_get(st, "WANLINK1_DIAL_ATTEMPTS"); | ||
+ | nb_syslog("wwan%d has dialed for %d times", op, attempts); | ||
+ | if (attempts > 2) { | ||
+ | nb_syslog("giving up after %d dial attempts", attempts); | ||
+ | return -1; | ||
+ | } | ||
+ | } | ||
+ | nb_syslog("giving up waiting for wanlink"); | ||
+ | |||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | /* returns true if wanlink is up */ | ||
+ | bool wanup () | ||
+ | { | ||
+ | st = nb_status("wan"); | ||
+ | state = struct_get(st, "WANLINK1_STATE"); | ||
+ | return (state == "up"); | ||
+ | } | ||
+ | |||
+ | /* scan test */ | ||
+ | struct nb_scan_test () | ||
+ | { | ||
+ | return mkstruct( | ||
+ | "NETWORK_COUNT", 2, | ||
+ | |||
+ | "NETWORK1_NAME", "swisscom", | ||
+ | "NETWORK1_LAI", "22801", | ||
+ | "NETWORK1_STATUS", "available", | ||
+ | |||
+ | "NETWORK2_NAME", "telekom", | ||
+ | "NETWORK2_LAI", "26201", | ||
+ | "NETWORK2_STATUS", "available" | ||
+ | ); | ||
+ | } | ||
+ | |||
+ | /* installs config and script */ | ||
+ | int install () | ||
+ | { | ||
+ | path = "/config"; | ||
+ | cfg = sprintf("%s/user-config.cfg", path); | ||
+ | |||
+ | makedir(sprintf("%s/files", path), S_IRUSR|S_IWUSR|S_IXUSR); | ||
+ | |||
+ | touch(cfg); | ||
+ | fp = fopen(cfg, "w"); | ||
+ | if (!fp) { | ||
+ | printf("ERROR: unable to open %s\n", cfg); | ||
+ | return -1; | ||
+ | } | ||
+ | |||
+ | /* basic system config */ | ||
+ | fwrite(fp, "config.version=1.3\n"); | ||
+ | fwrite(fp, sprintf("admin.password=%s\n", nb_config_get("admin.password"))); | ||
+ | |||
+ | /* set up OPERATORS */ | ||
+ | for (o = 0; o < OPCNT; o++) { | ||
+ | op = OPERATORS[o]; | ||
+ | fwrite(fp, sprintf("sim.%d.lai=%s\n", op.sim, op.lai)); | ||
+ | fwrite(fp, sprintf("wwan.%d.status=1\n", o)); | ||
+ | fwrite(fp, sprintf("wwan.%d.card=0\n", o)); /* force wwan0 */ | ||
+ | fwrite(fp, sprintf("wwan.%d.sim=%d\n", o, op.sim)); | ||
+ | fwrite(fp, sprintf("wwan.%d.number=*99***1#\n", o)); | ||
+ | fwrite(fp, sprintf("wwan.%d.username=%s\n", o, op.usename)); | ||
+ | fwrite(fp, sprintf("wwan.%d.password=%s\n", o, op.password)); | ||
+ | fwrite(fp, sprintf("wwan.%d.apn=%s\n", o, op.apn)); | ||
+ | } | ||
+ | |||
+ | /* enable first wwan interface */ | ||
+ | fwrite(fp, "wanlink.0.name=wwan0\n"); | ||
+ | fwrite(fp, "wanlink.0.prio=1\n"); | ||
+ | fwrite(fp, "wanlink.0.weight=0\n"); | ||
+ | fwrite(fp, "wanlink.0.mode=1\n"); | ||
+ | |||
+ | /* install this script */ | ||
+ | fwrite(fp, "sdk.status=1\n"); | ||
+ | fwrite(fp, "sdk.trigger.0.name=SDK-STARTUP\n"); | ||
+ | fwrite(fp, "sdk.trigger.0.event=sdk-startup\n"); | ||
+ | fwrite(fp, "sdk.script.0.name=dynamic-operator\n"); | ||
+ | fwrite(fp, "sdk.job.0.name=DYNAMIC-OPERATOR\n"); | ||
+ | fwrite(fp, "sdk.job.0.trigger=0\n"); | ||
+ | fwrite(fp, "sdk.job.0.script=0\n"); | ||
+ | |||
+ | scriptpath = sprintf("%s/files/home/sdk/scripts/uploaded", path); | ||
+ | makedir(scriptpath, S_IRUSR|S_IWUSR|S_IXUSR); | ||
+ | fclose(fp); | ||
+ | |||
+ | if (copy(ME, sprintf("%s/dynamic-operator", scriptpath)) != 0) { | ||
+ | printf("ERROR: cannot copy script"); | ||
+ | return -1; | ||
+ | } | ||
+ | |||
+ | return nb_update_config(sprintf("dir://%s", path)); | ||
+ | } | ||
+ | |||
+ | |||
+ | /* -------------------------------- main -------------------------------- */ | ||
+ | |||
+ | nb_syslog("starting %s", ME); | ||
+ | |||
+ | |||
+ | if (ARGV1 == "install") { | ||
+ | /* script installation requested */ | ||
+ | printf("installing script and its config\n"); | ||
+ | |||
+ | if (install() != 0) { | ||
+ | printf("unable to install script\n"); | ||
+ | exit(1); | ||
+ | } else { | ||
+ | printf("successfully installed script\n"); | ||
+ | } | ||
+ | /* script will terminate at this point */ | ||
+ | exit(0); | ||
+ | } | ||
+ | |||
+ | /* re-read operators */ | ||
+ | OPCNT = 0; | ||
+ | OPERATORS = mkarray(); | ||
+ | |||
+ | for (i = 0; i < 14; i++) { | ||
+ | status = nb_config_get(sprintf("wwan.%d.status", i)); | ||
+ | if (status != "1") { | ||
+ | continue; | ||
+ | } | ||
+ | |||
+ | sim = nb_config_get(sprintf("wwan.%d.sim", i)); | ||
+ | if (sim < 0) { | ||
+ | nb_syslog("invalid sim for wwan%d", i); | ||
+ | continue; | ||
+ | } | ||
+ | |||
+ | lai = nb_config_get(sprintf("sim.%d.lai", sim)); | ||
+ | |||
+ | OPERATORS[OPCNT].prio = i; | ||
+ | OPERATORS[OPCNT].lai = lai; | ||
+ | OPERATORS[OPCNT].sim = sim; | ||
+ | OPERATORS[OPCNT].username = nb_config_get(sprintf("wwan.%d.username", i)); | ||
+ | OPERATORS[OPCNT].password = nb_config_get(sprintf("wwan.%d.password", i)); | ||
+ | OPERATORS[OPCNT].apn = nb_config_get(sprintf("wwan.%d.apn", i)); | ||
+ | |||
+ | nb_syslog("added operator%d (prio %d, sim %d, lai %s)", | ||
+ | OPCNT, i, sim, lai); | ||
+ | |||
+ | OPCNT++; | ||
+ | } | ||
+ | |||
+ | while (1) { | ||
+ | nb_syslog("sleeping"); | ||
+ | sleep(SCAN_INTERVAL); | ||
+ | |||
+ | /* get wanlink state */ | ||
+ | up = wanup(); | ||
+ | if (up) { | ||
+ | nb_syslog("wanlink is up"); | ||
+ | } else { | ||
+ | nb_syslog("wanlink is down"); | ||
+ | } | ||
+ | |||
+ | /* get current operator */ | ||
+ | current = current_operator(); | ||
+ | if (current != -1) { | ||
+ | nb_syslog("current is wwan%d", current); | ||
+ | } | ||
+ | |||
+ | if (up && current != -1) { | ||
+ | nb_syslog("wwan%d is up", current); | ||
+ | if (FORCE != 1) continue; | ||
+ | } | ||
+ | |||
+ | /* scan networks */ | ||
+ | nb_syslog("scanning networks"); | ||
+ | if (TEST == 1) { | ||
+ | nets = nb_scan_test(); | ||
+ | } else { | ||
+ | nets = nb_scan_networks("Mobile2"); | ||
+ | } | ||
+ | nr_nets = struct_get(nets, "NETWORK_COUNT"); | ||
+ | |||
+ | if (is_void(nr_nets) || nr_nets < 1) { | ||
+ | nb_syslog("no networks found"); | ||
+ | continue; | ||
+ | } | ||
+ | |||
+ | nb_syslog("%d networks found", nr_nets); | ||
+ | |||
+ | best = -1; | ||
+ | prio = -1; | ||
+ | for (i = 1; i <= nr_nets; i++) { | ||
+ | net = trim(struct_get(nets, sprintf("NETWORK%d_NAME", i))); | ||
+ | lai = trim(struct_get(nets, sprintf("NETWORK%d_LAI", i))); | ||
+ | status = trim(struct_get(nets, sprintf("NETWORK%d_STATUS", i))); | ||
+ | |||
+ | nb_syslog("detected network '%s' (lai %s, status %s)", net, lai, status); | ||
+ | |||
+ | if (VALID_ONLY == 1 && status != "available") continue; | ||
+ | |||
+ | op = find_operator(lai, net); | ||
+ | if (op == -1) { | ||
+ | nb_syslog("network '%s' does not belong to a known operator", net); | ||
+ | continue; | ||
+ | } | ||
+ | if (current != -1 && op == current) { | ||
+ | /* skip current operator */ | ||
+ | continue; | ||
+ | } | ||
+ | if (prio == -1 || OPERATORS[op].prio < prio) { | ||
+ | best = op; | ||
+ | prio = OPERATORS[op].prio; | ||
+ | } | ||
+ | } | ||
+ | if (best != -1) { | ||
+ | /* activate best operator */ | ||
+ | activate_operator(best); | ||
+ | } else { | ||
+ | nb_syslog("no better operator found"); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | exit(0); | ||
+ | |||
+ | </code> | ||