From eda72d26886fac7d5ef5a60c914077d25b933bf3 Mon Sep 17 00:00:00 2001 From: Waldemar Kornewald Date: Thu, 15 Apr 2004 15:57:49 +0000 Subject: [PATCH] Checked in our version of libsocket.so. When building for BONE use this command: BONE_VERSION=1 jam This will remove the select() function from libsocket.so. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@7202 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/kits/network/libsocket/Jamfile | 29 +++ src/kits/network/libsocket/select.c | 179 +++++++++++++++ src/kits/network/libsocket/socket.c | 330 ++++++++++++++++++++++++++++ 3 files changed, 538 insertions(+) create mode 100644 src/kits/network/libsocket/Jamfile create mode 100644 src/kits/network/libsocket/select.c create mode 100644 src/kits/network/libsocket/socket.c diff --git a/src/kits/network/libsocket/Jamfile b/src/kits/network/libsocket/Jamfile new file mode 100644 index 0000000000..d67b20d15a --- /dev/null +++ b/src/kits/network/libsocket/Jamfile @@ -0,0 +1,29 @@ +SubDir OBOS_TOP src kits network libsocket ; + +UsePrivateHeaders net ; + +{ + local defines ; + if $(BONE_VERSION) { + defines += BONE_VERSION ; + } + defines = [ FDefines $(defines) ] ; + SubDirCcFlags $(defines) ; + SubDirC++Flags $(defines) ; +} + +SharedLibrary socket : + socket.c + select.c +; + +# Installation -- in the test directory for the time being +OBOSInstallRelSymLink install-networking + : [ FDirName $(OBOS_TEST_DIR) kits net lib ] + : libsocket.so + : installed-networking-test ; + +Package openbeos-networkingkit-cvs : + libsocket.so : +# boot home config lib ; + boot home Desktop openbeos-networkingkit lib ; diff --git a/src/kits/network/libsocket/select.c b/src/kits/network/libsocket/select.c new file mode 100644 index 0000000000..6ae6aec382 --- /dev/null +++ b/src/kits/network/libsocket/select.c @@ -0,0 +1,179 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "net_stack_driver.h" + + +#ifndef BONE_VERSION + +static int fd_set_count(fd_set * bits, int nbits) +{ + int count; + int fd; + + count = 0; + for (fd = 0; fd < nbits; fd++) + if (FD_ISSET(fd, bits)) + count++; + + return count; +} + + +_EXPORT int select(int nbits, struct fd_set * rbits, + struct fd_set * wbits, + struct fd_set * ebits, + struct timeval * tv) +{ + int fd; + int n; + struct stack_driver_args args; + status_t status; + area_id area; + struct r5_selectsync * rss; + +#define ROUND_TO_PAGE_SIZE(x) (((x) + (B_PAGE_SIZE) - 1) & ~((B_PAGE_SIZE) - 1)) + + // We share a area with the fd_set on it with the network stack code. + // The r5_notify_select_event in the net_stack_driver code will fill it and wakeup us + // when a event raise. + + area = create_area("r5_selectsync", (void **) &rss, + B_ANY_ADDRESS, ROUND_TO_PAGE_SIZE(sizeof(*rss)), B_NO_LOCK, + B_READ_AREA | B_WRITE_AREA); + if (area < B_OK) { + errno = area; + return -1; + }; + + // The area is multi-thread protected by a semaphore locker + rss->lock = create_sem(1, "r5_selectsync_lock"); + if (rss->lock < B_OK) { + errno = rss->lock; + rss->wakeup = 0; + n = -1; + goto error; + }; + + // Create the wakeup call semaphore + rss->wakeup = create_sem(0, "r5_selectsync_wakeup"); + if (rss->wakeup < B_OK) { + errno = rss->wakeup; + n = -1; + goto error; + }; + + FD_ZERO(&rss->rbits); + FD_ZERO(&rss->wbits); + FD_ZERO(&rss->ebits); + + /* Beware, ugly hacky hack: we pass the area_id of our shared r5_selectsync, + that net_stack_driver should udate directly + */ + args.u.select.sync = (struct selectsync *) area; + + /* call, indirectly, net_stack_select() for each event to monitor + * as we are not the vfs, we can't call this device hook ourself, but + * our NET_STACK_SELECT opcode would do it for us... + */ + n = 0; + for (fd = 0; fd < nbits; fd++) { + if (rbits && FD_ISSET(fd, rbits)) { + args.u.select.ref = (fd << 8) | 1; + if (ioctl(fd, NET_STACK_SELECT, &args, sizeof(args)) >= 0) + n++; + }; + if (wbits && FD_ISSET(fd, wbits)) { + args.u.select.ref = (fd << 8) | 2; + if (ioctl(fd, NET_STACK_SELECT, &args, sizeof(args)) >= 0) + n++; + }; + if (ebits && FD_ISSET(fd, ebits)) { + args.u.select.ref = (fd << 8) | 3; + if (ioctl(fd, NET_STACK_SELECT, &args, sizeof(args)) >= 0) + n++; + }; + } + + if (n < 1) { + // TODO: maybe we could hack a workaround for select() on file/dev here: + // If no fd handle the NET_STACK_SELECT, assume they're files, so always + // readable and writable? + errno = B_BAD_VALUE; + n = -1; + goto error; + }; + + // Okay, now wait for our wakeup call. + // Maybe his's already there, even... (when the select event is already raised) + if (tv) { + bigtime_t timeout; + + timeout = tv->tv_sec * 1000000LL + tv->tv_usec; + status = acquire_sem_etc(rss->wakeup, 1, B_RELATIVE_TIMEOUT | B_CAN_INTERRUPT, timeout); + } else + status = acquire_sem(rss->wakeup); + + // we don't need it anymore, and we say "select() party is over" that way, too :-) + delete_sem(rss->lock); + delete_sem(rss->wakeup); + rss->lock = rss->wakeup = -1; + + // unregister socket event notification + for(fd = 0; fd < nbits; fd++) { + if (rbits && FD_ISSET(fd, rbits)) { + args.u.select.ref = (fd << 8) | 1; + ioctl(fd, NET_STACK_DESELECT, &args, sizeof(args)); + }; + if (wbits && FD_ISSET(fd, wbits)) { + args.u.select.ref = (fd << 8) | 2; + ioctl(fd, NET_STACK_DESELECT, &args, sizeof(args)); + }; + if (ebits && FD_ISSET(fd, ebits)) { + args.u.select.ref = (fd << 8) | 3; + ioctl(fd, NET_STACK_DESELECT, &args, sizeof(args)); + }; + }; + + // Okay, what the final result? + switch (status) { + case B_OK: + case B_WOULD_BLOCK: + case B_TIMED_OUT: // logicly, 'n' should stay to 0 in this case... + n = 0; + if (rbits) { + memcpy(rbits, &rss->rbits, sizeof(*rbits)); + n += fd_set_count(rbits, nbits); + }; + if (wbits) { + memcpy(wbits, &rss->wbits, sizeof(*wbits)); + n += fd_set_count(wbits, nbits); + }; + if (ebits) { + memcpy(ebits, &rss->ebits, sizeof(*ebits)); + n += fd_set_count(ebits, nbits); + }; + break; + + default: + errno = status; + n = -1; + break; + }; + +error: + if (rss->lock >= 0) + delete_sem(rss->lock); + if (rss->wakeup >= 0) + delete_sem(rss->wakeup); + + delete_area(area); + return n; +} + +#endif diff --git a/src/kits/network/libsocket/socket.c b/src/kits/network/libsocket/socket.c new file mode 100644 index 0000000000..f0c4384060 --- /dev/null +++ b/src/kits/network/libsocket/socket.c @@ -0,0 +1,330 @@ +/* socket.c */ + +/* This is a very simple little shared library that acts as a wrapper + * for our device/kernel stack! + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "net_stack_driver.h" + +// Forward declaration of sysctl.h, because it's currently declared under headers/private/kernel/sysctl.h +int sysctl(int *, uint, void *, size_t *, void *, size_t); + +static char * get_stack_driver_path(void); + + +_EXPORT int socket(int family, int type, int protocol) +{ + int sock; + int rv; + struct stack_driver_args args; + + sock = open(get_stack_driver_path(), O_RDWR); + if (sock < 0) + return sock; + + args.u.socket.family = family; + args.u.socket.type = type; + args.u.socket.proto = protocol; + + rv = ioctl(sock, NET_STACK_SOCKET, &args, sizeof(args)); + if (rv < 0) { + close(sock); + return rv; + } + + return sock; +} + + +_EXPORT int bind(int sock, const struct sockaddr *addr, int addrlen) +{ + struct stack_driver_args args; + + args.u.sockaddr.addr = (struct sockaddr *) addr; + args.u.sockaddr.addrlen = addrlen; + + return ioctl(sock, NET_STACK_BIND, &args, sizeof(args)); +} + + +_EXPORT int shutdown(int sock, int how) +{ + struct stack_driver_args args; + + args.u.integer = how; + + return ioctl(sock, NET_STACK_SHUTDOWN, &args, sizeof(args)); +} + + +_EXPORT int connect(int sock, const struct sockaddr *addr, int addrlen) +{ + struct stack_driver_args args; + + args.u.sockaddr.addr = (struct sockaddr *) addr; + args.u.sockaddr.addrlen = addrlen; + + return ioctl(sock, NET_STACK_CONNECT, &args, sizeof(args)); +} + + +_EXPORT int listen(int sock, int backlog) +{ + struct stack_driver_args args; + + args.u.integer = backlog; + + return ioctl(sock, NET_STACK_LISTEN, &args, sizeof(args)); +} + + +_EXPORT int accept(int sock, struct sockaddr *addr, int *addrlen) +{ + struct stack_driver_args args; + int rv; + int new_sock; + void *cookie; + + new_sock = open(get_stack_driver_path(), O_RDWR); + if (new_sock < 0) + return new_sock; + + // The network stack driver will need to know to which net_stack_cookie to + // *bind* with the new accepted socket. He can't know himself find out + // the net_stack_cookie of our new_sock file descriptor, the just open() one... + // So, here, we ask him the net_stack_cookie value for our fd... :-) + rv = ioctl(new_sock, NET_STACK_GET_COOKIE, &cookie); + if (rv < 0) { + close(new_sock); + return rv; + } + + args.u.accept.cookie = cookie; // this way driver can use the right fd/cookie for the new_sock! + + args.u.accept.addr = addr; + args.u.accept.addrlen = *addrlen; + + rv = ioctl(sock, NET_STACK_ACCEPT, &args, sizeof(args)); + if (rv < 0) { + close(new_sock); + return rv; + } + + *addrlen = args.u.accept.addrlen; + + return new_sock; +} + + +_EXPORT ssize_t recvfrom(int sock, void *buffer, size_t buflen, int flags, + struct sockaddr *addr, size_t *addrlen) +{ + struct msghdr mh; + struct iovec iov; + int rv; + + /* XXX - would this be better done as scatter gather? */ + mh.msg_name = (caddr_t)addr; + mh.msg_namelen = addrlen ? *addrlen : 0; + mh.msg_flags = flags; + mh.msg_control = NULL; + mh.msg_controllen = 0; + iov.iov_base = buffer; + iov.iov_len = buflen; + mh.msg_iov = &iov; + mh.msg_iovlen = 1; + + rv = ioctl(sock, NET_STACK_RECVFROM, &mh, sizeof(mh)); + if (rv < 0) + return rv; + + if (addrlen) + *addrlen = mh.msg_namelen; + + return rv; +} + +_EXPORT ssize_t sendto(int sock, const void *buffer, size_t buflen, int flags, + const struct sockaddr *addr, size_t addrlen) +{ + struct msghdr mh; + struct iovec iov; + + /* XXX - would this be better done as scatter gather? */ + mh.msg_name = (caddr_t)addr; + mh.msg_namelen = addrlen; + mh.msg_flags = flags; + mh.msg_control = NULL; + mh.msg_controllen = 0; + iov.iov_base = (caddr_t)buffer; + iov.iov_len = buflen; + mh.msg_iov = &iov; + mh.msg_iovlen = 1; + + return ioctl(sock, NET_STACK_SENDTO, &mh, sizeof(mh)); +} + + +/* These need to be adjusted to take account of the MSG_PEEK + * flag, but old R5 doesn't use it... + */ +_EXPORT ssize_t recv(int sock, void *data, size_t datalen, int flags) +{ + struct stack_driver_args args; + int rv; + + args.u.transfer.data = data; + args.u.transfer.datalen = datalen; + args.u.transfer.flags = flags; + args.u.transfer.addr = NULL; + args.u.transfer.addrlen = 0; + + rv = ioctl(sock, NET_STACK_RECV, &args, sizeof(args)); + if (rv < 0) + return rv; + + return args.u.transfer.datalen; +} + + +_EXPORT ssize_t send(int sock, const void *data, size_t datalen, int flags) +{ + struct stack_driver_args args; + int rv; + + args.u.transfer.data = (void *) data; + args.u.transfer.datalen = datalen; + args.u.transfer.flags = flags; + args.u.transfer.addr = NULL; + args.u.transfer.addrlen = 0; + + rv = ioctl(sock, NET_STACK_SEND, &args, sizeof(args)); + if (rv < 0) + return rv; + + return args.u.transfer.datalen; +} + + +_EXPORT int getsockopt(int sock, int level, int option, void *optval, size_t *optlen) +{ + struct stack_driver_args args; + int rv; + + args.u.sockopt.level = level; + args.u.sockopt.option = option; + args.u.sockopt.optval = optval; + args.u.sockopt.optlen = *optlen; + + rv = ioctl(sock, NET_STACK_GETSOCKOPT, &args, sizeof(args)); + if (rv ==0) + *optlen = args.u.sockopt.optlen; + + return rv; +} + + +_EXPORT int setsockopt(int sock, int level, int option, const void *optval, size_t optlen) +{ + struct stack_driver_args args; + + args.u.sockopt.level = level; + args.u.sockopt.option = option; + args.u.sockopt.optval = (void *) optval; + args.u.sockopt.optlen = optlen; + + return ioctl(sock, NET_STACK_SETSOCKOPT, &args, sizeof(args)); +} + + +_EXPORT int getpeername(int sock, struct sockaddr *addr, int *addrlen) +{ + struct stack_driver_args args; + int rv; + + args.u.sockaddr.addr = addr; + args.u.sockaddr.addrlen = *addrlen; + + rv = ioctl(sock, NET_STACK_GETPEERNAME, &args, sizeof(args)); + if (rv < 0) + return rv; + + *addrlen = args.u.sockaddr.addrlen; + + return rv; +} + +_EXPORT int getsockname(int sock, struct sockaddr *addr, int *addrlen) +{ + struct stack_driver_args args; + int rv; + + args.u.sockaddr.addr = addr; + args.u.sockaddr.addrlen = *addrlen; + + rv = ioctl(sock, NET_STACK_GETSOCKNAME, &args, sizeof(args)); + if (rv < 0) + return rv; + + *addrlen = args.u.sockaddr.addrlen; + + return rv; +} + +// #pragma mark - + + +_EXPORT int sysctl (int *name, uint namelen, void *oldp, size_t *oldlenp, + void *newp, size_t newlen) +{ + int s; + struct sysctl_args sa; + int rv; + + s = socket(PF_ROUTE, SOCK_RAW, 0); + if (s < 0) + return s; + + sa.name = name; + sa.namelen = namelen; + sa.oldp = oldp; + sa.oldlenp = oldlenp; + sa.newp = newp; + sa.newlen = newlen; + + rv = ioctl(s, NET_STACK_SYSCTL, &sa, sizeof(sa)); + + close(s); + + return rv; +} + +// #pragma mark - + +/* + * Private routines + * ---------------- + */ + +static char * get_stack_driver_path(void) { + char * path; + + // user-defined stack driver path? + path = getenv("NET_STACK_DRIVER_PATH"); + if (path) + return path; + + // use the default stack driver path + return NET_STACK_DRIVER_PATH; +}