Differences

This shows you the differences between two versions of the page.

Link to this comparison view

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>​