From: <ljs...@us...> - 2006-09-16 16:18:36
|
Revision: 355 http://svn.sourceforge.net/cadcdev/?rev=355&view=rev Author: ljsebald Date: 2006-09-16 09:18:26 -0700 (Sat, 16 Sep 2006) Log Message: ----------- This is the last of the big networking changes for now. This update adds a completely new UDP system, and a working sockets system to go along with it. Modified Paths: -------------- kos/include/kos/net.h kos/kernel/fs/Makefile kos/kernel/net/net_core.c kos/kernel/net/net_udp.c kos/kernel/net/net_udp.h Added Paths: ----------- kos/include/kos/fs_socket.h kos/include/sys/socket.h kos/kernel/fs/fs_socket.c Added: kos/include/kos/fs_socket.h =================================================================== --- kos/include/kos/fs_socket.h (rev 0) +++ kos/include/kos/fs_socket.h 2006-09-16 16:18:26 UTC (rev 355) @@ -0,0 +1,38 @@ +/* KallistiOS ##version## + + kos/fs_socket.h + Copyright (C) 2006 Lawrence Sebald + +*/ + +#ifndef __KOS_FS_SOCKET_H +#define __KOS_FS_SOCKET_H + +#include <sys/cdefs.h> +__BEGIN_DECLS + +#include <arch/types.h> +#include <kos/limits.h> +#include <kos/fs.h> +#include <sys/queue.h> + +typedef struct net_socket { + /* List handle */ + LIST_ENTRY(net_socket) sock_list; + + /* Protocol of this socket. This corresponds to the IP protocol number */ + int protocol; + + /* Protocol specific data */ + void *data; +} net_socket_t; + +int fs_socket_init(); +int fs_socket_shutdown(); + +int fs_socket_setflags(int sock, int flags); + +__END_DECLS + +#endif /* __KOS_FS_SOCKET_H */ + Modified: kos/include/kos/net.h =================================================================== --- kos/include/kos/net.h 2006-09-14 03:04:48 UTC (rev 354) +++ kos/include/kos/net.h 2006-09-16 16:18:26 UTC (rev 355) @@ -210,23 +210,6 @@ /* Shutdown */ void net_udp_shutdown(); -/* Send a raw UDP packet, without a socket */ -int net_udp_send_raw(netif_t *net, uint16 src_port, uint16 dst_port, - const uint8 dst_ip[4], const uint8 *data, int size); - -/* Open a socket between the local system, and a remote host */ -int net_udp_sock_open(uint16 loc_port, uint32 loc_addr, uint16 rem_port, - uint32 rem_addr); - -/* Close a previously opened socket */ -int net_udp_sock_close(int sock); - -/* Send a packet on a socket */ -int net_udp_send(int sock, const uint8 *data, int size); - -/* Recieve a packet on a socket */ -int net_udp_recv(int sock, uint8 *buf, int size); - /***** net_core.c *********************************************************/ /* Interface list; note: do not manipulate directly */ Added: kos/include/sys/socket.h =================================================================== --- kos/include/sys/socket.h (rev 0) +++ kos/include/sys/socket.h 2006-09-16 16:18:26 UTC (rev 355) @@ -0,0 +1,56 @@ +/* KallistiOS ##version## + + sys/socket.h + Copyright (C)2006 Lawrence Sebald + +*/ + +#ifndef __SYS_SOCKET_H +#define __SYS_SOCKET_H + +#include <sys/cdefs.h> +#include <arch/types.h> + +__BEGIN_DECLS + +typedef uint32 socklen_t; + +#ifndef __SA_FAMILY_T_DEFINED +#define __SA_FAMILY_T_DEFINED +typedef uint32 sa_family_t; +#endif + +struct sockaddr { + sa_family_t sa_family; + char sa_data[]; +}; + +/* Socket types, currently only SOCK_DGRAM is available */ +#define SOCK_DGRAM 1 + +/* Socket address families. Currently only AF_INET is available */ +#define AF_INET 1 + +#define PF_INET AF_INET + +/* Socket shutdown macros. */ +#define SHUT_RD 0x00000001 +#define SHUT_WR 0x00000002 +#define SHUT_RDWR (SHUT_RD | SHUT_WR) + +int accept(int socket, struct sockaddr *address, socklen_t *address_len); +int bind(int socket, const struct sockaddr *address, socklen_t address_len); +int connect(int socket, const struct sockaddr *address, socklen_t address_len); +int listen(int socket, int backlog); +ssize_t recv(int socket, void *buffer, size_t length, int flags); +ssize_t recvfrom(int socket, void *buffer, size_t length, int flags, + struct sockaddr *address, socklen_t *address_len); +ssize_t send(int socket, const void *message, size_t length, int flags); +ssize_t sendto(int socket, const void *message, size_t length, int flags, + const struct sockaddr *dest_addr, socklen_t dest_len); +int shutdown(int socket, int how); +int socket(int domain, int type, int protocol); + +__END_DECLS + +#endif /* __SYS_SOCKET_H */ Modified: kos/kernel/fs/Makefile =================================================================== --- kos/kernel/fs/Makefile 2006-09-14 03:04:48 UTC (rev 354) +++ kos/kernel/fs/Makefile 2006-09-16 16:18:26 UTC (rev 355) @@ -6,7 +6,7 @@ # $Id: Makefile,v 1.3 2002/08/13 04:54:22 bardtx Exp $ OBJS = fs.o fs_romdisk.o fs_ramdisk.o fs_pty.o -OBJS += fs_utils.o elf.o +OBJS += fs_utils.o elf.o fs_socket.o SUBDIRS = include $(KOS_BASE)/Makefile.prefab Added: kos/kernel/fs/fs_socket.c =================================================================== --- kos/kernel/fs/fs_socket.c (rev 0) +++ kos/kernel/fs/fs_socket.c 2006-09-16 16:18:26 UTC (rev 355) @@ -0,0 +1,298 @@ +/* KallistiOS ##version## + + fs_socket.c + Copyright (C) 2006 Lawrence Sebald + +*/ + +#include <kos/mutex.h> +#include <arch/spinlock.h> +#include <kos/dbgio.h> +#include <kos/fs.h> +#include <kos/fs_socket.h> +#include <kos/net.h> + +#include <errno.h> +#include <string.h> +#include <malloc.h> +#include <sys/queue.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include "../net/net_ipv4.h" +#include "../net/net_udp.h" + +/* Define the socket list type */ +LIST_HEAD(socket_list, net_socket); + +static struct socket_list sockets; +static mutex_t *list_mutex; + +static void fs_socket_close(void *hnd) { + net_socket_t *sock = (net_socket_t *) hnd; + + mutex_lock(list_mutex); + LIST_REMOVE(sock, sock_list); + mutex_unlock(list_mutex); + + net_udp_close(hnd); + + free(sock); +} + +static off_t fs_socket_tell(void *hnd) { + errno = ESPIPE; + return (off_t) -1; +} + +/* VFS handler */ +static vfs_handler_t vh = { + /* Name handler */ + { + { 0 }, /* Name */ + 0, /* tbfi */ + 0x00010000, /* Version 1.0 */ + 0, /* Flags */ + NMMGR_TYPE_VFS, + NMMGR_LIST_INIT, + }, + + 0, NULL, /* No cache, privdata */ + + NULL, /* open */ + fs_socket_close, /* close */ + NULL, /* read */ + NULL, /* write */ + NULL, /* seek */ + fs_socket_tell, /* tell */ + NULL, /* total */ + NULL, /* readdir */ + NULL, /* ioctl */ + NULL, /* rename */ + NULL, /* unlink */ + NULL, /* mmap */ + NULL, /* complete */ + NULL, /* stat */ + NULL, /* mkdir */ + NULL /* rmdir */ +}; + +/* Have we been initialized? */ +static int initted = 0; + +int fs_socket_init() { + if(initted == 1) + return 0; + + LIST_INIT(&sockets); + + if(nmmgr_handler_add(&vh.nmmgr) < 0) + return -1; + + list_mutex = mutex_create(); + initted = 1; + + return 0; +} + +int fs_socket_shutdown() { + net_socket_t *c, *n; + + if(initted == 0) + return 0; + + mutex_lock(list_mutex); + c = LIST_FIRST(&sockets); + while(c != NULL) { + n = LIST_NEXT(c, sock_list); + + vh.close(c); + + free(c); + c = n; + } + + if(nmmgr_handler_remove(&vh.nmmgr) < 0) + return -1; + + mutex_destroy(list_mutex); + + initted = 0; + + return 0; +} + +int fs_socket_setflags(int sock, int flags) { + net_socket_t *hnd; + + hnd = (net_socket_t *) fs_get_handle(sock); + if(hnd == NULL) { + errno = EBADF; + return -1; + } + + return net_udp_setflags(hnd, flags); +} + +int socket(int domain, int type, int protocol) { + net_socket_t *sock; + file_t hnd; + + /* First, check the arguments for validity */ + if(domain != AF_INET) { + errno = EAFNOSUPPORT; + return -1; + } + + if(type != SOCK_DGRAM) { + errno = EPROTONOSUPPORT; + return -1; + } + + if(protocol != 0 && protocol != IPPROTO_UDP) { + errno = EPROTONOSUPPORT; + return -1; + } + + /* Allocate the socket structure, if we have the space */ + sock = (net_socket_t *) malloc(sizeof(net_socket_t)); + if(!sock) { + errno = ENOMEM; + return -1; + } + + /* Attempt to get a handle for this socket */ + hnd = fs_open_handle(&vh, sock); + if(hnd < 0) { + free(sock); + return -1; + } + + /* We only support UDP right now, so this is ok... */ + sock->protocol = IPPROTO_UDP; + + /* Initialize protocol-specific data */ + if(net_udp_socket(sock, domain, type, protocol) == -1) { + fs_close(hnd); + return -1; + } + + /* Add this socket into the list of sockets, and return */ + mutex_lock(list_mutex); + LIST_INSERT_HEAD(&sockets, sock, sock_list); + mutex_unlock(list_mutex); + + return hnd; +} + +int accept(int sock, struct sockaddr *address, socklen_t *address_len) { + net_socket_t *hnd; + + hnd = (net_socket_t *) fs_get_handle(sock); + if(hnd == NULL) { + errno = EBADF; + return -1; + } + + return net_udp_accept(hnd, address, address_len); +} + +int bind(int sock, const struct sockaddr *address, socklen_t address_len) { + net_socket_t *hnd; + + hnd = (net_socket_t *) fs_get_handle(sock); + if(hnd == NULL) { + errno = EBADF; + return -1; + } + + return net_udp_bind(hnd, address, address_len); +} + +int connect(int sock, const struct sockaddr *address, socklen_t address_len) { + net_socket_t *hnd; + + hnd = (net_socket_t *) fs_get_handle(sock); + if(hnd == NULL) { + errno = EBADF; + return -1; + } + + return net_udp_connect(hnd, address, address_len); +} + +int listen(int sock, int backlog) { + net_socket_t *hnd; + + hnd = (net_socket_t *) fs_get_handle(sock); + if(hnd == NULL) { + errno = EBADF; + return -1; + } + + return net_udp_listen(hnd, backlog); +} + +ssize_t recv(int sock, void *buffer, size_t length, int flags) { + net_socket_t *hnd; + + hnd = (net_socket_t *) fs_get_handle(sock); + if(hnd == NULL) { + errno = EBADF; + return -1; + } + + return net_udp_recv(hnd, buffer, length, flags); +} + +ssize_t recvfrom(int sock, void *buffer, size_t length, int flags, + struct sockaddr *address, socklen_t *address_len) { + net_socket_t *hnd; + + hnd = (net_socket_t *) fs_get_handle(sock); + if(hnd == NULL) { + errno = EBADF; + return -1; + } + + return net_udp_recvfrom(hnd, buffer, length, flags, address, + address_len); +} + +ssize_t send(int sock, const void *message, size_t length, int flags) { + net_socket_t *hnd; + + hnd = (net_socket_t *) fs_get_handle(sock); + if(hnd == NULL) { + errno = EBADF; + return -1; + } + + return net_udp_send(hnd, message, length, flags); +} + +ssize_t sendto(int sock, const void *message, size_t length, int flags, + const struct sockaddr *dest_addr, socklen_t dest_len) { + net_socket_t *hnd; + + hnd = (net_socket_t *) fs_get_handle(sock); + if(hnd == NULL) { + errno = EBADF; + return -1; + } + + return net_udp_sendto(hnd, message, length, flags, dest_addr, dest_len); +} + +int shutdown(int sock, int how) { + net_socket_t *hnd; + + hnd = (net_socket_t *) fs_get_handle(sock); + if(hnd == NULL) { + errno = EBADF; + return -1; + } + + return net_udp_shutdownsock(hnd, how); +} Modified: kos/kernel/net/net_core.c =================================================================== --- kos/kernel/net/net_core.c 2006-09-14 03:04:48 UTC (rev 354) +++ kos/kernel/net/net_core.c 2006-09-16 16:18:26 UTC (rev 355) @@ -10,6 +10,7 @@ #include <malloc.h> #include <stdio.h> #include <kos/net.h> +#include <kos/fs_socket.h> CVSID("$Id: net_core.c,v 1.5 2002/10/26 07:59:50 bardtx Exp $"); @@ -100,7 +101,7 @@ net_default_dev = n; - return olddev; + return olddev; } /* Device detect / init */ @@ -144,6 +145,11 @@ /* Initialize the ARP cache */ net_arp_init(); + /* Initialize the UDP system */ + net_udp_init(); + + fs_socket_init(); + return 0; } @@ -165,4 +171,9 @@ /* Shut down the ARP cache */ net_arp_shutdown(); + + /* Shut down the UDP system */ + net_udp_shutdown(); + + fs_socket_shutdown(); } Modified: kos/kernel/net/net_udp.c =================================================================== --- kos/kernel/net/net_udp.c 2006-09-14 03:04:48 UTC (rev 354) +++ kos/kernel/net/net_udp.c 2006-09-16 16:18:26 UTC (rev 355) @@ -1,295 +1,689 @@ /* KallistiOS ##version## kernel/net/net_udp.c - Copyright (C) 2005 Lawrence Sebald + Copyright (C) 2005, 2006 Lawrence Sebald */ #include <stdio.h> #include <string.h> #include <malloc.h> +#include <arpa/inet.h> #include <kos/net.h> #include <kos/mutex.h> +#include <kos/cond.h> #include <sys/queue.h> +#include <kos/dbgio.h> +#include <kos/fs_socket.h> +#include <sys/socket.h> +#include <errno.h> #include "net_ipv4.h" #include "net_udp.h" -typedef struct udp_pkt { - TAILQ_ENTRY(udp_pkt) pkt_queue; - udp_hdr_t hdr; - uint8 *data; - uint16 datasize; -} udp_pkt_t; +struct udp_pkt { + TAILQ_ENTRY(udp_pkt) pkt_queue; + struct sockaddr_in from; + uint8 *data; + uint16 datasize; +}; TAILQ_HEAD(udp_pkt_queue, udp_pkt); -typedef struct udp_sock { - LIST_ENTRY(udp_sock) sock_list; - int sock_num; - uint16 loc_port; - uint16 rem_port; - uint32 loc_addr; - uint32 rem_addr; - struct udp_pkt_queue packets; -} udp_sock_t; +struct udp_sock { + LIST_ENTRY(udp_sock) sock_list; + struct sockaddr_in local_addr; + struct sockaddr_in remote_addr; + int flags; + + struct udp_pkt_queue packets; +}; + LIST_HEAD(udp_sock_list, udp_sock); -static struct udp_sock_list net_udp_socks = LIST_HEAD_INITIALIZER(0); -static int cur_udp_sock = 0; -static uint8 udp_buf[1514]; +static struct udp_sock_list net_udp_sockets = LIST_HEAD_INITIALIZER(0); +static mutex_t *udp_mutex; +static condvar_t *udp_packets_ready; -int net_udp_sock_open(uint16 loc_port, uint32 loc_addr, uint16 rem_port, uint32 rem_addr) { - udp_sock_t *ns; +int net_udp_accept(net_socket_t *hnd, struct sockaddr *addr, + socklen_t *addr_len) { + errno = EOPNOTSUPP; + return -1; +} - LIST_FOREACH(ns, &net_udp_socks, sock_list) { - if(ns->loc_port == loc_port && ns->loc_addr == loc_addr && - ns->rem_port == rem_port && ns->rem_addr == rem_addr) { - dbglog(DBG_KDEBUG, "net_udp: Attempt to create already existing socket\n"); - return 0; - } - } +int net_udp_bind(net_socket_t *hnd, const struct sockaddr *addr, + socklen_t addr_len) { + struct udp_sock *udpsock, *iter; + struct sockaddr_in *realaddr; - ns = (udp_sock_t *)malloc(sizeof(udp_sock_t)); + /* Verify the parameters sent in first */ + if(addr == NULL) { + errno = EFAULT; + return -1; + } - ns->sock_num = ++cur_udp_sock; - ns->loc_port = loc_port; - ns->loc_addr = loc_addr; - ns->rem_port = rem_port; - ns->rem_addr = rem_addr; + if(addr->sa_family != AF_INET) { + errno = EAFNOSUPPORT; + return -1; + } - TAILQ_INIT(&ns->packets); - LIST_INSERT_HEAD(&net_udp_socks, ns, sock_list); + /* Get the sockaddr_in structure, rather than the sockaddr one */ + realaddr = (struct sockaddr_in *) addr; - return cur_udp_sock; + mutex_lock(udp_mutex); + + udpsock = (struct udp_sock *)hnd->data; + if(udpsock == NULL) { + mutex_unlock(udp_mutex); + errno = EBADF; + return -1; + } + + /* See if we requested a specific port or not */ + if(realaddr->sin_port != 0) { + /* Make sure we don't already have a socket bound to the + port specified */ + + LIST_FOREACH(iter, &net_udp_sockets, sock_list) { + if(iter->local_addr.sin_port == realaddr->sin_port) { + mutex_unlock(udp_mutex); + errno = EADDRINUSE; + return -1; + } + } + + udpsock->local_addr = *realaddr; + } + else { + uint16 port = 1024, tmp = 0; + + /* Grab the first unused port >= 1024. This is, unfortunately, O(n^2) */ + while(tmp != port) { + tmp = port; + + LIST_FOREACH(iter, &net_udp_sockets, sock_list) { + if(iter->local_addr.sin_port == port) { + ++port; + break; + } + } + } + + udpsock->local_addr = *realaddr; + udpsock->local_addr.sin_port = htons(port); + } + + mutex_unlock(udp_mutex); + + return 0; } -int net_udp_sock_close(int socknum) { - udp_sock_t *ns; - udp_pkt_t *pkt; +int net_udp_connect(net_socket_t *hnd, const struct sockaddr *addr, + socklen_t addr_len) { + struct udp_sock *udpsock; + struct sockaddr_in *realaddr; - LIST_FOREACH(ns, &net_udp_socks, sock_list) { - if(ns->sock_num == socknum) { - LIST_REMOVE(ns, sock_list); - TAILQ_FOREACH(pkt, &ns->packets, pkt_queue) { - TAILQ_REMOVE(&ns->packets, pkt, pkt_queue); - free(pkt->data); - free(pkt); - } - free(ns); + if(addr == NULL) { + errno = EFAULT; + return -1; + } - return 0; - } - } + if(addr->sa_family != AF_INET) { + errno = EAFNOSUPPORT; + return -1; + } - dbglog(DBG_KDEBUG, "net_udp: Attempt to close unopened socket"); - return -1; + mutex_lock(udp_mutex); + + udpsock = (struct udp_sock *)hnd->data; + if(udpsock == NULL) { + mutex_unlock(udp_mutex); + errno = EBADF; + return -1; + } + + if(udpsock->remote_addr.sin_addr.s_addr != INADDR_ANY) { + mutex_unlock(udp_mutex); + errno = EISCONN; + return -1; + } + + realaddr = (struct sockaddr_in *) addr; + if(realaddr->sin_port == 0 || realaddr->sin_addr.s_addr == INADDR_ANY) { + mutex_unlock(udp_mutex); + errno = EADDRNOTAVAIL; + return -1; + } + + udpsock->remote_addr.sin_addr.s_addr = realaddr->sin_addr.s_addr; + udpsock->remote_addr.sin_port = realaddr->sin_port; + + mutex_unlock(udp_mutex); + + return 0; } -int net_udp_recv(int sock, uint8 *buf, int size) { - udp_sock_t *ns; - udp_pkt_t *pkt; +int net_udp_listen(net_socket_t *hnd, int backlog) { + errno = EOPNOTSUPP; + return -1; +} - LIST_FOREACH(ns, &net_udp_socks, sock_list) { - if(ns->sock_num == sock) { - pkt = TAILQ_FIRST(&ns->packets); - if(pkt) { - if(size >= pkt->datasize) { - memcpy(buf, pkt->data, pkt->datasize); - TAILQ_REMOVE(&ns->packets, pkt, pkt_queue); - size = pkt->datasize; - free(pkt->data); - free(pkt); - return size; - } - else { - uint8 tbuf[pkt->datasize - size]; - memcpy(buf, pkt->data, size); - memcpy(tbuf, pkt->data + size, pkt->datasize - size); - free(pkt->data); - pkt->data = (uint8 *)malloc(pkt->datasize - size); - memcpy(pkt->data, tbuf, pkt->datasize - size); - pkt->datasize -= size; - return size; - } - } - else { - return 0; - } - } - } +ssize_t net_udp_recv(net_socket_t *hnd, void *buffer, size_t length, int flags) { + struct udp_sock *udpsock; + struct udp_pkt *pkt; - dbglog(DBG_KDEBUG, "net_udp: attempt to recv on unopened socket\n"); + mutex_lock(udp_mutex); - return -1; + udpsock = (struct udp_sock *)hnd->data; + if(udpsock == NULL) { + mutex_unlock(udp_mutex); + errno = EBADF; + return -1; + } + + if(udpsock->remote_addr.sin_addr.s_addr == INADDR_ANY || + udpsock->remote_addr.sin_port == 0) { + mutex_unlock(udp_mutex); + errno = ENOTCONN; + return -1; + } + + if(udpsock->flags & SHUT_RD) { + mutex_unlock(udp_mutex); + return 0; + } + + if(buffer == NULL) { + mutex_unlock(udp_mutex); + errno = EFAULT; + return -1; + } + + if(TAILQ_EMPTY(&udpsock->packets) && (udpsock->flags & O_NONBLOCK)) { + mutex_unlock(udp_mutex); + errno = EWOULDBLOCK; + return -1; + } + + if(TAILQ_EMPTY(&udpsock->packets)) { + cond_wait(udp_packets_ready, udp_mutex); + } + + pkt = TAILQ_FIRST(&udpsock->packets); + + if(pkt->datasize > length) { + memcpy(buffer, pkt->data, length); + } + else { + memcpy(buffer, pkt->data, pkt->datasize); + length = pkt->datasize; + } + + TAILQ_REMOVE(&udpsock->packets, pkt, pkt_queue); + free(pkt->data); + free(pkt); + + mutex_unlock(udp_mutex); + + return length; } -int net_udp_send(int sock, const uint8 *data, int size) { - udp_sock_t *ns; - - LIST_FOREACH(ns, &net_udp_socks, sock_list) { - if(ns->sock_num == sock) { - ip_pseudo_hdr_t *ps = (ip_pseudo_hdr_t *)udp_buf; - ip_hdr_t ip; - int internsize; +ssize_t net_udp_recvfrom(net_socket_t *hnd, void *buffer, size_t length, + int flags, struct sockaddr *addr, + socklen_t *addr_len) { + struct udp_sock *udpsock; + struct udp_pkt *pkt; - /* Fill in the UDP Header */ - ps->src_addr = ns->loc_addr; - ps->dst_addr = ns->rem_addr; - ps->zero = 0; - ps->proto = 17; - ps->length = net_ntohs(size + sizeof(udp_hdr_t)); - ps->src_port = ns->loc_port; - ps->dst_port = ns->rem_port; - ps->hdrlength = ps->length; - ps->checksum = 0; - memcpy(ps->data, data, size); + mutex_lock(udp_mutex); - if(size % 2) { - internsize = size + 1; - ps->data[internsize] = 0; - } - else - internsize = size; + udpsock = (struct udp_sock *)hnd->data; + if(udpsock == NULL) { + mutex_unlock(udp_mutex); + errno = EBADF; + return -1; + } - /* Compute the UDP Checksum */ - ps->checksum = net_ipv4_checksum((uint16 *)udp_buf, (internsize + sizeof(udp_hdr_t) + 12) / 2); + if(udpsock->flags & SHUT_RD) { + mutex_unlock(udp_mutex); + return 0; + } - /* Fill in the IP Header */ - ip.version_ihl = 0x45; /* 20 byte header, ipv4 */ - ip.tos = 0; - ip.length = net_ntohs(sizeof(udp_hdr_t) + size + 20); - ip.packet_id = 0; - ip.flags_frag_offs = net_ntohs(0x4000); - ip.ttl = 64; - ip.protocol = 17; /* UDP */ - ip.checksum = 0; - ip.src = ps->src_addr; - ip.dest = ps->dst_addr; + if(buffer == NULL || addr_len == NULL) { + mutex_unlock(udp_mutex); + errno = EFAULT; + return -1; + } - /* Compute the IP Checksum */ - ip.checksum = net_ipv4_checksum((uint16*)&ip, sizeof(ip_hdr_t) / 2); + if(TAILQ_EMPTY(&udpsock->packets) && (udpsock->flags & O_NONBLOCK)) { + mutex_unlock(udp_mutex); + errno = EWOULDBLOCK; + return -1; + } - net_ipv4_send_packet(net_default_dev, &ip, (uint8 *)(udp_buf + 12), sizeof(udp_hdr_t) + size); + while(TAILQ_EMPTY(&udpsock->packets)) { + cond_wait(udp_packets_ready, udp_mutex); + } - return size; - } - } + pkt = TAILQ_FIRST(&udpsock->packets); - dbglog(DBG_KDEBUG, "net_udp: attempt to send on unopened socket\n"); - - return -1; + if(pkt->datasize > length) { + memcpy(buffer, pkt->data, length); + } + else { + memcpy(buffer, pkt->data, pkt->datasize); + length = pkt->datasize; + } + + if(addr != NULL) { + struct sockaddr_in realaddr; + + realaddr.sin_family = AF_INET; + realaddr.sin_addr.s_addr = pkt->from.sin_addr.s_addr; + realaddr.sin_port = pkt->from.sin_port; + memset(realaddr.sin_zero, 0, 8); + + if(*addr_len < sizeof(struct sockaddr_in)) { + memcpy(addr, &realaddr, *addr_len); + } + else { + memcpy(addr, &realaddr, sizeof(struct sockaddr_in)); + *addr_len = sizeof(struct sockaddr_in); + } + } + + TAILQ_REMOVE(&udpsock->packets, pkt, pkt_queue); + free(pkt->data); + free(pkt); + + mutex_unlock(udp_mutex); + + return length; } -int net_udp_input(netif_t *src, eth_hdr_t *eh, ip_hdr_t *ip, const uint8 *data, int size) { - ip_pseudo_hdr_t *ps = (ip_pseudo_hdr_t*)udp_buf; - uint16 i; - udp_sock_t *sock; - udp_pkt_t *pkt; +ssize_t net_udp_send(net_socket_t *hnd, const void *message, size_t length, + int flags) { + struct udp_sock *udpsock; - ps->src_addr = ip->src; - ps->dst_addr = ip->dest; - ps->zero = 0; - ps->proto = ip->protocol; - memcpy(&ps->src_port, data, size); - ps->length = net_ntohs(size); + mutex_lock(udp_mutex); - if(size % 2) { - ps->data[size - sizeof(udp_hdr_t)] = 0; - ++size; - } + udpsock = (struct udp_sock *)hnd->data; + if(udpsock == NULL) { + mutex_unlock(udp_mutex); + errno = EBADF; + return -1; + } - i = ps->checksum; - ps->checksum = 0; - ps->checksum = net_ipv4_checksum((uint16 *)udp_buf, (size + 12) / 2); + if(udpsock->flags & SHUT_WR) { + mutex_unlock(udp_mutex); + errno = EPIPE; + return -1; + } -#ifdef DEBUG_UDP - printf("UDP Header Dump:\n"); - printf(" Pseudo-Header:\n"); - printf("src_addr = 0x%08x\n", ps->src_addr); - printf("dst_addr = 0x%08x\n", ps->dst_addr); - printf("zero = 0x%02x\n", ps->zero); - printf("proto = 0x%02x\n", ps->proto); - printf("length = 0x%04x\n", ps->length); - printf("src_port = 0x%04x\n", ps->src_port); - printf("dst_port = 0x%04x\n", ps->dst_port); - printf("hdrlength = 0x%04x\n", ps->hdrlength); - printf("checksum = 0x%04x\n", ps->checksum); -#endif + if(udpsock->remote_addr.sin_addr.s_addr == INADDR_ANY || + udpsock->remote_addr.sin_port == 0) { + mutex_unlock(udp_mutex); + errno = ENOTCONN; + return -1; + } - if(i != ps->checksum) { - dbglog(DBG_KDEBUG, "net_udp: discarding UDP packet with invalid checksum\n"); - dbglog(DBG_KDEBUG, "net_udp: was %x, expected %x\n", i, ps->checksum); - return -1; - } + if(message == NULL) { + mutex_unlock(udp_mutex); + errno = EFAULT; + return -1; + } - LIST_FOREACH(sock, &net_udp_socks, sock_list) { - if(sock->loc_port == ps->dst_port && sock->loc_addr == ps->dst_addr && - ((sock->rem_port == ps->src_port && sock->rem_addr == ps->src_addr) || - (sock->rem_port == 0 && sock->rem_addr == 0))) { - sock->rem_port = ps->src_port; - sock->rem_addr = ps->src_addr; - pkt = (udp_pkt_t *) malloc(sizeof(udp_pkt_t)); - pkt->datasize = size - sizeof(udp_hdr_t); - pkt->data = (uint8 *) malloc(pkt->datasize); - memcpy(&pkt->hdr, &ps->src_port, sizeof(udp_hdr_t)); - memcpy(pkt->data, ps->data, pkt->datasize); - TAILQ_INSERT_TAIL(&sock->packets, pkt, pkt_queue); - return 0; - } - } + if(udpsock->local_addr.sin_port == 0) { + uint16 port = 1024, tmp = 0; + struct udp_sock *iter; - dbglog(DBG_KDEBUG, "net_udp: discarding UDP packet for unopened socket\n"); + /* Grab the first unused port >= 1024. This is, unfortunately, O(n^2) */ + while(tmp != port) { + tmp = port; - return 0; + LIST_FOREACH(iter, &net_udp_sockets, sock_list) { + if(iter->local_addr.sin_port == port) { + ++port; + break; + } + } + } + + udpsock->local_addr.sin_port = htons(port); + } + + mutex_unlock(udp_mutex); + + return net_udp_send_raw(NULL, udpsock->local_addr.sin_addr.s_addr, + udpsock->local_addr.sin_port, + udpsock->remote_addr.sin_addr.s_addr, + udpsock->remote_addr.sin_port, (uint8 *) message, + length); } -int net_udp_send_raw(netif_t *net, uint16 src_port, uint16 dst_port, const uint8 ipa[4], - const uint8 *data, int size) { - ip_pseudo_hdr_t *ps = (ip_pseudo_hdr_t *)udp_buf; - ip_hdr_t ip; - int internsize; +ssize_t net_udp_sendto(net_socket_t *hnd, const void *message, size_t length, + int flags, const struct sockaddr *addr, + socklen_t addr_len) { + struct udp_sock *udpsock; + struct sockaddr_in *realaddr; - /* Fill in the UDP Header */ - if(net == NULL) /* Sending from the loopback device? */ - ps->src_addr = 0x0100007f; /* 127.0.0.1 */ - else - ps->src_addr = net_ntohl(net_ipv4_address(net->ip_addr)); - ps->dst_addr = net_ntohl(net_ipv4_address(ipa)); - ps->zero = 0; - ps->proto = 17; - ps->length = net_ntohs(size + sizeof(udp_hdr_t)); - ps->src_port = net_ntohs(src_port); - ps->dst_port = net_ntohs(dst_port); - ps->hdrlength = ps->length; - ps->checksum = 0; - memcpy(ps->data, data, size); + mutex_lock(udp_mutex); - if(size % 2) { - internsize = size + 1; - ps->data[internsize] = 0; - } - else - internsize = size; - + udpsock = (struct udp_sock *)hnd->data; + if(udpsock == NULL) { + mutex_unlock(udp_mutex); + errno = EBADF; + return -1; + } - /* Compute the UDP Checksum */ - ps->checksum = net_ipv4_checksum((uint16 *)udp_buf, (internsize + sizeof(udp_hdr_t) + 12) / 2); + if(udpsock->flags & SHUT_WR) { + mutex_unlock(udp_mutex); + errno = EPIPE; + return -1; + } - /* Fill in the IP Header */ - ip.version_ihl = 0x45; /* 20 byte header, ipv4 */ - ip.tos = 0; - ip.length = net_ntohs(sizeof(udp_hdr_t) + size + 20); - ip.packet_id = 0; - ip.flags_frag_offs = net_ntohs(0x4000); - ip.ttl = 64; - ip.protocol = 17; /* UDP */ - ip.checksum = 0; - ip.src = ps->src_addr; - ip.dest = ps->dst_addr; + if(message == NULL || addr == NULL) { + mutex_unlock(udp_mutex); + errno = EFAULT; + return -1; + } - /* Compute the IP Checksum */ - ip.checksum = net_ipv4_checksum((uint16*)&ip, sizeof(ip_hdr_t) / 2); + realaddr = (struct sockaddr_in *) addr; - return net_ipv4_send_packet(net, &ip, (uint8 *)(udp_buf + 12), sizeof(udp_hdr_t) + size); + if(udpsock->local_addr.sin_port == 0) { + uint16 port = 1024, tmp = 0; + struct udp_sock *iter; + + /* Grab the first unused port >= 1024. This is, unfortunately, O(n^2) */ + while(tmp != port) { + tmp = port; + + LIST_FOREACH(iter, &net_udp_sockets, sock_list) { + if(iter->local_addr.sin_port == port) { + ++port; + break; + } + } + } + + udpsock->local_addr.sin_port = htons(port); + } + + mutex_unlock(udp_mutex); + + return net_udp_send_raw(NULL, udpsock->local_addr.sin_addr.s_addr, + udpsock->local_addr.sin_port, + realaddr->sin_addr.s_addr, realaddr->sin_port, + (uint8 *) message, length); } + +int net_udp_shutdownsock(net_socket_t *hnd, int how) { + struct udp_sock *udpsock; + + mutex_lock(udp_mutex); + + udpsock = (struct udp_sock *)hnd->data; + if(udpsock == NULL) { + mutex_unlock(udp_mutex); + errno = EBADF; + return -1; + } + + if(how & 0xFFFFFFFC) { + mutex_unlock(udp_mutex); + errno = EINVAL; + } + + udpsock->flags |= how; + + mutex_unlock(udp_mutex); + + return 0; +} + +int net_udp_socket(net_socket_t *hnd, int domain, int type, int protocol) { + struct udp_sock *udpsock; + + udpsock = (struct udp_sock *) malloc(sizeof(struct udp_sock)); + if(udpsock == NULL) { + errno = ENOMEM; + return -1; + } + + udpsock->remote_addr.sin_family = AF_INET; + udpsock->remote_addr.sin_addr.s_addr = INADDR_ANY; + udpsock->remote_addr.sin_port = 0; + + udpsock->local_addr.sin_family = AF_INET; + udpsock->local_addr.sin_addr.s_addr = INADDR_ANY; + udpsock->local_addr.sin_port = 0; + + udpsock->flags = 0; + + TAILQ_INIT(&udpsock->packets); + + mutex_lock(udp_mutex); + LIST_INSERT_HEAD(&net_udp_sockets, udpsock, sock_list); + mutex_unlock(udp_mutex); + + hnd->data = udpsock; + + return 0; +} + +void net_udp_close(net_socket_t *hnd) { + struct udp_sock *udpsock; + struct udp_pkt *pkt; + + mutex_lock(udp_mutex); + + udpsock = (struct udp_sock *)hnd->data; + if(udpsock == NULL) { + mutex_unlock(udp_mutex); + errno = EBADF; + } + + TAILQ_FOREACH(pkt, &udpsock->packets, pkt_queue) { + free(pkt->data); + TAILQ_REMOVE(&udpsock->packets, pkt, pkt_queue); + free(pkt); + } + + LIST_REMOVE(udpsock, sock_list); + + free(udpsock); + mutex_unlock(udp_mutex); +} + +int net_udp_setflags(net_socket_t *hnd, int flags) { + struct udp_sock *udpsock; + + mutex_lock(udp_mutex); + + udpsock = (struct udp_sock *) hnd->data; + if(udpsock == NULL) { + mutex_unlock(udp_mutex); + errno = EBADF; + return -1; + } + + if(flags & (~O_NONBLOCK)) { + mutex_unlock(udp_mutex); + errno = EINVAL; + return -1; + } + + udpsock->flags |= flags; + mutex_unlock(udp_mutex); + + return 0; +} + +int net_udp_input(netif_t *src, eth_hdr_t *eh, ip_hdr_t *ip, const uint8 *data, + int size) { + uint8 buf[size + 13]; + ip_pseudo_hdr_t *ps = (ip_pseudo_hdr_t *)buf; + uint16 checksum; + struct udp_sock *sock; + struct udp_pkt *pkt; + + ps->src_addr = ip->src; + ps->dst_addr = ip->dest; + ps->zero = 0; + ps->proto = ip->protocol; + memcpy(&ps->src_port, data, size); + ps->length = htons(size); + + /* check this.... */ + if(size & 0x01) { + ps->data[size - sizeof(udp_hdr_t)] = 0; + checksum = ps->checksum; + ps->checksum = 0; + ps->checksum = net_ipv4_checksum((uint16 *) buf, (size + 13) >> 1); + } + else { + checksum = ps->checksum; + ps->checksum = 0; + ps->checksum = net_ipv4_checksum((uint16 *) buf, (size + 12) >> 1); + } + + if(checksum != ps->checksum) { + dbglog(DBG_KDEBUG, "net_udp: discarding UDP packet with invalid " + "checksum\n" + " calculated 0x%04X, sent 0x%04X\n", + ps->checksum, checksum); + return -1; + } + + if(mutex_trylock(udp_mutex)) { + dbglog(DBG_KDEBUG, "net_udp: discarding packet due to locked mutex\n"); + return -1; + } + + LIST_FOREACH(sock, &net_udp_sockets, sock_list) { + /* See if we have a socket matching the description provided */ + if(sock->local_addr.sin_port == ps->dst_port && + ((sock->remote_addr.sin_port == ps->src_port && + sock->remote_addr.sin_addr.s_addr == ps->src_addr) || + (sock->remote_addr.sin_port == 0 && + sock->remote_addr.sin_addr.s_addr == INADDR_ANY))) { + pkt = (struct udp_pkt *) malloc(sizeof(struct udp_pkt)); + + pkt->datasize = size - sizeof(udp_hdr_t); + pkt->data = (uint8 *) malloc(pkt->datasize); + + pkt->from.sin_family = AF_INET; + pkt->from.sin_addr.s_addr = ip->src; + pkt->from.sin_port = ps->src_port; + + memcpy(pkt->data, ps->data, pkt->datasize); + + TAILQ_INSERT_TAIL(&sock->packets, pkt, pkt_queue); + + cond_broadcast(udp_packets_ready); + + mutex_unlock(udp_mutex); + + return 0; + } + } + + dbglog(DBG_KDEBUG, "net_udp: Discarding packet for non-opened socket\n"); + mutex_unlock(udp_mutex); + + return 0; +} + +int net_udp_send_raw(netif_t *net, uint32 src_ip, uint16 src_port, + uint32 dst_ip, uint16 dst_port, const uint8 *data, + int size) { + uint8 buf[size + 13 + sizeof(udp_hdr_t)]; + ip_pseudo_hdr_t *ps = (ip_pseudo_hdr_t *) buf; + ip_hdr_t ip; + + if(net == NULL && net_default_dev == NULL) { + errno = ENETDOWN; + return -1; + } + + if(src_ip == INADDR_ANY) { + if(net == NULL && net_default_dev != NULL) { + ps->src_addr = htonl(net_ipv4_address(net_default_dev->ip_addr)); + } + else if(net != NULL) { + ps->src_addr = htonl(net_ipv4_address(net->ip_addr)); + } + } + else { + ps->src_addr = src_ip; + } + + buf[size + 12 + sizeof(udp_hdr_t)] = 0; + memcpy(ps->data, data, size); + size += sizeof(udp_hdr_t); + + ps->dst_addr = dst_ip; + ps->zero = 0; + ps->proto = 17; + ps->length = htons(size); + ps->src_port = src_port; + ps->dst_port = dst_port; + ps->hdrlength = ps->length; + ps->checksum = 0; + + /* Compute the UDP checksum */ + if(size & 0x01) { + ps->checksum = net_ipv4_checksum((uint16 *) buf, + (size + 13) >> 1); + } + else { + ps->checksum = net_ipv4_checksum((uint16 *) buf, + (size + 12) >> 1); + } + + /* Fill in the IPv4 Header */ + ip.version_ihl = 0x45; + ip.tos = 0; + ip.length = htons(size + 20); + ip.packet_id = 0; + ip.flags_frag_offs = htons(0x4000); + ip.ttl = 64; + ip.protocol = 17; + ip.checksum = 0; + ip.src = ps->src_addr; + ip.dest = ps->dst_addr; + + /* Compute the IPv4 checksum */ + ip.checksum = net_ipv4_checksum((uint16 *) &ip, sizeof(ip_hdr_t) >> 1); + + /* send it away.... */ + if(net_ipv4_send_packet(net, &ip, buf + 12, size)) { + /* If net_ipv4_send_packet() returns anything but 0, its an error, + errno should be set already from it. */ + return -1; + } + else { + return size - sizeof(udp_hdr_t); + } +} + +int net_udp_init() { + udp_mutex = mutex_create(); + + if(udp_mutex == NULL) { + return -1; + } + + udp_packets_ready = cond_create(); + + if(udp_packets_ready == NULL) { + mutex_destroy(udp_mutex); + return -1; + } + + return 0; +} + +void net_udp_shutdown() { + mutex_destroy(udp_mutex); + cond_destroy(udp_packets_ready); +} Modified: kos/kernel/net/net_udp.h =================================================================== --- kos/kernel/net/net_udp.h 2006-09-14 03:04:48 UTC (rev 354) +++ kos/kernel/net/net_udp.h 2006-09-16 16:18:26 UTC (rev 355) @@ -1,22 +1,52 @@ /* KallistiOS ##version## kernel/net/net_udp.h - Copyright (C) 2005 Lawrence Sebald + Copyright (C) 2005, 2006 Lawrence Sebald */ #ifndef __LOCAL_NET_UDP_H #define __LOCAL_NET_UDP_H +#include <sys/socket.h> +#include <kos/fs_socket.h> + #define packed __attribute__((packed)) typedef struct { - uint16 src_port packed; - uint16 dst_port packed; - uint16 length packed; - uint16 checksum packed; + uint16 src_port packed; + uint16 dst_port packed; + uint16 length packed; + uint16 checksum packed; } udp_hdr_t; #undef packed -int net_udp_input(netif_t *src, eth_hdr_t *eh, ip_hdr_t *ih, const uint8 *data, int size); +int net_udp_input(netif_t *src, eth_hdr_t *eh, ip_hdr_t *ih, const uint8 *data, + int size); +int net_udp_send_raw(netif_t *net, uint32 src_ip, uint16 src_port, + uint32 dst_ip, uint16 dst_port, const uint8 *data, + int size); +/* Sockets */ +int net_udp_accept(net_socket_t *hnd, struct sockaddr *addr, + socklen_t *addr_len); +int net_udp_bind(net_socket_t *hnd, const struct sockaddr *addr, + socklen_t addr_len); +int net_udp_connect(net_socket_t *hnd, const struct sockaddr *addr, + socklen_t addr_len); +int net_udp_listen(net_socket_t *hnd, int backlog); +ssize_t net_udp_recv(net_socket_t *hnd, void *buffer, size_t length, int flags); +ssize_t net_udp_recvfrom(net_socket_t *hnd, void *buffer, size_t length, + int flags, struct sockaddr *addr, socklen_t *addr_len); +ssize_t net_udp_send(net_socket_t *hnd, const void *message, size_t length, + int flags); +ssize_t net_udp_sendto(net_socket_t *hnd, const void *message, size_t length, + int flags, const struct sockaddr *addr, + socklen_t addr_len); +int net_udp_shutdownsock(net_socket_t *hnd, int how); +int net_udp_socket(net_socket_t *hnd, int domain, int type, int protocol); + +void net_udp_close(net_socket_t *hnd); + +int net_udp_setflags(net_socket_t *hnd, int flags); + #endif /* __LOCAL_NET_UDP_H */ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |