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
This commit is contained in:
@@ -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 ;
|
||||
@@ -0,0 +1,179 @@
|
||||
#include <unistd.h>
|
||||
#include <image.h>
|
||||
#include <OS.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/select.h>
|
||||
#include <errno.h>
|
||||
|
||||
#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
|
||||
@@ -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 <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <kernel/OS.h>
|
||||
#include <iovec.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
Reference in New Issue
Block a user