Added upstart script
authorGregor Riepl <onitake@gmail.com>
Thu, 22 Jul 2010 16:07:22 +0000 (18:07 +0200)
committerGregor Riepl <onitake@gmail.com>
Thu, 22 Jul 2010 16:07:22 +0000 (18:07 +0200)
Modified readme with new project name and copyright
Fixed bugs, the daemon is tested and working for Bluetooth at least
Added network device name validation

README
device.c
device.h
event.d-maemo-tethering [new file with mode: 0644]
main.c

diff --git a/README b/README
index 613db3f..ada9d53 100644 (file)
--- a/README
+++ b/README
@@ -1,20 +1,25 @@
-maemo-tethering 1.0
--------------------
+mtetherd 0.1
+------------
 
 Description:
 
-maemo-tethering allows you to use your N900 as an Internet router.
+mtetherd allows you to use your N900 as an Internet router.
 Once a USB network or Bluetooth PAN connection is opened to the device,
 it will automatically configure networking and start a dnsmasq instance
 that serves DHCP requests and forwards DNS queries.
-This tool can also be used to automatically configure network interfaces
+You can also use it to automatically configure network interfaces
 for development.
 
+Requirements:
+
+The iptables and bluetooth-dun packages must be installed.
+They are required for setting up NAT and Bluetooth PAN support.
+
 Usage:
 
 Bluetooth:
 1. Pair your host with the N900 and make sure the PAN (Bluetooth networking)
-   service is recognized.
+   service is recognized on the host.
 2. Open a PAN connection to the N900.
 3. Routing should setup automatically and you can access the Internet
    right away.
@@ -28,7 +33,7 @@ USB:
 6. The USB mode is kept between cable disconnects, you only have to
    reload the g_ether module after a reboot or mode change.
 7. Start surfing on the host.
-3a.It is also possible to load the module from the Terminal:
+3a.It is also possible to load the module from the Terminal (untested):
 rmmod g_nokia
 rmmod g_file_storage
 modprobe g_ether
@@ -36,7 +41,7 @@ modprobe g_ether
 Notes:
 
 IP addresses are currently hardcoded into the program. A later version
-will add support for a configuration file.
+will add support for an external configuration file.
 The assigned addresses are the following:
 USB: N900: 192.168.253.254 DHCP: 192.168.253.1-192.168.253.253
 Bluetooth: N900: 192.168.254.254 DHCP: 192.168.254.1-192.168.254.253
@@ -48,8 +53,15 @@ You can still communicate with the device, but not surf the internet
 from your host. Just disconnect and reconnect again when the GPRS/UMTS
 connection is available.
 
+Bugs:
+
+Likely.
+Please submit a bug report on garage.maemo.org if you find any!
+
 Legal:
 
