[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