From c00d2cc4f240e22ed52f9aa5f42e8752140c6560 Mon Sep 17 00:00:00 2001 From: Tomas 'ZeXx86' Jedrzejek Date: Fri, 12 Mar 2010 18:32:23 +0100 Subject: [PATCH] New developer version 0.6.8; added select () function; added demonstrating example of network server with select () - could be used as chat server with netcat clients; changed SYSV_GETCH macro in syscall.h and _libc.h to another address, replaced by ERRNO_ADDRESS at 0x9000; small cleanups in some parts of code --- apps/mserver/Makefile | 42 ++++++ apps/mserver/README | 8 ++ apps/mserver/link.ld | 48 +++++++ apps/mserver/main.c | 193 ++++++++++++++++++++++++++ apps/mserver/make_img.sh | 25 ++++ apps/mserver/start.s | 55 ++++++++ build.sh | 2 +- kernel/Makefile | 7 +- kernel/arch/i386/syscall.c | 18 +++ kernel/core/commands.c | 17 +-- kernel/core/net/socket.c | 72 +++++++++- kernel/core/net/tcp.c | 40 ++++++ kernel/core/net/tcp6.c | 40 ++++++ kernel/core/net/udp.c | 24 ++++ kernel/core/net/udp6.c | 25 ++++ kernel/include/errno.h | 2 +- kernel/include/net/socket.h | 2 + {libc/include/sys => kernel/include}/select.h | 10 +- kernel/include/syscall.h | 3 +- kernel/include/time.h | 6 + kernel/lib/Makefile | 3 +- kernel/lib/sys/select.c | 164 ++++++++++++++++++++++ libc/include/_libc.h | 5 +- libc/include/sys/select.h | 10 +- libc/sys/select.c | 91 +++++++++--- 25 files changed, 856 insertions(+), 56 deletions(-) create mode 100644 apps/mserver/Makefile create mode 100644 apps/mserver/README create mode 100644 apps/mserver/link.ld create mode 100644 apps/mserver/main.c create mode 100755 apps/mserver/make_img.sh create mode 100644 apps/mserver/start.s copy {libc/include/sys => kernel/include}/select.h (90%) create mode 100644 kernel/lib/sys/select.c diff --git a/apps/mserver/Makefile b/apps/mserver/Makefile new file mode 100644 index 0000000..807548d --- /dev/null +++ b/apps/mserver/Makefile @@ -0,0 +1,42 @@ +.SUFFIXES: .asm + +# defines +MAKEFILE=Makefile +MAKEDEP=$(MAKEFILE) +NASM =nasm -f elf +GLIBC =../../libc +LSCRIPT =./link.ld +LFLAGS =-g -T$(LSCRIPT) +INCDIR =$(GLIBC)/include +CC =gcc -m32 -g -O2 -Wall -W -c -nostdinc -fno-builtin -fno-stack-protector -I$(INCDIR) +#-Wall -W +LD =ld -m elf_i386 -s -nostdlib +LIBC =$(GLIBC)/libc.a +OBJS =start.o main.o + +# targets +all: mserver + +install: mserver + mkdir mnt + mount /dev/fd0 mnt + cp -f mserver ./mnt/mserver + umount mnt + rmdir mnt + +iso: mserver + cp mserver ../../iso/ + +clean: + rm -f *.o mserver mserver.img $(OBJS) + +# implicit rules +.s.o: + $(NASM) -o$@ $< + +.c.o: + $(CC) -c -o$@ $< + +# explicit rules +mserver: $(OBJS) $(LIBC) $(MAKEDEP) + $(LD) $(LFLAGS) -o$@ $(OBJS) $(LIBC) \ No newline at end of file diff --git a/apps/mserver/README b/apps/mserver/README new file mode 100644 index 0000000..75da39f --- /dev/null +++ b/apps/mserver/README @@ -0,0 +1,8 @@ +Description: Example code for demonstrating a select () function as network server +Info: You can use it as e.g. chat server with netcat clients + +License: GNU/GPL3 +Author: ZeXx86 + +Syntax: +exec mserver
\ No newline at end of file diff --git a/apps/mserver/link.ld b/apps/mserver/link.ld new file mode 100644 index 0000000..eac4bff --- /dev/null +++ b/apps/mserver/link.ld @@ -0,0 +1,48 @@ +OUTPUT_FORMAT("elf32-i386") +ENTRY(entry) +phys = 0x800000; + +SECTIONS +{ + .text phys + 0x1000 : AT (phys) + { + code = .; _code = .; __code = .; + *(.text) + . = ALIGN(64); + } + .data : AT(phys + (data - code)) + { + data = .; _data = .; __data = .; + *(.data) + . = ALIGN(64); + } + .rodata : AT(phys + (rodata - code)) + { + rodata = .; _rodata = .; __rodata = .; + *(.rodata) + *(.rodata.*) + . = ALIGN(64); + } + .bss : AT(phys + (bss - code)) + { + bss = .; _bss = .; __bss = .; + *(.bss) + *(COMMON) + . = ALIGN(64); + } + .comment : AT(phys + (comment - code)) + { + comment = .; _comment = .; __comment = .; + *(.comment) + *(.comment.*) + . = ALIGN(64); + } + .shstrtab : AT(phys + (shstrtab - code)) + { + shstrtab = .; _shstrtab = .; __shstrtab = .; + *(.shstrtab) + *(.shstrtab.*) + . = ALIGN(64); + } + end = .; _end = .; +} diff --git a/apps/mserver/main.c b/apps/mserver/main.c new file mode 100644 index 0000000..262dbfb --- /dev/null +++ b/apps/mserver/main.c @@ -0,0 +1,193 @@ +/* + * ZeX/OS + * Copyright (C) 2010 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int fd; +fd_set myset; +struct sockaddr_in sockname; + +/* Client structure */ +typedef struct client_context { + struct client_context *next, *prev; + + int fd; +} client_t; + +client_t client_list; + +int mserver_bind (int port) +{ + if ((fd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { + printf ("> cant create socket\n"); + return -1; + } + + sockname.sin_family = AF_INET; + sockname.sin_port = htons (port); + + // Create listen socket + if (bind (fd, (struct sockaddr *) &sockname, sizeof (sockname)) == -1) { + printf ("bind () - port is used\n"); + return -1; + } + + // Create queue for accept + if (listen (fd, 10) == -1) { + printf ("ERROR -> listen () == -1\n"); + return -1; + } + + client_list.next = &client_list; + client_list.prev = &client_list; + + return 0; +} + +int mserver_newclient () +{ + int client; + struct sockaddr_in clientInfo; + socklen_t addrlen = sizeof (clientInfo); + + if (FD_ISSET (fd, &myset)) { + printf ("> new client connected\n"); + + client = accept (fd, (struct sockaddr *) &clientInfo, &addrlen); + + if (client > 0) { + // alloc and init context + client_t *ctx = (client_t *) malloc (sizeof (client_t)); + + if (!ctx) + return 0; + + ctx->fd = client; + + ctx->next = &client_list; + ctx->prev = client_list.prev; + ctx->prev->next = ctx; + ctx->next->prev = ctx; + + return 1; + } + } + + return 0; +} + +int mserver_sendtoall (client_t *me, char *buf, unsigned len) +{ + if (!me) + return -1; + + client_t *c; + for (c = client_list.next; c != &client_list; c = c->next) + if (c != me) + send (c->fd, buf, len, 0); + + return 0; +} + +int mserver_handle (client_t *c) +{ + if (!FD_ISSET (c->fd, &myset)) + return 0; + + char str[80]; + int r = recv (c->fd, str, 80, 0); + + if (r > 0) { + str[r] = '\0'; + + printf ("data: %d: %s", c->fd, str); + mserver_sendtoall (c, str, r); + } else { + printf ("client %d is disconnected\n", c->fd); + /* disconnect socket */ + close (c->fd); + + /* delete client_t * struct from list */ + c->next->prev = c->prev; + c->prev->next = c->next; + + free (c); + return -1; + } + + return 0; +} + +int mserver_loop () +{ + struct timeval tv; + + FD_ZERO (&myset); + FD_SET (fd, &myset); + + client_t *c; + for (c = client_list.next; c != &client_list; c = c->next) + FD_SET (c->fd, &myset); + + tv.tv_sec = 1; + tv.tv_usec = 0; + + int ret = select (0, &myset, NULL, NULL, &tv); + + if (ret == -1) { + printf ("select error\n"); + return -1; + } else if (ret == 0) { + printf ("select timeout\n"); + return -1; + } + + /* check for incoming connections */ + if (mserver_newclient ()) + return 0; + + for (c = client_list.next; c != &client_list; c = c->next) { + if (mserver_handle (c) == -1) + break; + } + + return 0; +} + +int main (int argc, char **argv) +{ + int ret = mserver_bind (1234); + + if (ret == -1) + return -1; + + for (;; schedule ()) + mserver_loop (); + + return 0; +} diff --git a/apps/mserver/make_img.sh b/apps/mserver/make_img.sh new file mode 100755 index 0000000..027708b --- /dev/null +++ b/apps/mserver/make_img.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +if [ "$USER" = "root" ] ; then + +# Folder name of your application +APPNAME="mserver" + +# Compile source +make + +# Optimized for 1,4MB floppy +dd if=/dev/zero of=$APPNAME.img bs=1440k count=1 +mkfs.vfat $APPNAME.img + +mkdir floppy +mount -oloop $APPNAME.img floppy +cp $APPNAME floppy +umount floppy +rmdir floppy + +else + +echo "Please start this script as root - it is needed for mount program" + +fi \ No newline at end of file diff --git a/apps/mserver/start.s b/apps/mserver/start.s new file mode 100644 index 0000000..bd9cc05 --- /dev/null +++ b/apps/mserver/start.s @@ -0,0 +1,55 @@ +; ZeX/OS +; Copyright (C) 2007 Tomas 'ZeXx86' Jedrzejek (zexx86@gmail.com) +; Copyright (C) 2008 Tomas 'ZeXx86' Jedrzejek (zexx86@gmail.com) +; +; This program is free software: you can redistribute it and/or modify +; it under the terms of the GNU General Public License as published by +; the Free Software Foundation, either version 3 of the License, or +; (at your option) any later version. +; +; This program is distributed in the hope that it will be useful, +; but WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; GNU General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program. If not, see . + + +; This is the kernel's entry point. We could either call main here, +; or we can use this to setup the stack or other nice stuff, like +; perhaps setting up the GDT and segments. Please note that interrupts +; are disabled at this point: More on interrupts later! + +[SECTION .text] +[BITS 32] + +extern main +global entry + +entry: + ; first we get arguments + mov eax, 26 + mov ecx, 0 + int 0x80 + + push eax ; argv + + ; lets get count of arguments + mov eax, 26 + mov ecx, 1 + int 0x80 + + mov ebx, eax + push ebx ; argc + + call main ; call our program + + pop ebx + pop eax + + ; proc exit + mov eax, 1 + int 0x80 + + ret \ No newline at end of file diff --git a/build.sh b/build.sh index 2918a2d..816440f 100755 --- a/build.sh +++ b/build.sh @@ -1,6 +1,6 @@ #!/bin/bash -VERSION="0.6.7" +VERSION="0.6.8" ARCHITECTURE="i386" APPPREFIX="/usr/bin" diff --git a/kernel/Makefile b/kernel/Makefile index b88fa35..78a01b4 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -1,7 +1,8 @@ # ZeX/OS makefile # Copyright (C) 2007 Alex Smith -# 2008 Tomas 'ZeXx86' Jedrzejek (zexx86@gmail.com) -# 2009 Tomas 'ZeXx86' Jedrzejek (zexx86@gmail.com) +# 2008 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org) +# 2009 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org) +# 2010 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org) # # This program is free software; you can redistribute it and/or modify # it under the terms of version 2 of the GNU General Public License @@ -21,7 +22,7 @@ ZEXOS_VERSION = 0 ZEXOS_PATCHLEVEL = 6 -ZEXOS_SUBLEVEL = 7 +ZEXOS_SUBLEVEL = 8 ZEXOS_EXTRAVERSION = ZEXOS_CODENAME = diff --git a/kernel/arch/i386/syscall.c b/kernel/arch/i386/syscall.c index 3bf7693..7afe1de 100644 --- a/kernel/arch/i386/syscall.c +++ b/kernel/arch/i386/syscall.c @@ -37,6 +37,7 @@ #include #include #include +#include #include void sys_exit (struct regs *r) @@ -842,6 +843,21 @@ void sys_rename (struct regs *r) r->eax = (int) &ret; } +void sys_select (struct regs *r) +{ + struct select_t { + int nfds; + fd_set *readfds; + fd_set *writefds; + fd_set *exceptfds; + struct timeval *timeout; + }; + + struct select_t *s = (struct select_t *) r->ebx; + + *SYSV_SELECT = select (s->nfds, s->readfds, s->writefds, s->exceptfds, s->timeout); +} + void syscall_handler (struct regs *r) { switch (r->eax) { @@ -971,5 +987,7 @@ void syscall_handler (struct regs *r) return sys_remove (r); case 63: return sys_rename (r); + case 64: + return sys_select (r); } } diff --git a/kernel/core/commands.c b/kernel/core/commands.c index 890891c..169df73 100644 --- a/kernel/core/commands.c +++ b/kernel/core/commands.c @@ -891,9 +891,6 @@ void thread_test () } } -extern unsigned start; -extern unsigned end; -extern bool ide_acthandler (unsigned act, partition_t *p, char *block, char *more, int n); unsigned command_test (char *command, unsigned len) { partition_t *p = partition_find ("/dev/hda0"); @@ -907,8 +904,7 @@ unsigned command_test (char *command, unsigned len) return 1; } -extern char *vgafb; -extern char *vgadb; + unsigned command_test2 (char *command, unsigned len) { partition_t *p = partition_find ("/dev/cdc0"); @@ -1307,9 +1303,10 @@ unsigned command_dhcpcl (char *command, unsigned len) printf ("dhcpcl -> server didn't understand\n"); break; } - } else { + } else printf ("dhcpcl -> interface %s successfully configured\n", cmd_buf); - } + + return 0; } unsigned command_tunconfig (char *command, unsigned len) @@ -1844,7 +1841,7 @@ unsigned command_netcp (char *command, unsigned len) return 1; } - +extern bool ide_acthandler (unsigned act, partition_t *p, char *block, char *more, int n); unsigned command_znfscl (char *command, unsigned len) { #ifdef ARCH_i386 @@ -2136,9 +2133,9 @@ unsigned int init_commands () command_register ("free", "Display amount of free and used memory", &command_free, 0); command_register ("top", "Stats of cpu usage", &command_top, 0); command_register ("date", "Show current date and time", &command_date, 0); - command_register ("xmastime", "play noels on pc-speaker", &command_spk, 0); + //command_register ("xmastime", "play noels on pc-speaker", &command_spk, 0); command_register ("test", "Some test", &command_test, 0); - command_register ("test2", "Some test", &command_test2, 0); + //command_register ("test2", "Some test", &command_test2, 0); //command_register ("test3", "Some test", &command_test3, 0); //command_register ("testd", "Some test", &command_test4, 0); //command_register ("vesa", "Some test", &command_vesa, 0); diff --git a/kernel/core/net/socket.c b/kernel/core/net/socket.c index 9cddf47..8c1316d 100644 --- a/kernel/core/net/socket.c +++ b/kernel/core/net/socket.c @@ -3,6 +3,7 @@ * Copyright (C) 2007 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org) * Copyright (C) 2008 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org) * Copyright (C) 2009 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org) + * Copyright (C) 2010 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -64,37 +66,47 @@ int socket (int family, int type, int protocol) } sock->fd = fd->id; + + int ret = 0; switch (sock->family) { case AF_UNSPEC: return -1; case AF_UNIX: - net_proto_unix_socket (fd); + ret = net_proto_unix_socket (fd); break; case AF_INET: switch (sock->protocol) { case IPPROTO_TCP: - net_proto_tcp_socket (fd); + ret = net_proto_tcp_socket (fd); break; case IPPROTO_UDP: - net_proto_udp_socket (fd); + ret = net_proto_udp_socket (fd); break; } break; case AF_INET6: switch (sock->protocol) { case IPPROTO_TCP: - net_proto_tcp6_socket (fd); + ret = net_proto_tcp6_socket (fd); break; case IPPROTO_UDP: - net_proto_udp6_socket (fd); + ret = net_proto_udp6_socket (fd); break; } break; case AF_RS232: - sock->fd = ips_socket (fd); + ret = ips_socket (fd); break; } + + if (ret) { + kfree (sock); + fd_delete (fd); + + DPRINT (DBG_NET | DBG_SOCKET, "socket () -> %d : ERROR", sock->fd); + return -1; + } /* add into list */ sock->next = &socket_list; @@ -495,6 +507,9 @@ int accept (int fd, sockaddr *addr, socklen_t *addrlen) /* alloc and init context */ sock = (socket_t *) kmalloc (sizeof (socket_t)); + if (!sock) + return 0; + sock->fd = client; sock->family = servsock->family; sock->type = servsock->type; @@ -592,6 +607,51 @@ int sfcntl (int fd, int cmd, long arg) return -1; } +/* socket api select for specified socket */ +int sselect (int readfd, int writefd, int exceptfd) +{ + int fd = -1; + + if (readfd) + fd = readfd; + else if (writefd) + fd = writefd; + else if (exceptfd) + fd = exceptfd; + + socket_t *sock = socket_getbyfd (fd); + + if (!sock) + return -1; + + switch (sock->family) { + /*case AF_UNSPEC: + return -1; + case AF_UNIX: + return net_proto_unix_select (readfd, writefd, exceptfd);*/ + case AF_INET: + switch (sock->protocol) { + case IPPROTO_TCP: + return net_proto_tcp_select (readfd, writefd, exceptfd); + //case IPPROTO_UDP: + // return net_proto_udp_select (readfd, writefd, exceptfd); + } + break; + case AF_INET6: + switch (sock->protocol) { + case IPPROTO_TCP: + return net_proto_tcp6_select (readfd, writefd, exceptfd); + case IPPROTO_UDP: + return net_proto_udp6_select (readfd, writefd, exceptfd); + } + break; + /*case AF_RS232: + return ips_select (readfd, writefd, exceptfd);*/ + } + + return -1; +} + unsigned int init_socket () { socket_list.next = &socket_list; diff --git a/kernel/core/net/tcp.c b/kernel/core/net/tcp.c index 8327468..5ddca1e 100644 --- a/kernel/core/net/tcp.c +++ b/kernel/core/net/tcp.c @@ -2,6 +2,7 @@ * ZeX/OS * Copyright (C) 2008 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org) * Copyright (C) 2009 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org) + * Copyright (C) 2010 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -352,6 +353,45 @@ int net_proto_tcp_accept (int fd, sockaddr_in *addr, socklen_t *addrlen) return fd_new->id; } +int net_proto_tcp_select (int readfd, int writefd, int exceptfd) +{ + int fd = -1; + + if (readfd) + fd = readfd; + else if (writefd) + fd = writefd; + else if (exceptfd) + fd = exceptfd; + + proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd); + + if (!conn) + return -1; + + /* check for incoming connections */ + if (conn->bind) { + proto_tcp_backlog_t *backlog = 0; + + for (backlog = proto_tcp_backlog_list.next; backlog != &proto_tcp_backlog_list; backlog = backlog->next) { + if (backlog->conn == conn) + return 1; + } + + return 0; + } + + /* Is socket closed ? */ + if (conn->state == PROTO_TCP_CONN_STATE_CLOSE) + return 1; + + /* Are some data available ? */ + if (conn->len) + return 1; + + return 0; +} + /** TCP protocol * Hardcore code - syn, ack, psh, fin, etc :P */ diff --git a/kernel/core/net/tcp6.c b/kernel/core/net/tcp6.c index f4a2bb9..481a706 100644 --- a/kernel/core/net/tcp6.c +++ b/kernel/core/net/tcp6.c @@ -2,6 +2,7 @@ * ZeX/OS * Copyright (C) 2008 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org) * Copyright (C) 2009 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org) + * Copyright (C) 2010 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -357,6 +358,45 @@ int net_proto_tcp6_accept (int fd, sockaddr_in6 *addr, socklen_t *addrlen) return fd_new->id; } +int net_proto_tcp6_select (int readfd, int writefd, int exceptfd) +{ + int fd = -1; + + if (readfd) + fd = readfd; + else if (writefd) + fd = writefd; + else if (exceptfd) + fd = exceptfd; + + proto_tcp6_conn_t *conn = net_proto_tcp6_conn_find (fd); + + if (!conn) + return -1; + + /* check for incoming connections */ + if (conn->bind) { + proto_tcp6_backlog_t *backlog = 0; + + for (backlog = proto_tcp6_backlog_list.next; backlog != &proto_tcp6_backlog_list; backlog = backlog->next) { + if (backlog->conn == conn) + return 1; + } + + return 0; + } + + /* Is socket closed ? */ + if (conn->state == PROTO_TCP_CONN_STATE_CLOSE) + return 1; + + /* Are some data available ? */ + if (conn->len) + return 1; + + return 0; +} + /** TCP protocol * Hardcore code - syn, ack, psh, fin, etc :P */ diff --git a/kernel/core/net/udp.c b/kernel/core/net/udp.c index 7c1e758..15c0674 100644 --- a/kernel/core/net/udp.c +++ b/kernel/core/net/udp.c @@ -2,6 +2,7 @@ * ZeX/OS * Copyright (C) 2008 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org) * Copyright (C) 2009 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org) + * Copyright (C) 2010 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -305,6 +306,29 @@ int net_proto_udp_port (int fd, net_port port) return 0; } +int net_proto_udp_select (int readfd, int writefd, int exceptfd) +{ + int fd = -1; + + if (readfd) + fd = readfd; + else if (writefd) + fd = writefd; + else if (exceptfd) + fd = exceptfd; + + proto_udp_conn_t *conn = net_proto_udp_conn_find (fd); + + if (!conn) + return -1; + + /* Are some data available ? */ + if (conn->len) + return 1; + + return 0; +} + /** UDP protocol * hardcore code :P */ diff --git a/kernel/core/net/udp6.c b/kernel/core/net/udp6.c index ad9223a..2ffd390 100644 --- a/kernel/core/net/udp6.c +++ b/kernel/core/net/udp6.c @@ -2,6 +2,7 @@ * ZeX/OS * Copyright (C) 2008 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org) * Copyright (C) 2009 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org) + * Copyright (C) 2010 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -279,6 +280,30 @@ int net_proto_udp6_bind (int fd, sockaddr_in6 *addr, socklen_t len) return -1; } +int net_proto_udp6_select (int readfd, int writefd, int exceptfd) +{ + int fd = -1; + + if (readfd) + fd = readfd; + else if (writefd) + fd = writefd; + else if (exceptfd) + fd = exceptfd; + + proto_udp6_conn_t *conn = net_proto_udp6_conn_find (fd); + + if (!conn) + return -1; + + /* Are some data available ? */ + if (conn->len) + return 1; + + return 0; +} + + /** UDP protocol * hardcore code :P */ diff --git a/kernel/include/errno.h b/kernel/include/errno.h index dcd82b2..59aab27 100644 --- a/kernel/include/errno.h +++ b/kernel/include/errno.h @@ -149,7 +149,7 @@ #define ENOMEDIUM 123 /* No medium found */ #define EMEDIUMTYPE 124 /* Wrong medium type */ -#define ERRNO_ADDRESS 0x9064 /* specific address */ +#define ERRNO_ADDRESS 0x9000 /* specific address */ /* externs */ extern void errno_set (int error); diff --git a/kernel/include/net/socket.h b/kernel/include/net/socket.h index 060e48f..8019972 100644 --- a/kernel/include/net/socket.h +++ b/kernel/include/net/socket.h @@ -1,6 +1,7 @@ /* * ZeX/OS * Copyright (C) 2007 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org) + * Copyright (C) 2010 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -240,6 +241,7 @@ extern int recv (int fd, char *msg, size_t size, int flags); extern int bind (int fd, sockaddr *addr, socklen_t len); extern int sclose (int fd); extern int sfcntl (int fd, int cmd, long arg); +extern int sselect (int readfd, int writefd, int exceptfd); extern unsigned int init_socket (); #endif diff --git a/libc/include/sys/select.h b/kernel/include/select.h similarity index 90% copy from libc/include/sys/select.h copy to kernel/include/select.h index 54a394e..fdd7437 100644 --- a/libc/include/sys/select.h +++ b/kernel/include/select.h @@ -1,6 +1,6 @@ /* * ZeX/OS - * Copyright (C) 2009 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org) + * Copyright (C) 2010 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,17 +16,17 @@ * along with this program. If not, see . */ + #ifndef _SELECT_H #define _SELECT_H -#include +#include #ifndef FD_SETSIZE #define FD_SETSIZE 64 #endif -typedef struct fd_set -{ +typedef struct fd_set { unsigned int count; int fd[FD_SETSIZE]; } fd_set; @@ -38,4 +38,4 @@ typedef struct fd_set extern int select (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timeval *timeout); -#endif +#endif diff --git a/kernel/include/syscall.h b/kernel/include/syscall.h index 5d4676b..436a0fc 100644 --- a/kernel/include/syscall.h +++ b/kernel/include/syscall.h @@ -20,7 +20,6 @@ #ifndef _SYSCALL_H #define _SYSCALL_H -#define SYSV_GETCH (unsigned *) 0x9000 #define SYSV_GETKEY (unsigned *) 0x9004 #define SYSV_FORK (unsigned *) 0x9008 #define SYSV_WRITE (int *) 0x900C @@ -45,6 +44,8 @@ #define SYSV_THREADCLOSE (unsigned *) 0x9058 #define SYSV_IOCTL (int *) 0x905C #define SYSV_LSEEK (long *) 0x9060 +#define SYSV_GETCH (unsigned *) 0x9064 +#define SYSV_SELECT (int *) 0x9068 /* externs */ extern task_t *_curr_task; diff --git a/kernel/include/time.h b/kernel/include/time.h index 599ff79..67c3e70 100644 --- a/kernel/include/time.h +++ b/kernel/include/time.h @@ -38,4 +38,10 @@ typedef struct const char *__tm_zone; /* Timezone abbreviation. */ } tm; +struct timeval { + long tv_sec; /* seconds */ + long tv_usec; /* microseconds */ +}; + + #endif diff --git a/kernel/lib/Makefile b/kernel/lib/Makefile index a784eb1..ece4db2 100644 --- a/kernel/lib/Makefile +++ b/kernel/lib/Makefile @@ -13,13 +13,14 @@ STRING =string/memsetw.o string/memcpy.o string/strlen.o string/strcpy.o string/ ARCHDEP =x86/dma.o x86/setjmp.o x86/longjmp.o CTYPE =ctype/ctype.o UNISTD =unistd/fcntl.o unistd/lseek.o unistd/pipe.o +SYS =sys/select.o ifeq ($(ARCH),arm) CFLAGS=-g -Os -fno-builtin -ffreestanding -nostdinc -pipe -mcpu=arm926ej-s -mabi=apcs-gnu -nostdlib -nostartfiles -nodefaultlibs -ffixed-r8 -msoft-float -I$(INCDIR) -I../build/main ARCHDEP=arm/divsi3.o arm/div0.o arm/modsi3.o endif -OBJS =$(STDIO) $(STDLIB) $(STRING) $(ARCHDEP) $(CTYPE) $(UNISTD) $(ARCHDEP) +OBJS =$(STDIO) $(STDLIB) $(STRING) $(ARCHDEP) $(CTYPE) $(UNISTD) $(SYS) $(ARCHDEP) ifneq ($(V),1) Q := @ diff --git a/kernel/lib/sys/select.c b/kernel/lib/sys/select.c new file mode 100644 index 0000000..935c12c --- /dev/null +++ b/kernel/lib/sys/select.c @@ -0,0 +1,164 @@ +/* + * ZeX/OS + * Copyright (C) 2010 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +extern unsigned long timer_ticks; + +void _fd_clr (int fd, fd_set *set) +{ + if (!set || fd < 0) + return; + + unsigned i; + + for (i = 0; i < set->count; i ++) + if (set->fd[i] == fd) { + set->fd[i] = -1; + + if (set->count == i+1) + set->count --; + break; + } +} + +int _fd_isset (int fd, fd_set *set) +{ + if (!set || fd < 0) + return 0; + + unsigned i; + + for (i = 0; i < set->count; i ++) + if (set->fd[i] == fd) + return 1; + + return 0; +} + +void _fd_set (int fd, fd_set *set) +{ + if (!set || fd < 0) + return; + + unsigned i; + unsigned y = 0; + + /* try to find free entry in actual list */ + for (i = 0; i < set->count; i ++) + if (set->fd[i] == -1) { + set->fd[i] = fd; + y ++; + break; + } + + /* add new entry into list */ + if (!y) { + if (set->count < FD_SETSIZE) + set->fd[set->count ++] = fd; + } +} + +void _fd_zero (fd_set *set) +{ + if (!set) + return; + + set->count = 0; +} + +int select (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timeval *timeout) +{ + unsigned rfds = 0; + unsigned wfds = 0; + unsigned efds = 0; + + if (readfds) + rfds = (unsigned) readfds->count; + if (writefds) + wfds = (unsigned) writefds->count; + if (exceptfds) + efds = (unsigned) exceptfds->count; + + /* prevent from memory overwrite */ + if (rfds > FD_SETSIZE) + rfds = FD_SETSIZE; + if (wfds > FD_SETSIZE) + wfds = FD_SETSIZE; + if (efds > FD_SETSIZE) + efds = FD_SETSIZE; + + unsigned long stime = timer_ticks; + unsigned long ms = timeout->tv_usec / 1000 + timeout->tv_sec * 1000; // covert to milisecond precise + unsigned r; + + for (; (stime+ms) >= timer_ticks; ) { + for (r = 0; r < rfds; r ++) { + if (readfds->fd[r] == -1) + continue; + + fd_t *fd = fd_get (readfds->fd[r]); + + if (!fd) { + _fd_clr (readfds->fd[r], readfds); + continue; + } + + /* TODO: stdin, stdout */ + + if (fd->flags & FD_SOCK) { // socket select + int ret = sselect (fd->id, 0, 0); + + if (ret > 0) + goto ready; + + continue; + } + + if (!fd->s) { + _fd_clr (fd->id, readfds); + continue; + } + +ready: + _fd_zero (readfds); + _fd_zero (writefds); + _fd_zero (exceptfds); + + _fd_set (fd->id, readfds); + + /* TODO: make select to handle more then one event per call */ + return 1; + } + + schedule (); + } + + _fd_zero (readfds); + _fd_zero (writefds); + _fd_zero (exceptfds); + + return 0; +} + + diff --git a/libc/include/_libc.h b/libc/include/_libc.h index 30e57bb..bf86788 100644 --- a/libc/include/_libc.h +++ b/libc/include/_libc.h @@ -21,7 +21,6 @@ #define __LIBC_H /* syscall return value pointers from kernel */ -#define SYSV_GETCH (unsigned *) 0x9000 #define SYSV_GETKEY (unsigned *) 0x9004 #define SYSV_FORK (unsigned *) 0x9008 #define SYSV_WRITE (int *) 0x900C @@ -43,8 +42,10 @@ #define SYSV_GETCHAR (int *) 0x9050 #define SYSV_IOCTL (int *) 0x905C #define SYSV_LSEEK (long *) 0x9060 +#define SYSV_GETCH (unsigned *) 0x9064 +#define SYSV_SELECT (int *) 0x9068 -#define ERRNO_ADDRESS (int *) 0x9064 +#define ERRNO_ADDRESS (int *) 0x9000 #include diff --git a/libc/include/sys/select.h b/libc/include/sys/select.h index 54a394e..84e5abb 100644 --- a/libc/include/sys/select.h +++ b/libc/include/sys/select.h @@ -1,6 +1,7 @@ /* * ZeX/OS * Copyright (C) 2009 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org) + * Copyright (C) 2010 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,8 +26,7 @@ #define FD_SETSIZE 64 #endif -typedef struct fd_set -{ +typedef struct fd_set { unsigned int count; int fd[FD_SETSIZE]; } fd_set; @@ -36,6 +36,10 @@ typedef struct fd_set #define FD_SET(fd, set) _fd_set(fd, set) #define FD_CLR(fd, set) _fd_clr(fd, set) -extern int select (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timeval *timeout); +extern void _fd_clr (int fd, fd_set *set); +extern int _fd_isset (int fd, fd_set *set); +extern void _fd_set (int fd, fd_set *set); +extern void _fd_zero (fd_set *set); +extern int select (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); #endif diff --git a/libc/sys/select.c b/libc/sys/select.c index 1ada0bd..add91ca 100644 --- a/libc/sys/select.c +++ b/libc/sys/select.c @@ -20,49 +20,94 @@ #include #include #include +#include <_libc.h> -void _fd_zero (fd_set *set) +void _fd_clr (int fd, fd_set *set) { - set->count = 0; + if (!set || fd < 0) + return; + + unsigned i; + + for (i = 0; i < set->count; i ++) + if (set->fd[i] == fd) { + set->fd[i] = -1; + + if (set->count == i+1) + set->count --; + break; + } } int _fd_isset (int fd, fd_set *set) { - unsigned int i; + if (!set || fd < 0) + return 0; + + unsigned i; for (i = 0; i < set->count; i ++) if (set->fd[i] == fd) return 1; - + return 0; } void _fd_set (int fd, fd_set *set) { - if (set->count < FD_SETSIZE) - set->fd[set->count ++] = fd; -} - -void _fd_clr (int fd, fd_set *set) -{ - unsigned int i; - - for (i = 0; i < set->count ; i++) { - if (set->fd[i] == fd) { - while (i < set->count - 1) { - set->fd[i] = set->fd[i + 1]; - i ++; - } - - set->count --; + if (!set || fd < 0) + return; + + unsigned i; + unsigned y = 0; + + /* try to find free entry in actual list */ + for (i = 0; i < set->count; i ++) + if (set->fd[i] == -1) { + set->fd[i] = fd; + y ++; break; } + + /* add new entry into list */ + if (!y) { + if (set->count < FD_SETSIZE) + set->fd[set->count ++] = fd; } } -int select (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timeval *timeout) +void _fd_zero (fd_set *set) { - /*TODO */ + if (!set) + return; + + set->count = 0; +} + +int select (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) +{ + struct select_t { + int nfds; + fd_set *readfds; + fd_set *writefds; + fd_set *exceptfds; + struct timeval *timeout; + }; + + struct select_t s; + s.nfds = nfds; + s.readfds = readfds; + s.writefds = writefds; + s.exceptfds = exceptfds; + s.timeout = timeout; + + asm volatile ( + "movl $64, %%eax;" + "movl %0, %%ebx;" + "int $0x80;":: "b" (&s) : "%eax", "memory"); + + errno_update (); - return -1; + /* get return value */ + return (int) *SYSV_SELECT; } \ No newline at end of file -- 2.11.4.GIT