+mtetherd is (c) 2010 by Gregor Riepl <onitake@gmail.com>
+
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
index 9dbe424..7902ee4 100644 (file)
--- a/device.c
+++ b/device.c
@@ -1,21 +1,21 @@
 /*
-maemo-tethering
-(c) 2010 Gregor Riepl <onitake@gmail.com>
-
-Tethering utility for Maemo
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  maemo-tethering
+  (c) 2010 Gregor Riepl <onitake@gmail.com>
+  
+  Tethering utility for Maemo
+  
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+  
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include <stdio.h>
@@ -35,14 +35,11 @@ Device *device_new(const char *name) {
                return NULL;
        }
        memset(ret, 0, sizeof(Device));
-       size_t length = strlen(name) + 1;
-       ret->name = malloc(length);
+       device_set_name(ret, name);
        if (!ret->name) {
-               fprintf(stderr, "Error allocating memory for device name.\n");
                free(ret);
                return NULL;
        }
-       memcpy(ret->name, name, length);
        return ret;
 }
 
@@ -92,10 +89,31 @@ Device *device_set_name(Device *device, const char *name) {
                return NULL;
        }
        free(device->name);
-       size_t length = strlen(name) + 1;
-       device->name = malloc(length);
+       size_t length = strlen(name);
+       device->name = malloc(length + 1);
        if (!device->name) {
                fprintf(stderr, "Error allocating memory for device name.\n");
+       } else {
+               int filtered = 0;
+               size_t i, j;
+               for (i = 0, j = 0; i < length; i++) {
+                       if ((name[i] >= 'a' && name[i] <= 'z') || (name[i] >= '0' && name[i] <= '9')) {
+                               device->name[j] = name[i];
+                               j++;
+                       } else {
+                               filtered = 1;
+                       }
+               }
+               device->name[j] = '\0';
+               if (j == 0) {
+                       fprintf(stderr, "Error: Invalid device name.\n");
+                       free(device->name);
+                       device->name = NULL;
+               } else {
+                       if (filtered) {
+                               fprintf(stderr, "Warning, device name contained invalid characters. They have been removed.\n");
+                       }
+               }
        }
        return device;
 }
@@ -192,7 +210,7 @@ int device_validate(Device *device) {
 }
 
 Device *device_search(Device *start, const char *name) {
-       while (start) {
+       for (; start; start = start->next) {
                if (strcmp(start->name, name) == 0) {
                        return start;
                }
index 66e0002..3a216f0 100644 (file)
--- a/device.h
+++ b/device.h
@@ -1,21 +1,21 @@
 /*
-maemo-tethering
-(c) 2010 Gregor Riepl <onitake@gmail.com>
-
-Tethering utility for Maemo
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  maemo-tethering
+  (c) 2010 Gregor Riepl <onitake@gmail.com>
+  
+  Tethering utility for Maemo
+  
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+  
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 struct Device;
diff --git a/event.d-maemo-tethering b/event.d-maemo-tethering
new file mode 100644 (file)
index 0000000..cf4dd9d
--- /dev/null
@@ -0,0 +1,12 @@
+description "maemo-tethering"
+author "Gregor Riepl <onitake@gmail.com>"
+
+start on started dbus
+stop on stopping dbus
+
+console none
+
+exec /usr/sbin/maemo-tethering
+
+respawn
+
diff --git a/main.c b/main.c
index ac3f25b..d86ad4e 100644 (file)
--- a/main.c
+++ b/main.c
@@ -1,21 +1,21 @@
 /*
-maemo-tethering
-(c) 2010 Gregor Riepl <onitake@gmail.com>
-
-Tethering utility for Maemo
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  maemo-tethering
+  (c) 2010 Gregor Riepl <onitake@gmail.com>
+  
+  Tethering utility for Maemo
+  
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+  
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include <stdio.h>
@@ -33,8 +33,8 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 static const char *INETDEV = "gprs0";
 static const char *DEVICES[] = {
-       "bnep0",
        "usb0",
+       "bnep0",
        NULL
 };
 static const char *ADDRESSES[] = {
@@ -52,6 +52,10 @@ static const char *ENDADDRESSES[] = {
        "192.168.254.254",
        NULL
 };
+// Wait x seconds for process termination
+static const unsigned int TERMINATE_WAIT = 5;
+// Poll the main loop after x milliseconds
+static const unsigned int POLL_MAINLOOP = 500;
 
 // Run loop active flag
 static int running;
@@ -59,8 +63,15 @@ static int running;
 static unsigned int active;
 
 static void siginthandler(int sig) {
-       fprintf(stderr, "SIGINIT received, exiting\n");
-       running = 0;
+       if (running) {
+               fprintf(stderr, "SIGINIT received, exiting\n");
+               running = 0;
+       } else {
+               fprintf(stderr, "Another SIGINIT received, aborting\n");
+               if (kill(getpid(), SIGKILL) == -1) {
+                       fprintf(stderr, "PANIC! Error killing self: %s\n", strerror(errno));
+               }
+       }
 }
 
 static int launch(const char *args[]) {
@@ -74,19 +85,37 @@ static int launch(const char *args[]) {
                fprintf(stderr, "Can't fork external process %s: %s\n", args[0], strerror(errno));
                return -1;
        } else {
+               /*printf("Launching:");
+               size_t a;
+               for (a = 0; args[a]; a++) {
+                       printf(" %s", args[a]);
+               }
+               printf("\n");*/
                int status = 0;
