[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[tyndur-devel] [PATCH] tcpip: UDP-Unterstützung



+ tcpip: UDP-Client-Unterstützung. tcpip:/udp/<sport>:<host>:<port>
  öffnet einen UDP-"Socket".

Signed-off-by: Kevin Wolf <kevin@xxxxxxxxxx>
---
 src/modules/tcpip/checksum.c          |   31 +++-
 src/modules/tcpip/include/lostio_if.h |    2 +
 src/modules/tcpip/include/udp.h       |   59 ++++++
 src/modules/tcpip/ip.c                |    2 +
 src/modules/tcpip/lostio_if.c         |    2 +
 src/modules/tcpip/udp.c               |  366 +++++++++++++++++++++++++++++++++
 6 files changed, 461 insertions(+), 1 deletions(-)
 create mode 100644 src/modules/tcpip/include/udp.h
 create mode 100644 src/modules/tcpip/udp.c

diff --git a/src/modules/tcpip/checksum.c b/src/modules/tcpip/checksum.c
index 80db51e..36fbdb7 100644
--- a/src/modules/tcpip/checksum.c
+++ b/src/modules/tcpip/checksum.c
@@ -44,6 +44,7 @@
 
 #include "ip.h"
 #include "tcp.h"
+#include "udp.h"
 
 bool debug_checksum = false;
 
@@ -87,7 +88,6 @@ uint16_t tcp_checksum
     (struct tcp_header* header, struct tcp_pseudo_header* pseudo_header,
     void* data, uint32_t data_size)
 {
-    //printf("data_size = %d\n", data_size);
     char buffer[sizeof(struct tcp_header) + sizeof(struct tcp_pseudo_header) 
         + data_size];
 
@@ -110,3 +110,32 @@ void tcp_update_checksum
     header->checksum = 0;
     header->checksum = tcp_checksum(header, pseudo_header, data, data_size);
 }
+
+uint16_t udp_checksum
+    (struct udp_header* header, struct udp_pseudo_header* pseudo_header,
+    void* data, uint32_t data_size)
+{
+    uint16_t sum;
+    char buffer[sizeof(struct udp_header) + sizeof(struct udp_pseudo_header)
+        + data_size];
+
+    memcpy(buffer, pseudo_header, sizeof(struct udp_pseudo_header));
+    memcpy(buffer + sizeof(struct udp_pseudo_header), header,
+        sizeof(struct udp_header));
+    memcpy(buffer + sizeof(struct udp_pseudo_header) + sizeof(struct udp_header),
+        data, data_size);
+
+    sum = ip_checksum(buffer,
+        sizeof(struct udp_pseudo_header) + sizeof(struct udp_header) +
+        data_size);
+
+    return sum ? sum : 0xffff;
+}
+
+void udp_update_checksum
+    (struct udp_header* header, struct udp_pseudo_header* pseudo_header,
+    void* data, uint32_t data_size)
+{
+    header->checksum = 0;
+    header->checksum = udp_checksum(header, pseudo_header, data, data_size);
+}
diff --git a/src/modules/tcpip/include/lostio_if.h b/src/modules/tcpip/include/lostio_if.h
index 658035b..854de9e 100644
--- a/src/modules/tcpip/include/lostio_if.h
+++ b/src/modules/tcpip/include/lostio_if.h
@@ -48,6 +48,8 @@
 #define LOSTIO_TYPES_SERVER  251
 #define LOSTIO_TYPES_SERVER_DIR  250
 #define LOSTIO_TYPES_SERVER_CONN 249
+#define LOSTIO_TYPES_UDP_DIR 248
+#define LOSTIO_TYPES_UDP 247
 
 
 void init_lostio_interface(void);
diff --git a/src/modules/tcpip/include/udp.h b/src/modules/tcpip/include/udp.h
new file mode 100644
index 0000000..eb7c491
--- /dev/null
+++ b/src/modules/tcpip/include/udp.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2011 The tyndur Project. All rights reserved.
+ *
+ * This code is derived from software contributed to the tyndur Project
+ * by Kevin Wolf.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UDP_H
+#define UDP_H
+
+#include <stdint.h>
+
+struct udp_header {
+    uint16_t    src_port;
+    uint16_t    dest_port;
+    uint16_t    length;
+    uint16_t    checksum;
+} __attribute__ ((packed));
+
+struct udp_pseudo_header {
+    uint32_t    source_ip;
+    uint32_t    dest_ip;
+    uint16_t    proto;
+    uint16_t    length;
+} __attribute__ ((packed));
+
+
+void udp_register_lostio(void);
+void udp_receive(uint32_t source_ip, void* data, uint32_t data_size);
+
+uint16_t udp_checksum
+    (struct udp_header* header, struct udp_pseudo_header* pseudo_header,
+    void* data, uint32_t data_size);
+void udp_update_checksum
+    (struct udp_header* header, struct udp_pseudo_header* pseudo_header,
+    void* data, uint32_t data_size);
+
+#endif
diff --git a/src/modules/tcpip/ip.c b/src/modules/tcpip/ip.c
index 49f9e10..d3c9d14 100644
--- a/src/modules/tcpip/ip.c
+++ b/src/modules/tcpip/ip.c
@@ -47,6 +47,7 @@
 #include "arp.h"
 #include "ethernet.h"
 #include "tcp.h"
+#include "udp.h"
 
 //Hier koennen die Debug-Nachrichten aktiviert werden
 #define DEBUG 0
@@ -278,6 +279,7 @@ void ip_receive(struct device *device, void *data, size_t data_size)
 
         case IP_PROTO_UDP:
             DEBUG_MSG("UDP-Paket eingegangen");
+            udp_receive(header->source_ip, packet, packet_size);
             break;
 
         default:
diff --git a/src/modules/tcpip/lostio_if.c b/src/modules/tcpip/lostio_if.c
index cf7d27c..e37c305 100644
--- a/src/modules/tcpip/lostio_if.c
+++ b/src/modules/tcpip/lostio_if.c
@@ -47,6 +47,7 @@
 #include "network.h"
 #include "ip.h"
 #include "tcp.h"
+#include "udp.h"
 #include "lostio_if.h"
 #include "dns.h"
 
@@ -129,6 +130,7 @@ void init_lostio_interface(void)
 
     // Weitere Typen
     tcp_server_register_lostio();
+    udp_register_lostio();
 
     // Dateien/Verzeichnisse anlegen
     vfstree_create_node("/dns", LOSTIO_TYPES_DNS, 0, NULL, 
diff --git a/src/modules/tcpip/udp.c b/src/modules/tcpip/udp.c
new file mode 100644
index 0000000..8755fef
--- /dev/null
+++ b/src/modules/tcpip/udp.c
@@ -0,0 +1,366 @@
+/*
+ * Copyright (c) 2011 The tyndur Project. All rights reserved.
+ *
+ * This code is derived from software contributed to the tyndur Project
+ * by Kevin Wolf.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "udp.h"
+#include "ip.h"
+#include "dns.h"
+#include "lostio_if.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <syscall.h>
+#include <stdint.h>
+
+struct udp_socket {
+    uint16_t local_port;
+    uint16_t remote_port;
+    uint32_t local_ip;
+    uint32_t remote_ip;
+
+    list_t* incoming_packets;
+};
+
+struct udp_packet {
+    size_t length;
+    char data[];
+};
+
+static list_t* udp_sockets;
+
+/**
+ * Parst einen gegebenen String, der eine Verbindung im Format
+ * <Lokaler Port>:<Remote-Hostname>:<Remote-Port> beschreibt.
+ *
+ * Rückgabe:
+ *       0: Erfolg
+ * -EINVAL: Falsches Format
+ * -ENOENT: Der DNS-Name konnte nicht aufgelöst werden
+ */
+static int parse_connection(const char* filename, int* sport,
+    uint32_t* daddr, int* dport)
+{
+    int ret, tmp_sport, tmp_dport;
+    uint32_t tmp_daddr;
+    char hostname[64];
+
+    /* Verzeichnisname abschneiden */
+    if (strncmp(filename, "/udp/", strlen("/udp/"))) {
+        return -EINVAL;
+    }
+
+    filename = filename + strlen("/udp/");
+
+    /* Wenn der Aufrufer das Ergebnis nicht braucht, lokale Variablen nehmen */
+    if (sport == NULL || daddr == NULL || dport == NULL) {
+        sport = &tmp_sport;
+        daddr = &tmp_daddr;
+        dport = &tmp_dport;
+    }
+
+    /* Dateiname auseinandernehmen */
+    ret = sscanf(filename, "%d:%63[^:]:%d", sport, hostname, dport);
+    if (ret != 3) {
+        return -EINVAL;
+    }
+
+    /* Servername auflösen, wenn es keine IP-Adresse war */
+    uint32_t ip = string_to_ip(hostname);
+    if (!ip) {
+        struct dns_request_result* result = dns_request(hostname);
+        if (result && (result->ip_count > 0)) {
+            ip = result->ip_address[0];
+        }
+    }
+
+    if (!ip) {
+        return -ENOENT;
+    }
+
+    *daddr = ip;
+    return 0;
+}
+
+/**
+ * Legt Knoten im Verzeichnisbaum an, die noch nicht existieren, wenn auf sie
+ * zugegriffen werden soll
+ */
+static bool lio_udp_dir_not_found(char** path, uint8_t flags, pid_t pid,
+    io_resource_t* ps)
+{
+    int ret;
+
+    ret = parse_connection(*path, NULL, NULL, NULL);
+    if (ret < 0) {
+        return false;
+    }
+
+    return vfstree_create_node(*path, LOSTIO_TYPES_UDP, 0, NULL,
+        LOSTIO_FLAG_NOAUTOEOF);
+}
+
+/**
+ * Das Oeffnen einer Datei in tcpip:/tcp-listen registriert einen TCP-Server.
+ * Wenn ein Client verbindet, wird in der geoeffneten Datei der Dateiname zum
+ * Oeffnen der Verbindung ausgegeben
+ */
+static bool lio_udp_pre_open(char** path, uint8_t flags, pid_t pid,
+    io_resource_t* ps)
+{
+    int i;
+    struct udp_socket* s;
+    vfstree_node_t* node;
+    int ret, sport, dport;
+    uint32_t daddr;
+    struct routing_entry* route;
+
+    /* Knoten raussuchen */
+    node = vfstree_get_node_by_path(*path);
+    if (node == NULL) {
+        return false;
+    }
+
+    /* Pfad auseinandernehmen */
+    ret = parse_connection(*path, &sport, &daddr, &dport);
+    if (ret < 0) {
+        return false;
+    }
+
+    p();
+    route = get_routing_entry(daddr);
+    if (route == NULL || route->device == NULL) {
+        v();
+        return false;
+    }
+
+    /* Pruefen, ob der Port nicht schon belegt ist */
+    for (i = 0; (s = list_get_element_at(udp_sockets, i)); i++) {
+        if (s->local_port == sport) {
+            v();
+            return false;
+        }
+    }
+
+    /* Neuen Socket anlegen und der Ressource zuordnen */
+    s = calloc(1, sizeof(*s));
+    s->local_port = sport;
+    s->local_ip = route->device->ip;
+    s->remote_port = dport;
+    s->remote_ip = daddr;
+    s->incoming_packets = list_create();
+    node->data = s;
+
+    list_push(udp_sockets, s);
+    v();
+
+    return true;
+}
+
+/**
+ * Liest ein einzelnes UDP-Paket aus
+ */
+size_t lio_udp_read(lostio_filehandle_t* fh, void* buf,
+    size_t blocksize, size_t count)
+{
+    struct udp_socket* s = fh->node->data;
+    struct udp_packet* p;
+    size_t len;
+
+    p = list_pop(s->incoming_packets);
+    if (p == NULL) {
+        return 0;
+    }
+
+    len = p->length;
+    if (blocksize * count < len) {
+        len = blocksize * count;
+    }
+
+    strncpy(buf, p->data, len);
+    free(p);
+
+    return len;
+}
+
+/**
+ * Empfängt ein eingehendes UDP-Paket
+ */
+void udp_receive(uint32_t source_ip, void* data, uint32_t data_size)
+{
+    struct udp_header* hdr = data;
+    struct udp_packet* p;
+    struct udp_socket* s;
+    void* payload;
+    size_t payload_size;
+    size_t pktlen;
+    int i;
+
+    if (data_size < sizeof(*hdr)) {
+        return;
+    }
+
+    p();
+    for (i = 0; (s = list_get_element_at(udp_sockets, i)); i++) {
+        if (   s->remote_ip   == source_ip
+            && s->remote_port == big_endian_word(hdr->src_port)
+            && s->local_port  == big_endian_word(hdr->dest_port))
+        {
+            goto found;
+        }
+    }
+    goto out;
+
+found:
+    pktlen = big_endian_word(hdr->length);
+    if (pktlen > data_size) {
+        goto out;
+    }
+
+    payload = hdr + 1;
+    payload_size = pktlen - sizeof(struct udp_header);
+
+    struct udp_pseudo_header phdr = {
+        .source_ip  = s->remote_ip,
+        .dest_ip    = s->local_ip,
+        .proto      = big_endian_word(IP_PROTO_UDP),
+        .length     = big_endian_word(data_size),
+    };
+
+    if (udp_checksum(hdr, &phdr, payload, payload_size) != 0xffff) {
+        printf("\033[1;31mUDP-Checksumme ungueltig\n\033[0;37m\n\n");
+        goto out;
+    }
+
+    p = malloc(sizeof(*p) + payload_size);
+    p->length = payload_size;
+    memcpy(p->data, payload, payload_size);
+
+    list_insert(s->incoming_packets, list_size(s->incoming_packets), p);
+
+out:
+    v();
+}
+
+/**
+ * Schreibt ein einzelnes UDP-Paket
+ */
+size_t lio_udp_write(lostio_filehandle_t* fh, size_t blocksize, size_t count,
+    void* buf)
+{
+    struct udp_socket* s = fh->node->data;
+    size_t len = blocksize * count;
+
+    size_t udp_packet_size = len + sizeof(struct udp_header);
+    uint8_t udp_packet[udp_packet_size];
+
+    struct udp_header* hdr = (struct udp_header*) udp_packet;
+    struct udp_pseudo_header phdr;
+
+    phdr = (struct udp_pseudo_header) {
+        .source_ip  = s->local_ip,
+        .dest_ip    = s->remote_ip,
+        .proto      = big_endian_word(IP_PROTO_UDP),
+        .length     = big_endian_word(udp_packet_size),
+    };
+
+    *hdr = (struct udp_header) {
+        .src_port   = big_endian_word(s->local_port),
+        .dest_port  = big_endian_word(s->remote_port),
+        .length     = big_endian_word(udp_packet_size),
+        .checksum   = 0,
+    };
+
+    memcpy(udp_packet + sizeof(struct udp_header), buf, len);
+    udp_update_checksum(hdr, &phdr,
+        udp_packet + sizeof(struct udp_header), len);
+
+    ip_send(s->remote_ip, IP_PROTO_UDP, udp_packet, udp_packet_size);
+
+    return len;
+}
+
+/**
+ * Beendet eine UDP-Verbindung
+ */
+int lio_udp_close(lostio_filehandle_t* fh)
+{
+    struct udp_socket* s = fh->node->data;
+    struct udp_socket* cur;
+    struct udp_packet* p;
+    int i;
+
+    /* Aus der Liste der UDP-Sockets entfernen */
+    p();
+    for (i = 0; (cur = list_get_element_at(udp_sockets, i)); i++) {
+        if (s == cur) {
+            list_remove(udp_sockets, i);
+            break;
+        }
+    }
+    v();
+
+    /* VFS-Knoten entfernen */
+    fh->node->data = NULL;
+    while ((p = list_pop(s->incoming_packets))) {
+        free(p);
+    }
+    list_destroy(s->incoming_packets);
+    free(s);
+    vfstree_delete_child(fh->node->parent, fh->node->name);
+
+    return 0;
+}
+
+/** Typ fuer einen UDP-Socket */
+static typehandle_t lio_type_udp = {
+    .id          = LOSTIO_TYPES_UDP,
+    .pre_open    = &lio_udp_pre_open,
+    .read        = &lio_udp_read,
+    .write       = &lio_udp_write,
+    .close       = &lio_udp_close,
+};
+
+/**
+ * Registriert die LostIO-Typehandles, die fuer UDP benoetigt werden
+ */
+void udp_register_lostio(void)
+{
+    udp_sockets = list_create();
+
+    /* Typ fuer das Verzeichnis udp */
+    lostio_type_directory_use_as(LOSTIO_TYPES_UDP_DIR);
+    get_typehandle(LOSTIO_TYPES_UDP_DIR)->not_found = &lio_udp_dir_not_found;
+
+    /* Typen fuer einen TCP-Server und seine Verbindungen */
+    lostio_register_typehandle(&lio_type_udp);
+
+    /* Knoten erstellen */
+    vfstree_create_node("/udp", LOSTIO_TYPES_UDP_DIR, 0, NULL,
+        LOSTIO_FLAG_BROWSABLE);
+}
-- 
1.6.0.2