|
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.
|