-               if (waitpid(pid, &status, 0) == -1) {
-                       perror("Error waiting for child process completion");
-                       return -1;
+               if (waitpid(pid, &status, WNOHANG) == -1) {
+                       fprintf(stderr, "Error waiting for child process completion: %s\n", strerror(errno));
+                       return -2;
                }
-               if (WIFEXITED(status)) {
-                       if (WEXITSTATUS(status) != 0) {
-                               fprintf(stderr, "Child process returned error: %d\n", WEXITSTATUS(status));
-                               return -1;
+               size_t i;
+               for (i = 0; i < TERMINATE_WAIT && !WIFEXITED(status); i++) {
+                       if (WIFEXITED(status)) {
+                               if (WEXITSTATUS(status) != 0) {
+                                       fprintf(stderr, "Child process returned error: %d\n", WEXITSTATUS(status));
+                                       return -3;
+                               }
+                       } else if (WIFSIGNALED(status)) {
+                               fprintf(stderr, "Child process killed by signal: %d\n", WTERMSIG(status));
+                               return -4;
+                       }
+                       sleep(1);
+                       if (waitpid(pid, &status, WNOHANG) == -1) {
+                               fprintf(stderr, "Error waiting for child process completion: %s\n", strerror(errno));
+                               return -2;
                        }
-               } else if (WIFSIGNALED(status)) {
-                       fprintf(stderr, "Child process killed by signal: %d\n", WTERMSIG(status));
-                       return -1;
+               }
+               if (i >= TERMINATE_WAIT) {
+                       fprintf(stderr, "Child process %s still running after %u seconds, ignoring.\n", args[0], TERMINATE_WAIT);
+                       return -5;
                }
        }
        return 0;
@@ -100,7 +129,7 @@ static void added(Device *device, const char *inetdev) {
                return;
        }
        char *range = NULL;
-       if (asprintf(&range, "%s-%s,3600", device->startaddress, device->endaddress) == -1) {
+       if (asprintf(&range, "%s,%s,3600", device->startaddress, device->endaddress) == -1) {
                fprintf(stderr, "Can't construct address range parameter for device %s: %s\n", device->name, strerror(errno));
                free(runfile);
                return;
@@ -108,7 +137,7 @@ static void added(Device *device, const char *inetdev) {
        const char *ifconfig[] = { "/sbin/ifconfig", device->name, device->address, "up", NULL };
        const char *modprobe[] = { "/sbin/modprobe", "ipt_MASQUERADE", NULL };
        const char *iptables[] = { "/usr/sbin/iptables", "-t", "nat", "-A", "POSTROUTING", "-o", inetdev, "-j", "MASQUERADE", NULL };
-       const char *dnsmasq[] = { "/sbin/start-stop-daemon", "-S", "-p", runfile, "-m", "-b", "-x", "/usr/sbin/dnsmasq", "--", "-k", "-I", "lo", "-i", device->name, "-a", device->address, "-z", "-F", range, NULL };
+       const char *dnsmasq[] = { "/sbin/start-stop-daemon", "-S", "-p", runfile, "-b", "-x", "/usr/sbin/dnsmasq", "--", "-x", runfile, "-k", "-I", "lo", "-i", device->name, "-a", device->address, "-z", "-F", range, NULL };
        char *forwsysctl = NULL;
        if (asprintf(&forwsysctl, "/proc/sys/net/ipv4/conf/%s/forwarding", device->name) == -1) {
                fprintf(stderr, "Can't construct sysctl path for device %s: %s\n", device->name, strerror(errno));
@@ -175,6 +204,9 @@ static void removed(Device *device, const char *inetdev) {
 
        // Errors are ignored here: we just disable as much as we can.
        launch(dnsmasq);
+       if (unlink(runfile) == -1) {
+               fprintf(stderr, "Error removing PID file for device %s: %s\n", device->name, strerror(errno));
+       }
        launch(iptables);
 
        free(runfile);
@@ -200,9 +232,7 @@ static void removed(Device *device, const char *inetdev) {
 }
 
 int main(int argc, const char *argv[]) {
-       running = 1;
        active = 0;
-       signal(SIGINT, siginthandler);
 
        Device *devices = NULL;
        Device *node = NULL;
@@ -250,8 +280,10 @@ int main(int argc, const char *argv[]) {
        }
        dbus_connection_flush(conn);
 
+       running = 1;
+       signal(SIGINT, siginthandler);
        while (running) {
-               dbus_connection_read_write(conn, 500);
+               dbus_connection_read_write(conn, POLL_MAINLOOP);
                DBusMessage* msg = dbus_connection_pop_message(conn);
                if (msg) {
                        if (dbus_message_is_signal(msg, "org.kernel.kevent", "add")) {