[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[tyndur-devel] [PATCH] tcpip: Unterstuetzung fuer TCP-Server
+ tcpip: Unterstuetzung fuer TCP-Server. Um Verbindungen
entgegenzunehmen, muss sich ein Server zunaechst fuer einen Port
registrieren, indem er tcpip:/tcp-listen/:<port> oeffnet. Sobald ein
Client eine Verbindung oeffnen will, wird in dieser Datei der Name
einer zweiten Datei in tcpip:/tcp-conn ausgegeben, die geoeffnet
werden muss, um die Verbindung anzunehmen (pro Client eine Zeile).
Signed-off-by: Kevin Wolf <kevin@xxxxxxxxxx>
---
src/modules/tcpip/include/lostio_if.h | 18 ++
src/modules/tcpip/include/tcp.h | 21 ++
src/modules/tcpip/lostio_if.c | 13 +-
src/modules/tcpip/tcp.c | 25 +++
src/modules/tcpip/tcp_server.c | 343 +++++++++++++++++++++++++++++++++
5 files changed, 414 insertions(+), 6 deletions(-)
create mode 100644 src/modules/tcpip/tcp_server.c
diff --git a/src/modules/tcpip/include/lostio_if.h b/src/modules/tcpip/include/lostio_if.h
index 894ea80..1d34799 100644
--- a/src/modules/tcpip/include/lostio_if.h
+++ b/src/modules/tcpip/include/lostio_if.h
@@ -38,8 +38,26 @@
#include "main.h"
+
+#define LOSTIO_TYPES_TCPPORT 255
+#define LOSTIO_TYPES_NETCONFIG 254
+#define LOSTIO_TYPES_DNS 253
+#define LOSTIO_TYPES_ROUTE 252
+#define LOSTIO_TYPES_SERVER 251
+#define LOSTIO_TYPES_SERVER_DIR 250
+#define LOSTIO_TYPES_SERVER_CONN 249
+
+
void init_lostio_interface(void);
void lostio_add_driver(struct driver *driver);
void lostio_add_device(struct device *device);
+size_t lostio_tcp_read(lostio_filehandle_t* fh, void* buf,
+ size_t blocksize, size_t count);
+size_t lostio_tcp_write
+ (lostio_filehandle_t* fh, size_t blocksize, size_t count, void* data);
+int lostio_tcp_close(lostio_filehandle_t* filehandle);
+
+
+
#endif
diff --git a/src/modules/tcpip/include/tcp.h b/src/modules/tcpip/include/tcp.h
index 42b5699..d192226 100644
--- a/src/modules/tcpip/include/tcp.h
+++ b/src/modules/tcpip/include/tcp.h
@@ -43,6 +43,7 @@
#define TCPS_WAIT_FOR_LAST_ACK 3
#define TCPS_CONNECTED_FIN 4
#define TCPS_CLOSED 5
+#define TCPS_WAIT_FOR_ACCEPT 6
#define TCPF_FIN (1 << 0)
#define TCPF_SYN (1 << 1)
@@ -107,9 +108,15 @@ struct tcp_out_buffer {
void* data;
};
+struct tcp_server {
+ uint16_t port;
+ list_t* requests;
+};
+
void init_tcp(void);
struct tcp_connection* tcp_open_connection(dword ip, word port);
+void tcp_accept_connection(struct tcp_connection* conn);
word tcp_checksum
(struct tcp_header* header, struct tcp_pseudo_header* pseudo_header,
@@ -128,4 +135,18 @@ void tcp_send_ack(struct tcp_connection* conn); // TODO Ersetzen
*/
size_t tcp_get_mss(struct tcp_connection* conn);
+/**
+ * Registriert die LostIO-Typehandles, die fuer TCP-Server benoetigt werden
+ */
+void tcp_server_register_lostio(void);
+
+/**
+ * Wird aufgerufen, um ein SYN-Paket zu behandeln. Erstellt eine Verbindung,
+ * ohne jedoch SYN ACK zu senden. Stattdessen wird der Server benachrichtigt
+ * und eine LostIO-Ressource angelegt, ueber die die Verbindung tatsaechlich
+ * auf TCP-Ebene geoeffnet wird.
+ */
+struct tcp_connection* tcp_incoming_connection(uint32_t ip,
+ struct tcp_header* header);
+
#endif
diff --git a/src/modules/tcpip/lostio_if.c b/src/modules/tcpip/lostio_if.c
index 3bb7f10..a3b0f1c 100644
--- a/src/modules/tcpip/lostio_if.c
+++ b/src/modules/tcpip/lostio_if.c
@@ -45,6 +45,7 @@
#include "network.h"
#include "ip.h"
#include "tcp.h"
+#include "lostio_if.h"
#include "dns.h"
//Hier koennen die Debug-Nachrichten aktiviert werden
@@ -67,11 +68,6 @@
#endif
-#define LOSTIO_TYPES_TCPPORT 255
-#define LOSTIO_TYPES_NETCONFIG 254
-#define LOSTIO_TYPES_DNS 253
-#define LOSTIO_TYPES_ROUTE 252
-
typehandle_t typehandle;
typehandle_t typehandle2;
typehandle_t typehandle3;
@@ -124,10 +120,15 @@ void init_lostio_interface(void)
lostio_register_typehandle(&typehandle3);
+ // Typ fuer das DNS-Verzeichnis
lostio_type_directory_use_as(LOSTIO_TYPES_DNS);
get_typehandle(LOSTIO_TYPES_DNS)->not_found = lostio_tcp_not_found;
vfstree_get_node_by_path("/")->type = LOSTIO_TYPES_DNS;
-
+
+ // Weitere Typen
+ tcp_server_register_lostio();
+
+ // Dateien/Verzeichnisse anlegen
vfstree_create_node("/dns", LOSTIO_TYPES_DNS, 0, NULL,
LOSTIO_FLAG_BROWSABLE);
vfstree_create_node("/route", LOSTIO_TYPES_ROUTE, 1, NULL, 0);
diff --git a/src/modules/tcpip/tcp.c b/src/modules/tcpip/tcp.c
index 7eac8b2..721a690 100644
--- a/src/modules/tcpip/tcp.c
+++ b/src/modules/tcpip/tcp.c
@@ -66,12 +66,14 @@
extern bool debug_checksum;
list_t* tcp_connections;
+list_t* tcp_servers;
void tcp_send_ack(struct tcp_connection* conn);
void init_tcp()
{
tcp_connections = list_create();
+ tcp_servers = list_create();
}
static word tcp_get_free_port(void)
@@ -129,6 +131,8 @@ static void tcp_send_packet(struct tcp_connection* conn, void* data,
tcp_update_checksum(buffer, &pseudo_header, buffer + sizeof(header), data_size + options_size);
+ DEBUG_MSG2("Sending packet to %x, ack = %d", conn->dest_ip,
+ conn->ack);
ip_send(conn->dest_ip, IP_PROTO_TCP, buffer, buffer_size);
}
@@ -153,6 +157,15 @@ void tcp_send_ack(struct tcp_connection* conn)
}
}
+static void tcp_send_syn_ack(struct tcp_connection* conn)
+{
+ conn->status = TCPS_CONNECTED;
+ conn->seq = 0; //TODO (dword) get_tick_count();
+
+ tcp_send_packet(conn, NULL, 0, TCPF_SYN | TCPF_ACK);
+ conn->seq++;
+}
+
static void tcp_send_reset(struct tcp_connection* conn)
{
tcp_send_packet(conn, NULL, 0, TCPF_RST);
@@ -214,6 +227,12 @@ struct tcp_connection* tcp_open_connection(dword ip, word port)
return conn;
}
+void tcp_accept_connection(struct tcp_connection* conn)
+{
+ DEBUG_MSG("tcp_send_syn_ack");
+ tcp_send_syn_ack(conn);
+}
+
struct tcp_connection* tcp_get_connection
(dword remote_ip, word remote_port, word local_port)
@@ -312,6 +331,12 @@ void tcp_receive(dword source_ip, void* data, dword data_size)
big_endian_word(header->dest_port));
DEBUG_MSG("--");
+
+ // Neue Verbindung fuer einen TCP-Server?
+ if ((conn == NULL) && (header->flags == TCPF_SYN)) {
+ conn = tcp_incoming_connection(source_ip, header);
+ }
+
if (conn == NULL) {
DEBUG_MSG1("Verbindung nicht gefunden. IP = %08x", source_ip);
return;
diff --git a/src/modules/tcpip/tcp_server.c b/src/modules/tcpip/tcp_server.c
new file mode 100644
index 0000000..da48ad6
--- /dev/null
+++ b/src/modules/tcpip/tcp_server.c
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2009 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the tyndur Project
+ * and its contributors.
+ * 4. Neither the name of the tyndur Project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 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 <lostio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <syscall.h>
+#include <rpc.h>
+#include <network.h>
+
+#include "ip.h"
+#include "tcp.h"
+#include "lostio_if.h"
+
+extern list_t* tcp_connections;
+extern list_t* tcp_servers;
+
+static void do_nothing(void) {}
+
+/**
+ * Legt Knoten im Verzeichnisbaum an, die noch nicht existieren, wenn auf sie
+ * zugegriffen werden soll
+ */
+static bool lio_server_dir_not_found(char** path, byte flags, pid_t pid,
+ io_resource_t* ps)
+{
+ return vfstree_create_node(*path, LOSTIO_TYPES_SERVER, 0, NULL, 0);
+}
+
+/**
+ * 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_server_pre_open(char** path, byte flags, pid_t pid,
+ io_resource_t* ps)
+{
+ char* s;
+ char* port;
+ int portnr;
+ int i;
+ struct tcp_server* server;
+ vfstree_node_t* node;
+
+ // Knoten raussuchen
+ node = vfstree_get_node_by_path(*path);
+ if (node == NULL) {
+ return FALSE;
+ }
+
+ // Pfad auseinandernehmen
+ if (strncmp(*path, "/tcp-listen/", strlen("/tcp-listen/"))) {
+ return FALSE;
+ }
+
+ s = *path + strlen("/tcp-listen/");
+ port = strchr(s, ':');
+ if (port == NULL) {
+ return FALSE;
+ }
+
+ port++;
+ portnr = atoi(port);
+ if (port == 0) {
+ return FALSE;
+ }
+
+ // Pruefen, ob der Port nicht schon belegt ist
+ p();
+ for (i = 0; (server = list_get_element_at(tcp_servers, i)); i++) {
+ if (server->port == portnr) {
+ return FALSE;
+ }
+ }
+ v();
+
+ // Neuen Server anlegen und der Ressource zuordnen
+ server = calloc(1, sizeof(*server));
+ server->port = portnr;
+ server->requests = list_create();
+ node->data = server;
+
+ p();
+ list_push(tcp_servers, server);
+ v();
+
+ return TRUE;
+}
+
+/**
+ * Liest eine Verbindung, die geoeffnet werden kann, aus
+ */
+size_t lio_server_read(lostio_filehandle_t* fh, void* buf,
+ size_t blocksize, size_t count)
+{
+ struct tcp_server* server = fh->node->data;
+ char* s;
+ size_t len;
+
+ s = list_pop(server->requests);
+ if (s == NULL) {
+ return 0;
+ }
+
+ len = strlen(s);
+ if (blocksize * count < len) {
+ len = blocksize * count;
+ }
+
+
+ strncpy(buf, s, len);
+ free(s);
+
+ return len;
+}
+
+/**
+ * Beendet einen Server
+ */
+int lio_server_close(lostio_filehandle_t* fh)
+{
+ struct tcp_server* server = fh->node->data;
+ struct tcp_server* cur;
+ char* s;
+ int i;
+
+ // Aus der Liste der Server entfernen
+ p();
+ for (i = 0; (cur = list_get_element_at(tcp_servers, i)); i++) {
+ if (server == cur) {
+ list_remove(tcp_servers, i);
+ break;
+ }
+ }
+ v();
+
+ // VFS-Knoten entfernen
+ fh->node->data = NULL;
+ while ((s = list_pop(server->requests))) {
+ free(s);
+ }
+ list_destroy(server->requests);
+ free(server);
+ vfstree_delete_child(fh->node->parent, fh->node->name);
+
+ return 0;
+}
+
+/**
+ * Wird aufgerufen, um ein SYN-Paket zu behandeln. Erstellt eine Verbindung,
+ * ohne jedoch SYN ACK zu senden. Stattdessen wird der Server benachrichtigt
+ * und eine LostIO-Ressource angelegt, ueber die die Verbindung tatsaechlich
+ * auf TCP-Ebene geoeffnet wird.
+ */
+struct tcp_connection* tcp_incoming_connection(uint32_t remote_ip,
+ struct tcp_header* header)
+{
+ struct tcp_server* server;
+ struct tcp_connection* conn;
+ struct routing_entry* route;
+ uint64_t timeout;
+ int i;
+
+ uint16_t remote_port = big_endian_word(header->source_port);
+ uint16_t local_port = header->dest_port;
+
+ // Server an header->dest_port suchen
+ server = NULL;
+ for (i = 0; (server = list_get_element_at(tcp_servers, i)); i++) {
+ if (server->port == header->dest_port) {
+ break;
+ }
+ }
+
+ if (server == NULL) {
+ return NULL;
+ }
+
+ // Duplikate suchen
+ // Wenn wir sowieso schon darauf warten, dass jemand die Verbindung
+ // annimmt, hilft uns ein zweites SYN-Paket auch nicht weiter.
+ conn = NULL;
+ for (i = 0; (conn = list_get_element_at(tcp_connections, i)); i++) {
+ if ((conn->source_port == local_port) &&
+ (conn->dest_port == remote_port) &&
+ (conn->dest_ip == remote_ip))
+ {
+ return NULL;
+ }
+ }
+
+ // Verbindung erstellen
+ conn = calloc(1, sizeof(struct tcp_connection));
+ route = get_routing_entry(remote_ip);
+
+ if (route == NULL) {
+ return NULL;
+ }
+
+ conn->dest_ip = remote_ip;
+ conn->dest_port = remote_port;
+ conn->source_ip = route->device->dev.ip;
+ conn->source_port = local_port;
+ conn->window = 0x1000;
+ conn->ack = big_endian_dword(header->seq) + 1;
+ conn->out_buffer = list_create();
+ conn->in_buffer = list_create();
+ conn->to_lostio = list_create();
+ conn->status = TCPS_WAIT_FOR_ACCEPT;
+
+ p();
+ list_push(tcp_connections, conn);
+ v();
+
+ // Neuen VFS-Knoten anlegen
+ char* ip_str = ip_to_string(remote_ip);
+ char* buf;
+ asprintf(&buf, "/tcp-conn/local:%d_%s:%d",
+ header->dest_port, ip_str, header->source_port);
+ vfstree_create_node(buf, LOSTIO_TYPES_SERVER_CONN, 0, conn,
+ LOSTIO_FLAG_NOAUTOEOF);
+ free(buf);
+
+ // Den Server informieren
+ asprintf(&buf, "tcpip:/tcp-conn/local:%d_%s:%d\n",
+ header->dest_port, ip_str, header->source_port);
+ free(ip_str);
+ p();
+ list_push(server->requests, buf);
+ v();
+
+ // Warten, bis der Server die Verbindung annimmt
+ timeout = get_tick_count() + 9 * 1000000;
+ timer_register(do_nothing, 10 * 1000000);
+ while ((conn->status == TCPS_WAIT_FOR_ACCEPT)
+ && (get_tick_count() < timeout))
+ {
+ wait_for_rpc();
+ }
+
+ if (conn->status == TCPS_WAIT_FOR_ACCEPT) {
+ // TODO Verbindung abbrechen und wieder freigeben
+ return NULL;
+ }
+
+ return conn;
+}
+
+/**
+ * Oeffnet eine eingehende Verbindung
+ */
+void lio_server_conn_post_open(lostio_filehandle_t* fh)
+{
+ struct tcp_connection* conn = fh->node->data;
+
+ tcp_accept_connection(conn);
+ fh->node->size++;
+}
+
+/**
+ * Schliesst eine eingehende Verbindung und entfernt sie aus dem
+ * Verzeichnisbaum.
+ */
+int lio_server_conn_close(lostio_filehandle_t* fh)
+{
+ int ret = lostio_tcp_close(fh);
+
+ // VFS-Knoten entfernen
+ vfstree_delete_child(fh->node->parent, fh->node->name);
+
+ return ret;
+}
+
+/// Typ fuer einen TCP-Server
+static typehandle_t lio_type_server = {
+ .id = LOSTIO_TYPES_SERVER,
+ .pre_open = &lio_server_pre_open,
+ .read = &lio_server_read,
+ .close = &lio_server_close,
+};
+
+/// Typ fuer eine Verbindung fuer TCP-Server
+static typehandle_t lio_type_server_conn = {
+ .id = LOSTIO_TYPES_SERVER_CONN,
+ .post_open = &lio_server_conn_post_open,
+ .read = &lostio_tcp_read,
+ .write = &lostio_tcp_write,
+ .close = &lio_server_conn_close,
+};
+
+/**
+ * Registriert die LostIO-Typehandles, die fuer TCP-Server benoetigt werden
+ */
+void tcp_server_register_lostio(void)
+{
+ // Typ fuer das Verzeichnis tcp-listen
+ lostio_type_directory_use_as(LOSTIO_TYPES_SERVER_DIR);
+ get_typehandle(LOSTIO_TYPES_SERVER_DIR)->not_found =
+ &lio_server_dir_not_found;
+
+ // Typen fuer einen TCP-Server und seine Verbindungen
+ lostio_register_typehandle(&lio_type_server);
+ lostio_register_typehandle(&lio_type_server_conn);
+
+ // Knoten erstellen
+ vfstree_create_node("/tcp-listen", LOSTIO_TYPES_SERVER_DIR, 0, NULL,
+ LOSTIO_FLAG_BROWSABLE);
+ vfstree_create_node("/tcp-conn", LOSTIO_TYPES_DIRECTORY, 0, NULL,
+ LOSTIO_FLAG_BROWSABLE);
+}
--
1.6.0.2