* Removed the old net_stack driver code, and the kernel socket interface.
* Also removed the header files that belong to those files. * Only kept the userland_ipc.h header for now, to remember us about the former userland server driver (that I also removed - it can always be resurrected from SVN if needed). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25045 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
88321c8cd5
commit
45e95a057f
build/jam
headers
src/add-ons/kernel
drivers/network
network
@ -373,8 +373,7 @@ AddSymlinkToHaikuImage beos system add-ons Tracker
|
||||
AddFilesToHaikuImage beos system add-ons input_server devices
|
||||
: <input>keyboard <input>mouse <input>wacom ;
|
||||
AddFilesToHaikuImage beos system add-ons input_server filters : screen_saver ;
|
||||
AddFilesToHaikuImage beos system add-ons kernel network
|
||||
: stack socket ;
|
||||
AddFilesToHaikuImage beos system add-ons kernel network : stack ;
|
||||
AddFilesToHaikuImage beos system add-ons kernel network devices
|
||||
: $(BEOS_NETWORK_DEVICES) ;
|
||||
AddFilesToHaikuImage beos system add-ons kernel network datalink_protocols
|
||||
|
@ -1,43 +0,0 @@
|
||||
/* Copyright 2007, Haiku Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _SOCKET_INTERFACE_H
|
||||
#define _SOCKET_INTERFACE_H
|
||||
|
||||
//! Kernel interface to the socket API
|
||||
|
||||
|
||||
#include <module.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
|
||||
|
||||
#define B_SOCKET_MODULE_NAME "network/socket/v1"
|
||||
|
||||
struct socket_module_info {
|
||||
struct module_info info;
|
||||
|
||||
int (*accept)(int socket, struct sockaddr *address, socklen_t *_addressLength);
|
||||
int (*bind)(int socket, const struct sockaddr *address, socklen_t addressLength);
|
||||
int (*connect)(int socket, const struct sockaddr *address, socklen_t addressLength);
|
||||
int (*getpeername)(int socket, struct sockaddr *address, socklen_t *_addressLength);
|
||||
int (*getsockname)(int socket, struct sockaddr *address, socklen_t *_addressLength);
|
||||
int (*getsockopt)(int socket, int level, int option, void *value, socklen_t *_length);
|
||||
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 bufferLength, int flags,
|
||||
struct sockaddr *address, socklen_t *_addressLength);
|
||||
ssize_t (*recvmsg)(int socket, struct msghdr *message, int flags);
|
||||
ssize_t (*send)(int socket, const void *buffer, size_t length, int flags);
|
||||
ssize_t (*sendmsg)(int socket, const struct msghdr *message, int flags);
|
||||
ssize_t (*sendto)(int socket, const void *message, size_t length, int flags,
|
||||
const struct sockaddr *address, socklen_t addressLength);
|
||||
int (*setsockopt)(int socket, int level, int option, const void *value,
|
||||
socklen_t length);
|
||||
int (*shutdown)(int socket, int how);
|
||||
int (*socket)(int domain, int type, int protocol);
|
||||
int (*sockatmark)(int socket);
|
||||
int (*socketpair)(int domain, int type, int protocol, int socketVector[2]);
|
||||
};
|
||||
|
||||
#endif // _SOCKET_INTERFACE_H
|
@ -1,97 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2006, Haiku, Inc. All Rights Reserved.
|
||||
* This file may be used under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef NET_STACK_DRIVER_H
|
||||
#define NET_STACK_DRIVER_H
|
||||
|
||||
|
||||
#include <net_stat.h>
|
||||
|
||||
#include <sys/select.h>
|
||||
|
||||
|
||||
// Forward declaration
|
||||
struct sockaddr;
|
||||
|
||||
#define NET_STACK_DRIVER_DEVICE "net/stack"
|
||||
#define NET_STACK_DRIVER_PATH "/dev/" NET_STACK_DRIVER_DEVICE
|
||||
|
||||
enum {
|
||||
NET_STACK_IOCTL_BASE = 8800,
|
||||
NET_STACK_IOCTL_END = 8999,
|
||||
|
||||
// ops not acting on an existing socket
|
||||
NET_STACK_SOCKET = NET_STACK_IOCTL_BASE, // socket_args *
|
||||
NET_STACK_GET_COOKIE, // void **
|
||||
NET_STACK_CONTROL_NET_MODULE, // control_net_module_args *
|
||||
NET_STACK_GET_NEXT_STAT, // get_next_stat_args *
|
||||
|
||||
// ops acting on an existing socket
|
||||
NET_STACK_BIND, // sockaddr_args *
|
||||
NET_STACK_RECEIVE, // message_args *
|
||||
NET_STACK_SEND, // message_args *
|
||||
NET_STACK_LISTEN, // int_args * (value = backlog)
|
||||
NET_STACK_ACCEPT, // sockaddr_args *
|
||||
NET_STACK_CONNECT, // sockaddr_args *
|
||||
NET_STACK_SHUTDOWN, // int_args * (value = how)
|
||||
NET_STACK_GETSOCKOPT, // sockopt_args *
|
||||
NET_STACK_SETSOCKOPT, // sockopt_args *
|
||||
NET_STACK_GETSOCKNAME, // sockaddr_args *
|
||||
NET_STACK_GETPEERNAME, // sockaddr_args *
|
||||
NET_STACK_SOCKETPAIR, // socketpair_args *
|
||||
|
||||
NET_STACK_NOTIFY_SOCKET_EVENT, // notify_socket_event_args * (userland stack only)
|
||||
|
||||
NET_STACK_IOCTL_MAX
|
||||
};
|
||||
|
||||
struct sockaddr_args { // used by NET_STACK_CONNECT/_BIND/_GETSOCKNAME/_GETPEERNAME
|
||||
struct sockaddr *address;
|
||||
socklen_t address_length;
|
||||
};
|
||||
|
||||
struct sockopt_args { // used by NET_STACK_SETSOCKOPT/_GETSOCKOPT
|
||||
int level;
|
||||
int option;
|
||||
void *value;
|
||||
int length;
|
||||
};
|
||||
|
||||
struct message_args {
|
||||
struct msghdr *header;
|
||||
void *data;
|
||||
size_t length;
|
||||
int flags;
|
||||
};
|
||||
|
||||
struct socket_args { // used by NET_STACK_SOCKET
|
||||
int family;
|
||||
int type;
|
||||
int protocol;
|
||||
};
|
||||
|
||||
struct socketpair_args { // used by NET_STACK_SOCKETPAIR
|
||||
int second_socket;
|
||||
};
|
||||
|
||||
struct accept_args { // used by NET_STACK_ACCEPT
|
||||
int accept_socket;
|
||||
struct sockaddr *address;
|
||||
socklen_t address_length;
|
||||
};
|
||||
|
||||
struct get_next_stat_args { // used by NET_STACK_GET_NEXT_STAT
|
||||
uint32 cookie;
|
||||
int family;
|
||||
struct net_stat stat;
|
||||
};
|
||||
|
||||
struct control_net_module_args { // used by NET_STACK_CONTROL_NET_MODULE
|
||||
const char *name;
|
||||
uint32 op;
|
||||
void *data;
|
||||
size_t length;
|
||||
};
|
||||
|
||||
#endif /* NET_STACK_DRIVER_H */
|
@ -7,7 +7,6 @@ SubInclude HAIKU_TOP src add-ons kernel drivers network pegasus ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers network rtl8139 ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers network rtl8169 ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers network sis900 ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers network stack ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers network via_rhine ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers network vlance ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers network wb840 ;
|
||||
|
@ -1,55 +0,0 @@
|
||||
SubDir HAIKU_TOP src add-ons kernel drivers network stack ;
|
||||
|
||||
SetSubDirSupportedPlatformsBeOSCompatible ;
|
||||
|
||||
if ! $(TARGET_PLATFORM_HAIKU_COMPATIBLE) {
|
||||
UseHeaders [ FStandardOSHeaders ] : true ;
|
||||
# Needed for <drivers/Select.h> and maybe other stuff.
|
||||
UseHeaders [ FDirName $(HAIKU_TOP) headers posix ] : true ;
|
||||
# We need the public network headers also when not compiling for Haiku.
|
||||
# Unfortunately we get more than we want, namely all POSIX headers.
|
||||
}
|
||||
|
||||
UsePrivateHeaders kernel net ;
|
||||
UseHeaders $(TARGET_PRIVATE_KERNEL_HEADERS) : true ;
|
||||
|
||||
# a) Userland stack version:
|
||||
|
||||
KernelAddon userland_net_server :
|
||||
userland_server.cpp
|
||||
;
|
||||
|
||||
# b) Kernelland stack version:
|
||||
|
||||
KernelAddon net_stack :
|
||||
kernel_stack.cpp
|
||||
;
|
||||
|
||||
# Installation
|
||||
|
||||
HaikuInstall install-networking : /boot/home/config/add-ons/kernel/drivers/bin :
|
||||
userland_net_server
|
||||
net_stack
|
||||
;
|
||||
|
||||
HaikuInstallRelSymLink install-networking : /boot/home/config/add-ons/kernel/drivers/dev/net :
|
||||
<installed>userland_net_server
|
||||
<installed>net_stack :
|
||||
installed-symlink
|
||||
;
|
||||
|
||||
HaikuInstall install-userland-networking : /boot/home/config/add-ons/kernel/drivers/bin :
|
||||
userland_net_server :
|
||||
installed-userland-networking
|
||||
;
|
||||
|
||||
HaikuInstallRelSymLink install-userland-networking : /boot/home/config/add-ons/kernel/drivers/dev/net :
|
||||
<installed-userland-networking>userland_net_server :
|
||||
installed-userland-networking-symlink
|
||||
;
|
||||
Package haiku-networkingkit-cvs :
|
||||
net_stack userland_net_server :
|
||||
boot home config add-ons kernel drivers bin ;
|
||||
|
||||
PackageDriverSymLink haiku-networkingkit-cvs : net net_stack ;
|
||||
PackageDriverSymLink haiku-networkingkit-cvs : net userland_net_server ;
|
@ -1,746 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2008, Haiku, Inc. All Rights Reserved.
|
||||
* This file may be used under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
/*!
|
||||
This file implements a very simple socket driver that is intended to
|
||||
act as an interface to the networking stack.
|
||||
*/
|
||||
|
||||
#include <net_stack_driver.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <driver_settings.h>
|
||||
#include <Drivers.h>
|
||||
#include <KernelExport.h>
|
||||
|
||||
#include <fs/fd.h>
|
||||
#include <kernel.h>
|
||||
#include <syscall_restart.h>
|
||||
|
||||
#include <net_socket.h>
|
||||
|
||||
|
||||
#define NET_STARTER_MODULE_NAME "network/stack/starter/v1"
|
||||
|
||||
// debugging macros
|
||||
#define LOGID "net_stack_driver: "
|
||||
#define ERROR(format, args...) dprintf(LOGID "ERROR: " format, ## args)
|
||||
|
||||
#ifdef DEBUG
|
||||
# define TRACE(format, args...) dprintf(format, ## args)
|
||||
#else
|
||||
# define TRACE(format, args...)
|
||||
#endif
|
||||
|
||||
|
||||
// the cookie we attach to each file descriptor opened on our driver entry
|
||||
struct net_stack_cookie {
|
||||
net_socket *socket;
|
||||
// is set using NET_STACK_SOCKET/_ACCEPT
|
||||
};
|
||||
|
||||
|
||||
int32 api_version = B_CUR_DRIVER_API_VERSION;
|
||||
|
||||
static int32 sOpenCount = 0;
|
||||
static status_t sInitializationStatus = B_NO_INIT;
|
||||
static sem_id sInitializationSem;
|
||||
static struct net_socket_module_info *sSocket = NULL;
|
||||
|
||||
|
||||
// #pragma mark - internal functions
|
||||
|
||||
|
||||
template<typename ArgType> status_t
|
||||
return_address(ArgType &args, void *data)
|
||||
{
|
||||
sockaddr_storage *target;
|
||||
socklen_t length;
|
||||
|
||||
if (user_memcpy(&target, &((ArgType *)data)->address, sizeof(void *))
|
||||
< B_OK
|
||||
|| user_memcpy(&length, &((ArgType *)data)->address_length,
|
||||
sizeof(socklen_t)) < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
|
||||
if (target == NULL)
|
||||
return B_OK;
|
||||
|
||||
if (user_memcpy(&((ArgType *)data)->address_length, &args.address_length,
|
||||
sizeof(socklen_t)) < B_OK
|
||||
|| user_memcpy(target, args.address, min_c(length, args.address_length))
|
||||
< B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
template<typename ArgType> status_t
|
||||
check_args_and_address(ArgType &args, sockaddr_storage &address, void *data,
|
||||
size_t length, bool copyAddress = true)
|
||||
{
|
||||
if (data == NULL || length != sizeof(ArgType))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (user_memcpy(&args, data, sizeof(ArgType)) < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
|
||||
if (copyAddress && args.address_length > sizeof(sockaddr_storage))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (copyAddress
|
||||
&& user_memcpy(&address, args.address, args.address_length) < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
|
||||
args.address = (sockaddr *)&address;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
check_message_args(message_args &args, msghdr &header,
|
||||
sockaddr_storage &address, void *data, size_t length,
|
||||
sockaddr **originalAddress)
|
||||
{
|
||||
if (length < sizeof(message_args))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
status_t status = user_memcpy(&args, data, sizeof(message_args));
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
if (args.header != NULL) {
|
||||
status = user_memcpy(&header, args.header, sizeof(msghdr));
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
if (header.msg_name == NULL)
|
||||
return B_OK;
|
||||
|
||||
if (originalAddress == NULL) {
|
||||
if (header.msg_namelen > sizeof(address))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (header.msg_name != NULL) {
|
||||
status = user_memcpy(&address, header.msg_name,
|
||||
header.msg_namelen);
|
||||
if (status < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
}
|
||||
} else {
|
||||
*originalAddress = (sockaddr *)header.msg_name;
|
||||
}
|
||||
|
||||
header.msg_name = (char *)&address;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
template<typename ArgType> status_t
|
||||
check_args(ArgType &args, void *data, size_t length)
|
||||
{
|
||||
if (data == NULL || length != sizeof(ArgType))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (user_memcpy(&args, data, sizeof(ArgType)) < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
static const char*
|
||||
opcode_name(int op)
|
||||
{
|
||||
#define C2N(op) { op, #op }
|
||||
// op-code to name
|
||||
struct commands_info {
|
||||
int op;
|
||||
const char *name;
|
||||
} *ci, commands_info[] = {
|
||||
C2N(NET_STACK_SOCKET),
|
||||
C2N(NET_STACK_GET_COOKIE),
|
||||
C2N(NET_STACK_CONTROL_NET_MODULE),
|
||||
C2N(NET_STACK_GET_NEXT_STAT),
|
||||
C2N(NET_STACK_BIND),
|
||||
C2N(NET_STACK_RECEIVE),
|
||||
C2N(NET_STACK_SEND),
|
||||
C2N(NET_STACK_LISTEN),
|
||||
C2N(NET_STACK_ACCEPT),
|
||||
C2N(NET_STACK_CONNECT),
|
||||
C2N(NET_STACK_SHUTDOWN),
|
||||
C2N(NET_STACK_GETSOCKOPT),
|
||||
C2N(NET_STACK_SETSOCKOPT),
|
||||
C2N(NET_STACK_GETSOCKNAME),
|
||||
C2N(NET_STACK_GETPEERNAME),
|
||||
C2N(NET_STACK_SOCKETPAIR),
|
||||
C2N(NET_STACK_NOTIFY_SOCKET_EVENT),
|
||||
|
||||
// Userland IPC-specific opcodes
|
||||
// C2N(NET_STACK_OPEN),
|
||||
// C2N(NET_STACK_CLOSE),
|
||||
// C2N(NET_STACK_NEW_CONNECTION),
|
||||
|
||||
// Standard BeOS opcodes
|
||||
C2N(FIONBIO),
|
||||
C2N(B_SET_BLOCKING_IO),
|
||||
C2N(B_SET_NONBLOCKING_IO),
|
||||
|
||||
{ 0, "Unknown!" }
|
||||
};
|
||||
#undef C2N
|
||||
|
||||
ci = commands_info;
|
||||
while(ci && ci->op) {
|
||||
if (ci->op == op)
|
||||
return ci->name;
|
||||
ci++;
|
||||
}
|
||||
|
||||
return "???";
|
||||
}
|
||||
#endif // DEBUG
|
||||
|
||||
|
||||
static status_t
|
||||
resolve_cookie(int kernel, int socket, net_stack_cookie **cookie)
|
||||
{
|
||||
if (kernel)
|
||||
return ioctl(socket, NET_STACK_GET_COOKIE, cookie, sizeof(*cookie));
|
||||
|
||||
return user_fd_kernel_ioctl(socket, NET_STACK_GET_COOKIE, cookie,
|
||||
sizeof(*cookie));
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - device
|
||||
|
||||
|
||||
static status_t
|
||||
net_stack_open(const char *name, uint32 flags, void **_cookie)
|
||||
{
|
||||
if (atomic_add(&sOpenCount, 1) == 0) {
|
||||
// When we're opened for the first time, we'll try to load the
|
||||
// networking stack
|
||||
module_info *module;
|
||||
status_t status = get_module(NET_STARTER_MODULE_NAME, &module);
|
||||
if (status == B_OK) {
|
||||
status = get_module(NET_SOCKET_MODULE_NAME,
|
||||
(module_info **)&sSocket);
|
||||
if (status != B_OK) {
|
||||
put_module(NET_STARTER_MODULE_NAME);
|
||||
ERROR("Can't load " NET_SOCKET_MODULE_NAME " module: %ld\n",
|
||||
status);
|
||||
}
|
||||
} else
|
||||
ERROR("Can't load network stack module: %ld\n", status);
|
||||
|
||||
sInitializationStatus = status;
|
||||
release_sem_etc(sInitializationSem, 1,
|
||||
B_RELEASE_ALL | B_DO_NOT_RESCHEDULE);
|
||||
|
||||
if (status < B_OK) {
|
||||
atomic_add(&sOpenCount, -1);
|
||||
return status;
|
||||
}
|
||||
} else {
|
||||
while (sInitializationStatus == B_NO_INIT) {
|
||||
acquire_sem(sInitializationSem);
|
||||
}
|
||||
if (sInitializationStatus != B_OK) {
|
||||
atomic_add(&sOpenCount, -1);
|
||||
return sInitializationStatus;
|
||||
}
|
||||
}
|
||||
|
||||
net_stack_cookie *cookie = (net_stack_cookie *)malloc(
|
||||
sizeof(net_stack_cookie));
|
||||
if (cookie == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
cookie->socket = NULL;
|
||||
*_cookie = cookie;
|
||||
|
||||
TRACE("net_stack_open(%s, %s%s) return this cookie: %p\n",
|
||||
name,
|
||||
(((flags & O_RWMASK) == O_RDONLY) ? "O_RDONLY" :
|
||||
((flags & O_RWMASK) == O_WRONLY) ? "O_WRONLY" : "O_RDWR"),
|
||||
(flags & O_NONBLOCK) ? " O_NONBLOCK" : "",
|
||||
cookie);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
net_stack_close(void *_cookie)
|
||||
{
|
||||
net_stack_cookie *cookie = (net_stack_cookie *)_cookie;
|
||||
|
||||
TRACE("net_stack_close(%p)\n", cookie);
|
||||
|
||||
if (cookie->socket == NULL)
|
||||
return B_OK;
|
||||
|
||||
return sSocket->close(cookie->socket);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
net_stack_free_cookie(void *_cookie)
|
||||
{
|
||||
net_stack_cookie *cookie = (net_stack_cookie *)_cookie;
|
||||
|
||||
TRACE("net_stack_free_cookie(%p)\n", cookie);
|
||||
|
||||
if (cookie->socket != NULL)
|
||||
sSocket->free(cookie->socket);
|
||||
|
||||
free(cookie);
|
||||
|
||||
if (atomic_add(&sOpenCount, -1) == 1) {
|
||||
// the last reference to us has been removed, unload the networking
|
||||
// stack again (it will only be actually unloaded in case there is
|
||||
// no interface defined)
|
||||
put_module(NET_SOCKET_MODULE_NAME);
|
||||
put_module(NET_STARTER_MODULE_NAME);
|
||||
sInitializationStatus = B_NO_INIT;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
net_stack_control(void *_cookie, uint32 op, void *data, size_t length)
|
||||
{
|
||||
net_stack_cookie *cookie = (net_stack_cookie *)_cookie;
|
||||
status_t status;
|
||||
|
||||
TRACE("net_stack_control(%p, %s (0x%lX), %p, %ld)\n",
|
||||
_cookie, opcode_name(op), op, data, length);
|
||||
|
||||
if (cookie->socket == NULL) {
|
||||
switch (op) {
|
||||
case NET_STACK_SOCKET:
|
||||
{
|
||||
socket_args args;
|
||||
status = check_args(args, data, length);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
return sSocket->open_socket(args.family, args.type,
|
||||
args.protocol, &cookie->socket);
|
||||
}
|
||||
|
||||
case NET_STACK_GET_COOKIE:
|
||||
if (!IS_KERNEL_ADDRESS(data))
|
||||
return B_BAD_ADDRESS;
|
||||
*((net_stack_cookie **)data) = cookie;
|
||||
return B_OK;
|
||||
|
||||
case NET_STACK_GET_NEXT_STAT:
|
||||
{
|
||||
get_next_stat_args args;
|
||||
status = check_args(args, data, length);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
status = sSocket->get_next_stat(&args.cookie, args.family,
|
||||
&args.stat);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
return user_memcpy(data, &args, sizeof(get_next_stat_args));
|
||||
}
|
||||
|
||||
default:
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
} else {
|
||||
switch (op) {
|
||||
case NET_STACK_CONNECT:
|
||||
{
|
||||
sockaddr_storage address;
|
||||
sockaddr_args args;
|
||||
status = check_args_and_address(args, address, data, length);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
status = sSocket->connect(cookie->socket, args.address,
|
||||
args.address_length);
|
||||
|
||||
return syscall_restart_ioctl_handle_post(status);
|
||||
}
|
||||
|
||||
case NET_STACK_BIND:
|
||||
{
|
||||
sockaddr_storage address;
|
||||
sockaddr_args args;
|
||||
status = check_args_and_address(args, address, data, length);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
return sSocket->bind(cookie->socket, args.address,
|
||||
args.address_length);
|
||||
}
|
||||
|
||||
case NET_STACK_LISTEN:
|
||||
// backlog to set
|
||||
return sSocket->listen(cookie->socket, (int)data);
|
||||
|
||||
case NET_STACK_ACCEPT:
|
||||
{
|
||||
int kernel = IS_KERNEL_ADDRESS(data);
|
||||
sockaddr_storage address;
|
||||
accept_args args;
|
||||
|
||||
status = check_args_and_address(args, address, data, length,
|
||||
false);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
net_stack_cookie *acceptCookie;
|
||||
status = resolve_cookie(kernel, args.accept_socket,
|
||||
&acceptCookie);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
status = sSocket->accept(cookie->socket, args.address,
|
||||
&args.address_length, &acceptCookie->socket);
|
||||
|
||||
if (status < B_OK)
|
||||
return syscall_restart_ioctl_handle_post(status);
|
||||
|
||||
return return_address(args, data);
|
||||
}
|
||||
|
||||
case NET_STACK_SHUTDOWN:
|
||||
return sSocket->shutdown(cookie->socket, (int)data);
|
||||
|
||||
case NET_STACK_SEND:
|
||||
{
|
||||
sockaddr_storage address;
|
||||
message_args args;
|
||||
msghdr header;
|
||||
|
||||
status = check_message_args(args, header, address, data,
|
||||
length, NULL);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
ssize_t bytesSent = sSocket->send(cookie->socket,
|
||||
args.header ? &header : NULL,
|
||||
args.data, args.length, args.flags);
|
||||
|
||||
return syscall_restart_ioctl_handle_post(bytesSent);
|
||||
}
|
||||
|
||||
case NET_STACK_RECEIVE:
|
||||
{
|
||||
sockaddr *originalAddress = NULL;
|
||||
sockaddr_storage address;
|
||||
message_args args;
|
||||
msghdr header;
|
||||
|
||||
status = check_message_args(args, header, address, data,
|
||||
length, &originalAddress);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
ssize_t bytesRead = sSocket->receive(cookie->socket,
|
||||
args.header ? &header : NULL, args.data,
|
||||
args.length, args.flags);
|
||||
if (bytesRead < B_OK)
|
||||
return syscall_restart_ioctl_handle_post(bytesRead);
|
||||
|
||||
if (args.header != NULL) {
|
||||
if (header.msg_name != NULL) {
|
||||
if (user_memcpy(originalAddress, header.msg_name,
|
||||
header.msg_namelen) < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
}
|
||||
|
||||
if (user_memcpy(&args.header->msg_flags, &header.msg_flags,
|
||||
sizeof(int)) < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
}
|
||||
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
case NET_STACK_GETSOCKOPT:
|
||||
{
|
||||
sockopt_args args;
|
||||
status = check_args(args, data, length);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
char valueBuffer[256];
|
||||
if (args.length > (int)sizeof(valueBuffer))
|
||||
return ENOBUFS;
|
||||
|
||||
status = sSocket->getsockopt(cookie->socket, args.level,
|
||||
args.option, valueBuffer, &args.length);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
if (user_memcpy(args.value, valueBuffer, args.length) < B_OK
|
||||
|| user_memcpy(&((sockopt_args *)data)->length,
|
||||
&args.length, sizeof(int)) < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
case NET_STACK_SETSOCKOPT:
|
||||
{
|
||||
sockopt_args args;
|
||||
status = check_args(args, data, length);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
char valueBuffer[256];
|
||||
if (args.length > (int)sizeof(valueBuffer))
|
||||
return ENOBUFS;
|
||||
if (user_memcpy(valueBuffer, args.value, args.length) < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
|
||||
return sSocket->setsockopt(cookie->socket, args.level,
|
||||
args.option, valueBuffer, args.length);
|
||||
}
|
||||
|
||||
case NET_STACK_GETSOCKNAME:
|
||||
{
|
||||
sockaddr_storage address;
|
||||
sockaddr_args args;
|
||||
status = check_args_and_address(args, address, data, length,
|
||||
false);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
status = sSocket->getsockname(cookie->socket, args.address,
|
||||
&args.address_length);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
return return_address(args, data);
|
||||
}
|
||||
|
||||
case NET_STACK_GETPEERNAME:
|
||||
{
|
||||
sockaddr_storage address;
|
||||
sockaddr_args args;
|
||||
status = check_args_and_address(args, address, data, length,
|
||||
false);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
status = sSocket->getpeername(cookie->socket, args.address,
|
||||
&args.address_length);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
return return_address(args, data);
|
||||
}
|
||||
|
||||
case FIONBIO:
|
||||
{
|
||||
int value = (int)data;
|
||||
return sSocket->setsockopt(cookie->socket, SOL_SOCKET,
|
||||
SO_NONBLOCK, &value, sizeof(int));
|
||||
}
|
||||
|
||||
case B_SET_BLOCKING_IO:
|
||||
case B_SET_NONBLOCKING_IO:
|
||||
{
|
||||
int value = op == B_SET_NONBLOCKING_IO;
|
||||
return sSocket->setsockopt(cookie->socket, SOL_SOCKET,
|
||||
SO_NONBLOCK, &value, sizeof(int));
|
||||
}
|
||||
|
||||
default:
|
||||
if (op < NET_STACK_IOCTL_BASE || op > NET_STACK_IOCTL_END) {
|
||||
// we only accept networking ioctl()s to get into our stack
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
return sSocket->control(cookie->socket, op, data, length);
|
||||
}
|
||||
}
|
||||
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
net_stack_read(void *_cookie, off_t /*offset*/, void *buffer, size_t *_length)
|
||||
{
|
||||
net_stack_cookie *cookie = (net_stack_cookie *)_cookie;
|
||||
|
||||
TRACE("net_stack_read(%p, %p, %ld)\n", cookie, buffer, *_length);
|
||||
|
||||
if (cookie->socket == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
ssize_t bytesRead = sSocket->receive(cookie->socket, NULL, buffer, *_length,
|
||||
0);
|
||||
if (bytesRead < 0) {
|
||||
*_length = 0;
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
*_length = bytesRead;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
net_stack_readv(void *_cookie, off_t /*offset*/, const struct iovec *vecs,
|
||||
size_t count, size_t *_length)
|
||||
{
|
||||
net_stack_cookie *cookie = (net_stack_cookie *)_cookie;
|
||||
|
||||
TRACE("net_stack_readv(%p, (%p, %lu), %ld)\n", cookie, vecs, count, *_length);
|
||||
|
||||
if (cookie->socket == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
return sSocket->readv(cookie->socket, vecs, count, _length);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
net_stack_write(void *_cookie, off_t /*offset*/, const void *buffer,
|
||||
size_t *_length)
|
||||
{
|
||||
net_stack_cookie *cookie = (net_stack_cookie *)_cookie;
|
||||
|
||||
TRACE("net_stack_write(%p, %p, %ld)\n", cookie, buffer, *_length);
|
||||
|
||||
if (cookie->socket == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
ssize_t bytesWritten = sSocket->send(cookie->socket, NULL, buffer, *_length,
|
||||
0);
|
||||
if (bytesWritten < 0) {
|
||||
*_length = 0;
|
||||
return bytesWritten;
|
||||
}
|
||||
|
||||
*_length = bytesWritten;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
net_stack_writev(void *_cookie, off_t /*offset*/, const struct iovec *vecs,
|
||||
size_t count, size_t *_length)
|
||||
{
|
||||
net_stack_cookie *cookie = (net_stack_cookie *)_cookie;
|
||||
|
||||
TRACE("net_stack_writev(%p, (%p, %lu), %ld)\n", cookie, vecs, count, *_length);
|
||||
|
||||
if (cookie->socket == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
return sSocket->writev(cookie->socket, vecs, count, _length);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
net_stack_select(void *_cookie, uint8 event, uint32 ref, selectsync *sync)
|
||||
{
|
||||
net_stack_cookie *cookie = (net_stack_cookie *)_cookie;
|
||||
|
||||
TRACE("net_stack_select(%p, %d, %ld, %p)\n", cookie, event, ref, sync);
|
||||
|
||||
if (cookie->socket == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
return sSocket->request_notification(cookie->socket, event, ref, sync);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
net_stack_deselect(void *_cookie, uint8 event, selectsync *sync)
|
||||
{
|
||||
net_stack_cookie *cookie = (net_stack_cookie *)_cookie;
|
||||
|
||||
TRACE("net_stack_deselect(%p, %d, %p)\n", cookie, event, sync);
|
||||
|
||||
if (cookie->socket == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
return sSocket->cancel_notification(cookie->socket, event, sync);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - driver
|
||||
|
||||
|
||||
status_t
|
||||
init_hardware(void)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
init_driver(void)
|
||||
{
|
||||
sInitializationSem = create_sem(1, "net stack init");
|
||||
if (sInitializationSem < B_OK)
|
||||
return sInitializationSem;
|
||||
|
||||
sInitializationStatus = B_NO_INIT;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
uninit_driver(void)
|
||||
{
|
||||
delete_sem(sInitializationSem);
|
||||
}
|
||||
|
||||
|
||||
const char **
|
||||
publish_devices(void)
|
||||
{
|
||||
static const char *devices[] = {
|
||||
NET_STACK_DRIVER_DEVICE,
|
||||
NULL
|
||||
};
|
||||
|
||||
return devices;
|
||||
}
|
||||
|
||||
|
||||
device_hooks*
|
||||
find_device(const char* device_name)
|
||||
{
|
||||
static device_hooks hooks = {
|
||||
net_stack_open,
|
||||
net_stack_close,
|
||||
net_stack_free_cookie,
|
||||
net_stack_control,
|
||||
net_stack_read,
|
||||
net_stack_write,
|
||||
net_stack_select,
|
||||
net_stack_deselect,
|
||||
net_stack_readv,
|
||||
net_stack_writev,
|
||||
};
|
||||
|
||||
return &hooks;
|
||||
}
|
@ -1,834 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2006, Haiku, Inc. All Rights Reserved.
|
||||
* This file may be used under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
/*!
|
||||
This file implements a very simple socket driver
|
||||
that is intended to act as an interface to the networking stack when
|
||||
it is loaded in userland, hosted by a net_server-like app.
|
||||
The communication is slow, and could probably be much better, but it's
|
||||
working, and that should be enough for now.
|
||||
*/
|
||||
|
||||
#ifndef _KERNEL_MODE
|
||||
# error "This module MUST be built as a kernel driver!"
|
||||
#endif
|
||||
|
||||
#include <net_stack_driver.h>
|
||||
#include <userland_ipc.h>
|
||||
#include <sys/sockio.h>
|
||||
|
||||
#include <Drivers.h>
|
||||
#include <KernelExport.h>
|
||||
#include <driver_settings.h>
|
||||
|
||||
#include <netinet/in_var.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#define DEBUG_PREFIX "userland_net_server: "
|
||||
#define __out dprintf
|
||||
|
||||
#define DEBUG 1
|
||||
#ifdef DEBUG
|
||||
#define PRINT(x) { __out(DEBUG_PREFIX); __out x; }
|
||||
#define REPORT_ERROR(status) __out(DEBUG_PREFIX "%s:%ld: %s\n",__FUNCTION__,__LINE__,strerror(status));
|
||||
#define RETURN_ERROR(err) { status_t _status = err; if (_status < B_OK) REPORT_ERROR(_status); return _status;}
|
||||
#define FATAL(x) { __out(DEBUG_PREFIX); __out x; }
|
||||
#define INFORM(x) { __out(DEBUG_PREFIX); __out x; }
|
||||
#define FUNCTION() __out(DEBUG_PREFIX "%s()\n",__FUNCTION__);
|
||||
#define FUNCTION_START(x) { __out(DEBUG_PREFIX "%s() ",__FUNCTION__); __out x; }
|
||||
// #define FUNCTION() ;
|
||||
// #define FUNCTION_START(x) ;
|
||||
#define D(x) {x;};
|
||||
#else
|
||||
#define PRINT(x) ;
|
||||
#define REPORT_ERROR(status) ;
|
||||
#define RETURN_ERROR(status) return status;
|
||||
#define FATAL(x) { __out(DEBUG_PREFIX); __out x; }
|
||||
#define INFORM(x) { __out(DEBUG_PREFIX); __out x; }
|
||||
#define FUNCTION() ;
|
||||
#define FUNCTION_START(x) ;
|
||||
#define D(x) ;
|
||||
#endif
|
||||
|
||||
#define NET_SERVER_DRIVER_DEV "net/userland_server"
|
||||
|
||||
/* wait one second when waiting on the stack */
|
||||
#define STACK_TIMEOUT 1000000LL
|
||||
|
||||
#ifdef COMPILE_FOR_R5
|
||||
typedef status_t (*notify_select_event_function)(selectsync * sync, uint32 ref);
|
||||
#else
|
||||
typedef status_t (*notify_select_event_function)(selectsync * sync, uint32 ref, uint8 event);
|
||||
#endif
|
||||
|
||||
|
||||
// this struct will store one select() event to monitor per thread
|
||||
typedef struct selecter {
|
||||
struct selecter * next;
|
||||
thread_id thread;
|
||||
uint32 event;
|
||||
selectsync * sync;
|
||||
uint32 ref;
|
||||
} selecter;
|
||||
|
||||
|
||||
// the cookie we attach to each file descriptor opened on our driver entry
|
||||
typedef struct {
|
||||
port_id local_port;
|
||||
port_id remote_port;
|
||||
area_id area;
|
||||
thread_id socket_thread;
|
||||
|
||||
sem_id command_sem;
|
||||
net_command *commands;
|
||||
int32 command_index;
|
||||
int32 nb_commands;
|
||||
|
||||
sem_id selecters_lock; // protect the selecters linked-list
|
||||
selecter * selecters; // the select()'ers lists (thread-aware)
|
||||
} net_server_cookie;
|
||||
|
||||
/* device hooks */
|
||||
static status_t net_server_open(const char *name, uint32 flags, void **cookie);
|
||||
static status_t net_server_close(void *cookie);
|
||||
static status_t net_server_free_cookie(void *cookie);
|
||||
static status_t net_server_control(void *cookie, uint32 msg, void *data, size_t datalen);
|
||||
static status_t net_server_read(void *cookie, off_t pos, void *data, size_t *datalen);
|
||||
static status_t net_server_write(void *cookie, off_t pos, const void *data, size_t *datalen);
|
||||
static status_t net_server_select(void *cookie, uint8 event, uint32 ref, selectsync *sync);
|
||||
static status_t net_server_deselect(void *cookie, uint8 event, selectsync *sync);
|
||||
|
||||
/* select() support */
|
||||
static int32 socket_event_listener(void *data);
|
||||
static void on_socket_event(void *socket, uint32 event, void *cookie);
|
||||
static status_t r5_notify_select_event(selectsync *sync, uint32 ref, uint8 event);
|
||||
|
||||
/* command queue */
|
||||
static status_t init_connection(void **cookie);
|
||||
static void shutdown_connection(net_server_cookie *nsc);
|
||||
static net_command *get_command(net_server_cookie *nsc, int32 *index);
|
||||
static status_t execute_command(net_server_cookie *nsc, uint32 op, void *data, uint32 length);
|
||||
|
||||
|
||||
int32 api_version = B_CUR_DRIVER_API_VERSION;
|
||||
|
||||
// by default, assert we can use kernel select() support
|
||||
notify_select_event_function g_nse = notify_select_event;
|
||||
thread_id sSocketEventThread = -1;
|
||||
port_id sSocketEventPort = -1;
|
||||
|
||||
static port_id sUserlandPort = -1;
|
||||
|
||||
|
||||
// #pragma mark - driver
|
||||
|
||||
|
||||
status_t
|
||||
init_hardware(void)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
init_driver(void)
|
||||
{
|
||||
thread_id thread;
|
||||
port_id port;
|
||||
|
||||
FUNCTION();
|
||||
|
||||
port = create_port(32, "socket_event_listener");
|
||||
if (port < B_OK)
|
||||
return port;
|
||||
set_port_owner(port, B_SYSTEM_TEAM);
|
||||
|
||||
thread = spawn_kernel_thread(socket_event_listener, "socket_event_listener",
|
||||
B_NORMAL_PRIORITY, NULL);
|
||||
if (thread < B_OK) {
|
||||
delete_port(port);
|
||||
return thread;
|
||||
}
|
||||
|
||||
sSocketEventThread = thread;
|
||||
sSocketEventPort = port;
|
||||
|
||||
return resume_thread(thread);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
uninit_driver(void)
|
||||
{
|
||||
FUNCTION();
|
||||
|
||||
delete_port(sSocketEventPort);
|
||||
|
||||
status_t dummy;
|
||||
wait_for_thread(sSocketEventThread, &dummy);
|
||||
}
|
||||
|
||||
|
||||
const char **
|
||||
publish_devices(void)
|
||||
{
|
||||
FUNCTION();
|
||||
static const char *deviceNames[] = {
|
||||
"net/userland_server",
|
||||
NULL
|
||||
};
|
||||
|
||||
return deviceNames;
|
||||
}
|
||||
|
||||
|
||||
device_hooks *
|
||||
find_device(const char *deviceName)
|
||||
{
|
||||
FUNCTION();
|
||||
device_hooks hooks = {
|
||||
net_server_open,
|
||||
net_server_close,
|
||||
net_server_free_cookie,
|
||||
net_server_control,
|
||||
net_server_read,
|
||||
net_server_write,
|
||||
net_server_select,
|
||||
net_server_deselect,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
return &hooks;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
//*****************************************************/
|
||||
// Device hooks
|
||||
//*****************************************************/
|
||||
|
||||
|
||||
static status_t
|
||||
net_server_open(const char *name, uint32 flags, void **cookie)
|
||||
{
|
||||
net_server_cookie *nsc;
|
||||
|
||||
status_t status = init_connection(cookie);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
nsc = *cookie;
|
||||
|
||||
status = execute_command(nsc, NET_STACK_OPEN, &flags, sizeof(uint32));
|
||||
if (status < B_OK)
|
||||
net_server_free_cookie(nsc);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
net_server_close(void *cookie)
|
||||
{
|
||||
net_server_cookie *nsc = cookie;
|
||||
if (nsc == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// we don't care here if the stack isn't alive anymore -
|
||||
// from the kernel's point of view, the device can always
|
||||
// be closed
|
||||
execute_command(nsc, NET_STACK_CLOSE, NULL, 0);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
net_server_free_cookie(void *cookie)
|
||||
{
|
||||
net_server_cookie *nsc = cookie;
|
||||
if (nsc == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
shutdown_connection(nsc);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
net_server_control(void *cookie, uint32 op, void *data, size_t length)
|
||||
{
|
||||
net_server_cookie *nsc = cookie;
|
||||
struct stack_driver_args *args = data;
|
||||
|
||||
//FUNCTION_START(("cookie = %p, op = %lx, data = %p, length = %ld\n", cookie, op, data, length));
|
||||
|
||||
if (nsc == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
switch (op) {
|
||||
case NET_STACK_SELECT:
|
||||
// if we get this call via ioctl() we are obviously called from an
|
||||
// R5 compatible libnet: we are using the r5 kernel select() call,
|
||||
// So, we can't use the kernel notify_select_event(), but our own implementation!
|
||||
g_nse = r5_notify_select_event;
|
||||
return net_server_select(cookie, (args->u.select.ref & 0x0F), args->u.select.ref, args->u.select.sync);
|
||||
|
||||
case NET_STACK_DESELECT:
|
||||
return net_server_deselect(cookie, (args->u.select.ref & 0x0F), args->u.select.sync);
|
||||
|
||||
default:
|
||||
return execute_command(nsc, op, data, -1);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
net_server_read(void *cookie, off_t pos, void *buffer, size_t *length)
|
||||
{
|
||||
net_server_cookie *nsc = cookie;
|
||||
struct stack_driver_args args;
|
||||
int status;
|
||||
|
||||
memset(&args, 0, sizeof(args));
|
||||
args.u.transfer.data = buffer;
|
||||
args.u.transfer.datalen = *length;
|
||||
|
||||
status = execute_command(nsc, NET_STACK_RECV, &args, sizeof(args));
|
||||
if (status > 0) {
|
||||
*length = status;
|
||||
return B_OK;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
net_server_write(void *cookie, off_t pos, const void *buffer, size_t *length)
|
||||
{
|
||||
net_server_cookie *nsc = cookie;
|
||||
struct stack_driver_args args;
|
||||
int status;
|
||||
|
||||
memset(&args, 0, sizeof(args));
|
||||
args.u.transfer.data = (void *) buffer;
|
||||
args.u.transfer.datalen = *length;
|
||||
|
||||
status = execute_command(nsc, NET_STACK_SEND, &args, sizeof(args));
|
||||
if (status > 0) {
|
||||
*length = status;
|
||||
return B_OK;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
net_server_select(void *cookie, uint8 event, uint32 ref, selectsync *sync)
|
||||
{
|
||||
net_server_cookie *nsc = cookie;
|
||||
struct notify_socket_event_args args;
|
||||
selecter *s;
|
||||
status_t status;
|
||||
|
||||
FUNCTION_START(("cookie = %p, event = %d, ref = %lx, sync =%p\n", cookie, event, ref, sync));
|
||||
|
||||
s = (selecter *) malloc(sizeof(selecter));
|
||||
if (!s)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
|
||||
// lock the selecters list
|
||||
status = acquire_sem(nsc->selecters_lock);
|
||||
if (status != B_OK) {
|
||||
free(s);
|
||||
return status;
|
||||
};
|
||||
|
||||
s->thread = find_thread(NULL); // current thread id
|
||||
s->event = event;
|
||||
s->sync = sync;
|
||||
s->ref = ref;
|
||||
|
||||
// add it to selecters list
|
||||
s->next = nsc->selecters;
|
||||
nsc->selecters = s;
|
||||
|
||||
// unlock the selecters list
|
||||
release_sem(nsc->selecters_lock);
|
||||
|
||||
// Tell the net_server to notify event(s) for this socket
|
||||
memset(&args, 0, sizeof(args));
|
||||
args.notify_port = sSocketEventPort;
|
||||
args.cookie = cookie;;
|
||||
|
||||
return execute_command(nsc, NET_STACK_NOTIFY_SOCKET_EVENT, &args, sizeof(args));
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
net_server_deselect(void *cookie, uint8 event, selectsync *sync)
|
||||
{
|
||||
net_server_cookie *nsc = cookie;
|
||||
selecter *previous;
|
||||
selecter *s;
|
||||
thread_id current_thread;
|
||||
status_t status;
|
||||
|
||||
FUNCTION_START(("cookie = %p, event = %d, sync =%p\n", cookie, event, sync));
|
||||
|
||||
if (!nsc)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
current_thread = find_thread(NULL);
|
||||
|
||||
// lock the selecters list
|
||||
status = acquire_sem(nsc->selecters_lock);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
previous = NULL;
|
||||
s = nsc->selecters;
|
||||
while (s) {
|
||||
if (s->thread == current_thread &&
|
||||
s->event == event && s->sync == sync)
|
||||
// selecter found!
|
||||
break;
|
||||
|
||||
previous = s;
|
||||
s = s->next;
|
||||
};
|
||||
|
||||
if (s != NULL) {
|
||||
// remove it from selecters list
|
||||
if (previous)
|
||||
previous->next = s->next;
|
||||
else
|
||||
nsc->selecters = s->next;
|
||||
free(s);
|
||||
};
|
||||
|
||||
status = B_OK;
|
||||
if (nsc->selecters == NULL) {
|
||||
struct notify_socket_event_args args;
|
||||
|
||||
// Selecters list is empty: no need to monitor socket events anymore
|
||||
// Tell the net_server to stop notifying event(s) for this socket
|
||||
memset(&args, 0, sizeof(args));
|
||||
args.notify_port = -1; // stop notifying
|
||||
args.cookie = cookie; // for sanity check
|
||||
status = execute_command(nsc, NET_STACK_NOTIFY_SOCKET_EVENT, &args, sizeof(args));
|
||||
};
|
||||
|
||||
// unlock the selecters list
|
||||
release_sem(nsc->selecters_lock);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
//*****************************************************/
|
||||
// select() support
|
||||
//*****************************************************/
|
||||
|
||||
/*
|
||||
This is started as separate thread at init_driver() time to wait for
|
||||
socket event notification.
|
||||
|
||||
One port to listen them all.
|
||||
One port to find them.
|
||||
One port to get them and in [r5_]notify_select_event() send them.
|
||||
|
||||
Okay, I should stop watch this movie *now*.
|
||||
*/
|
||||
|
||||
static int32 socket_event_listener(void *data)
|
||||
{
|
||||
struct socket_event_data sed;
|
||||
int32 msg;
|
||||
ssize_t bytes;
|
||||
|
||||
while(true) {
|
||||
bytes = read_port(sSocketEventPort, &msg, &sed, sizeof(sed));
|
||||
if (bytes < B_OK)
|
||||
return bytes;
|
||||
|
||||
if (msg == NET_STACK_SOCKET_EVENT_NOTIFICATION)
|
||||
// yep, we pass a NULL "socket" pointer here, but don't worry, we don't use anyway
|
||||
on_socket_event(NULL, sed.event, sed.cookie);
|
||||
};
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void on_socket_event(void *socket, uint32 event, void *cookie)
|
||||
{
|
||||
net_server_cookie *nsc = cookie;
|
||||
selecter *s;
|
||||
|
||||
if (!nsc)
|
||||
return;
|
||||
|
||||
FUNCTION_START(("socket = %p, event = %ld, cookie = %p\n", socket, event, cookie));
|
||||
|
||||
// lock the selecters list
|
||||
if (acquire_sem(nsc->selecters_lock) != B_OK)
|
||||
return;
|
||||
|
||||
s = nsc->selecters;
|
||||
while (s) {
|
||||
if (s->event == event)
|
||||
// notify this selecter (thread/event pair)
|
||||
#ifdef COMPILE_FOR_R5
|
||||
g_nse(s->sync, s->ref);
|
||||
#else
|
||||
g_nse(s->sync, s->ref, (uint8) event);
|
||||
#endif
|
||||
s = s->next;
|
||||
};
|
||||
|
||||
// unlock the selecters list
|
||||
release_sem(nsc->selecters_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Under vanilla R5, we can't use the kernel notify_select_event(),
|
||||
as select() kernel implementation is too buggy to be usefull.
|
||||
So, here is our own notify_select_event() implementation, the driver-side pair
|
||||
of the our libnet.so select() implementation...
|
||||
*/
|
||||
static status_t r5_notify_select_event(selectsync *sync, uint32 ref, uint8 event)
|
||||
{
|
||||
area_id area;
|
||||
struct r5_selectsync *rss;
|
||||
int fd;
|
||||
|
||||
FUNCTION_START(("sync = %p, ref = %lx\n", sync, ref));
|
||||
|
||||
rss = NULL;
|
||||
area = clone_area("r5_selectsync_area (driver)", (void **) &rss,
|
||||
B_ANY_KERNEL_ADDRESS, B_READ_AREA | B_WRITE_AREA, (area_id) sync);
|
||||
if (area < B_OK) {
|
||||
#if SHOW_INSANE_DEBUGGING
|
||||
dprintf(LOGID "r5_notify_select_event: clone_area(%d) failed -> %d!\n", (area_id) sync, area);
|
||||
#endif
|
||||
return area;
|
||||
};
|
||||
|
||||
#if SHOW_INSANE_DEBUGGING
|
||||
dprintf(LOGID "r5_selectsync at %p (area %ld, clone from %ld):\n"
|
||||
"lock %ld\n"
|
||||
"wakeup %ld\n", rss, area, (area_id) sync, rss->lock, rss->wakeup);
|
||||
#endif
|
||||
|
||||
if (acquire_sem(rss->lock) != B_OK)
|
||||
// if we can't (anymore?) lock the shared r5_selectsync, select() party is done
|
||||
goto error;
|
||||
|
||||
fd = ref >> 8;
|
||||
switch (ref & 0xFF) { // event == ref & 0xFF !
|
||||
case B_SELECT_READ:
|
||||
FD_SET(fd, &rss->rbits);
|
||||
break;
|
||||
case B_SELECT_WRITE:
|
||||
FD_SET(fd, &rss->wbits);
|
||||
break;
|
||||
case B_SELECT_ERROR:
|
||||
FD_SET(fd, &rss->ebits);
|
||||
break;
|
||||
};
|
||||
|
||||
// wakeup select()
|
||||
release_sem(rss->wakeup);
|
||||
|
||||
release_sem(rss->lock);
|
||||
|
||||
error:
|
||||
delete_area(area);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
//*****************************************************/
|
||||
// The Command Queue
|
||||
//*****************************************************/
|
||||
|
||||
|
||||
static net_command *
|
||||
get_command(net_server_cookie *nsc, int32 *index)
|
||||
{
|
||||
int32 i, count = 0;
|
||||
net_command *command;
|
||||
|
||||
while (count < nsc->nb_commands*2) {
|
||||
i = atomic_add(&nsc->command_index,1) & (nsc->nb_commands - 1);
|
||||
command = nsc->commands + i;
|
||||
|
||||
if (command->op == 0) {
|
||||
// command is free to use
|
||||
*index = i;
|
||||
return command;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
get_area_from_address(net_area_info *info, void *data)
|
||||
{
|
||||
area_info areaInfo;
|
||||
|
||||
if (data == NULL)
|
||||
return B_OK;
|
||||
|
||||
info->id = area_for(data);
|
||||
if (info->id < B_OK)
|
||||
return info->id;
|
||||
|
||||
if (get_area_info(info->id,&areaInfo) != B_OK)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
info->offset = areaInfo.address;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
set_command_areas(net_command *command)
|
||||
{
|
||||
struct stack_driver_args *args = (void *) command->data;
|
||||
|
||||
if (args == NULL)
|
||||
return;
|
||||
|
||||
if (get_area_from_address(&command->area[0], args) < B_OK)
|
||||
return;
|
||||
|
||||
switch (command->op) {
|
||||
case NET_STACK_GETSOCKOPT:
|
||||
case NET_STACK_SETSOCKOPT:
|
||||
get_area_from_address(&command->area[1], args->u.sockopt.optval);
|
||||
break;
|
||||
|
||||
case NET_STACK_CONNECT:
|
||||
case NET_STACK_BIND:
|
||||
case NET_STACK_GETSOCKNAME:
|
||||
case NET_STACK_GETPEERNAME:
|
||||
get_area_from_address(&command->area[1], args->u.sockaddr.addr);
|
||||
break;
|
||||
|
||||
case NET_STACK_RECV:
|
||||
case NET_STACK_SEND:
|
||||
get_area_from_address(&command->area[1], args->u.transfer.data);
|
||||
get_area_from_address(&command->area[2], args->u.transfer.addr);
|
||||
break;
|
||||
|
||||
case NET_STACK_RECVFROM:
|
||||
case NET_STACK_SENDTO: {
|
||||
struct msghdr *mh = (void *) args;
|
||||
get_area_from_address(&command->area[1],mh->msg_name);
|
||||
get_area_from_address(&command->area[2],mh->msg_iov);
|
||||
get_area_from_address(&command->area[3],mh->msg_control);
|
||||
break;
|
||||
}
|
||||
|
||||
case NET_STACK_ACCEPT:
|
||||
/* accept_args.cookie is always in the address space of the server */
|
||||
get_area_from_address(&command->area[1], args->u.accept.addr);
|
||||
break;
|
||||
|
||||
case NET_STACK_SYSCTL:
|
||||
get_area_from_address(&command->area[1], args->u.sysctl.name);
|
||||
get_area_from_address(&command->area[2], args->u.sysctl.oldp);
|
||||
get_area_from_address(&command->area[3], args->u.sysctl.oldlenp);
|
||||
get_area_from_address(&command->area[4], args->u.sysctl.newp);
|
||||
break;
|
||||
|
||||
case NET_STACK_CONTROL_NET_MODULE:
|
||||
// TODO!
|
||||
break;
|
||||
|
||||
case OSIOCGIFCONF:
|
||||
case SIOCGIFCONF: {
|
||||
struct ifconf *ifc = (void *) args;
|
||||
|
||||
get_area_from_address(&command->area[1], ifc->ifc_buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
execute_command(net_server_cookie *nsc, uint32 op, void *data, uint32 length)
|
||||
{
|
||||
uint32 command_index;
|
||||
net_command *command = get_command(nsc, (long *) &command_index);
|
||||
int32 max_tries = 200;
|
||||
status_t status;
|
||||
ssize_t bytes;
|
||||
|
||||
if (command == NULL) {
|
||||
FATAL(("execute: command queue is full\n"));
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
memset(command, 0, sizeof(net_command));
|
||||
|
||||
command->op = op;
|
||||
command->data = data;
|
||||
set_command_areas(command);
|
||||
|
||||
bytes = write_port(nsc->remote_port, command_index, NULL, 0);
|
||||
if (bytes < B_OK) {
|
||||
FATAL(("execute %ld: couldn't contact stack (id = %ld): %s\n",op, nsc->remote_port, strerror(bytes)));
|
||||
return bytes;
|
||||
}
|
||||
|
||||
// if we're closing the connection, there is no need to
|
||||
// wait for a result
|
||||
if (op == NET_STACK_CLOSE)
|
||||
return B_OK;
|
||||
|
||||
while (true) {
|
||||
// wait until we get the results back from our command
|
||||
if ((status = acquire_sem_etc(nsc->command_sem, 1, B_CAN_INTERRUPT, 0)) == B_OK) {
|
||||
if (command->op != 0) {
|
||||
if (--max_tries <= 0) {
|
||||
FATAL(("command is not freed after 200 tries!\n"));
|
||||
return B_ERROR;
|
||||
}
|
||||
release_sem(nsc->command_sem);
|
||||
continue;
|
||||
}
|
||||
return command->result;
|
||||
}
|
||||
FATAL(("command couldn't be executed: %s\n", strerror(status)));
|
||||
if (status == B_INTERRUPTED)
|
||||
// Signaling our net_server counterpart, so his socket thread awake too...
|
||||
send_signal_etc(nsc->socket_thread, SIGINT, 0);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
init_connection(void **cookie)
|
||||
{
|
||||
net_connection connection;
|
||||
ssize_t bytes;
|
||||
uint32 msg;
|
||||
|
||||
net_server_cookie *nsc = (net_server_cookie *) malloc(sizeof(net_server_cookie));
|
||||
if (nsc == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
// create a new port and get a connection from the stack
|
||||
|
||||
nsc->local_port = create_port(CONNECTION_QUEUE_LENGTH, "net_driver connection");
|
||||
if (nsc->local_port < B_OK) {
|
||||
FATAL(("open: couldn't create port: %s\n", strerror(nsc->local_port)));
|
||||
free(cookie);
|
||||
return B_ERROR;
|
||||
}
|
||||
set_port_owner(nsc->local_port, B_SYSTEM_TEAM);
|
||||
|
||||
bytes = write_port(sUserlandPort, NET_STACK_NEW_CONNECTION, &nsc->local_port, sizeof(port_id));
|
||||
if (bytes == B_BAD_PORT_ID) {
|
||||
sUserlandPort = find_port(NET_STACK_PORTNAME);
|
||||
PRINT(("try to get net_server's port id: %ld\n", sUserlandPort));
|
||||
bytes = write_port(sUserlandPort, NET_STACK_NEW_CONNECTION, &nsc->local_port, sizeof(port_id));
|
||||
}
|
||||
if (bytes < B_OK) {
|
||||
FATAL(("open: couldn't contact stack: %s\n",strerror(bytes)));
|
||||
delete_port(nsc->local_port);
|
||||
free(nsc);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
bytes = read_port_etc(nsc->local_port, &msg, &connection, sizeof(net_connection), B_TIMEOUT,STACK_TIMEOUT);
|
||||
if (bytes < B_OK) {
|
||||
FATAL(("open: didn't hear back from stack: %s\n",strerror(bytes)));
|
||||
delete_port(nsc->local_port);
|
||||
free(nsc);
|
||||
return bytes;
|
||||
}
|
||||
if (msg != NET_STACK_NEW_CONNECTION) {
|
||||
FATAL(("open: received wrong answer: %ld\n",msg));
|
||||
delete_port(nsc->local_port);
|
||||
free(nsc);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
// set up communication channels
|
||||
|
||||
// ToDo: close server connection if anything fails
|
||||
// -> could also be done by the server, if it doesn't receive NET_STACK_OPEN
|
||||
|
||||
nsc->remote_port = connection.port;
|
||||
nsc->command_sem = connection.commandSemaphore;
|
||||
nsc->area = clone_area("net connection buffer", (void **) &nsc->commands,
|
||||
B_CLONE_ADDRESS, B_READ_AREA | B_WRITE_AREA, connection.area);
|
||||
if (nsc->area < B_OK) {
|
||||
status_t err;
|
||||
FATAL(("couldn't clone command queue: %s\n", strerror(nsc->area)));
|
||||
err = nsc->area;
|
||||
delete_port(nsc->local_port);
|
||||
free(nsc);
|
||||
return err;
|
||||
}
|
||||
|
||||
nsc->socket_thread = connection.socket_thread;
|
||||
nsc->nb_commands = connection.numCommands;
|
||||
nsc->command_index = 0;
|
||||
nsc->selecters = NULL;
|
||||
|
||||
nsc->selecters_lock = create_sem(1, "socket_selecters_lock");
|
||||
if (nsc->selecters_lock < B_OK) {
|
||||
status_t err;
|
||||
FATAL(("couldn't create socket_selecters_lock semaphore: %s\n", strerror(nsc->selecters_lock)));
|
||||
err = nsc->selecters_lock;
|
||||
delete_port(nsc->local_port);
|
||||
delete_area(nsc->area);
|
||||
free(nsc);
|
||||
return err;
|
||||
}
|
||||
|
||||
*cookie = nsc;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
shutdown_connection(net_server_cookie *nsc)
|
||||
{
|
||||
selecter *s;
|
||||
|
||||
delete_area(nsc->area);
|
||||
delete_port(nsc->local_port);
|
||||
|
||||
// free the selecters list
|
||||
delete_sem(nsc->selecters_lock);
|
||||
s = nsc->selecters;
|
||||
while (s) {
|
||||
selecter * tmp = s;
|
||||
s = s->next;
|
||||
free(tmp);
|
||||
};
|
||||
|
||||
free(nsc);
|
||||
}
|
||||
|
@ -3,5 +3,4 @@ SubDir HAIKU_TOP src add-ons kernel network ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel network datalink_protocols ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel network devices ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel network protocols ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel network socket ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel network stack ;
|
||||
|
@ -1,8 +0,0 @@
|
||||
SubDir HAIKU_TOP src add-ons kernel network socket ;
|
||||
|
||||
UseHeaders $(TARGET_PRIVATE_KERNEL_HEADERS) : true ;
|
||||
UsePrivateHeaders net ;
|
||||
|
||||
KernelAddon socket :
|
||||
socket.cpp
|
||||
;
|
@ -1,371 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007, Haiku, Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Axel Dörfler, axeld@pinc-software.de
|
||||
*/
|
||||
|
||||
/*!
|
||||
The kernel socket API directly forwards all requests into the stack
|
||||
via the networking stack driver.
|
||||
*/
|
||||
|
||||
#include <socket_interface.h>
|
||||
|
||||
#include <net_stack_driver.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
int
|
||||
socket(int family, int type, int protocol)
|
||||
{
|
||||
int socket = open(NET_STACK_DRIVER_PATH, O_RDWR);
|
||||
if (socket < 0)
|
||||
return -1;
|
||||
|
||||
socket_args args;
|
||||
args.family = family;
|
||||
args.type = type;
|
||||
args.protocol = protocol;
|
||||
|
||||
if (ioctl(socket, NET_STACK_SOCKET, &args, sizeof(args)) < 0) {
|
||||
close(socket);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return socket;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
bind(int socket, const struct sockaddr *address, socklen_t addressLength)
|
||||
{
|
||||
sockaddr_args args;
|
||||
args.address = const_cast<struct sockaddr *>(address);
|
||||
args.address_length = addressLength;
|
||||
|
||||
return ioctl(socket, NET_STACK_BIND, &args, sizeof(args));
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
shutdown(int socket, int how)
|
||||
{
|
||||
return ioctl(socket, NET_STACK_SHUTDOWN, (void *)how, 0);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
connect(int socket, const struct sockaddr *address, socklen_t addressLength)
|
||||
{
|
||||
sockaddr_args args;
|
||||
args.address = const_cast<struct sockaddr *>(address);
|
||||
args.address_length = addressLength;
|
||||
|
||||
return ioctl(socket, NET_STACK_CONNECT, &args, sizeof(args));
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
listen(int socket, int backlog)
|
||||
{
|
||||
return ioctl(socket, NET_STACK_LISTEN, (void *)backlog, 0);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
accept(int socket, struct sockaddr *address, socklen_t *_addressLength)
|
||||
{
|
||||
int acceptSocket = open(NET_STACK_DRIVER_PATH, O_RDWR);
|
||||
if (acceptSocket < 0)
|
||||
return -1;
|
||||
|
||||
accept_args args;
|
||||
args.accept_socket = acceptSocket;
|
||||
args.address = address;
|
||||
args.address_length = _addressLength ? *_addressLength : 0;
|
||||
|
||||
if (ioctl(socket, NET_STACK_ACCEPT, &args, sizeof(args)) < 0) {
|
||||
close(acceptSocket);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (_addressLength != NULL)
|
||||
*_addressLength = args.address_length;
|
||||
|
||||
return acceptSocket;
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
recv(int socket, void *data, size_t length, int flags)
|
||||
{
|
||||
message_args args;
|
||||
args.data = data;
|
||||
args.length = length;
|
||||
args.flags = flags;
|
||||
args.header = NULL;
|
||||
|
||||
return ioctl(socket, NET_STACK_RECEIVE, &args, sizeof(args));
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
recvfrom(int socket, void *data, size_t length, int flags,
|
||||
struct sockaddr *address, socklen_t *_addressLength)
|
||||
{
|
||||
message_args args;
|
||||
msghdr header;
|
||||
|
||||
memset(&header, 0, sizeof(header));
|
||||
|
||||
args.data = data;
|
||||
args.length = length;
|
||||
args.flags = flags;
|
||||
args.header = &header;
|
||||
|
||||
header.msg_name = (char *)address;
|
||||
header.msg_namelen = _addressLength ? *_addressLength : 0;
|
||||
|
||||
ssize_t bytesReceived = ioctl(socket, NET_STACK_RECEIVE, &args, sizeof(args));
|
||||
if (bytesReceived < 0)
|
||||
return -1;
|
||||
|
||||
if (_addressLength != NULL)
|
||||
*_addressLength = header.msg_namelen;
|
||||
|
||||
return bytesReceived;
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
recvmsg(int socket, struct msghdr *message, int flags)
|
||||
{
|
||||
message_args args;
|
||||
|
||||
if (message == NULL || (message->msg_iovlen > 0 && message->msg_iov == NULL))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
args.header = message;
|
||||
args.flags = flags;
|
||||
|
||||
if (message->msg_iovlen > 0) {
|
||||
args.data = message->msg_iov[0].iov_base;
|
||||
args.length = message->msg_iov[0].iov_len;
|
||||
} else {
|
||||
args.data = NULL;
|
||||
args.length = 0;
|
||||
}
|
||||
|
||||
return ioctl(socket, NET_STACK_RECEIVE, &args, sizeof(args));
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
send(int socket, const void *data, size_t length, int flags)
|
||||
{
|
||||
message_args args;
|
||||
args.data = const_cast<void *>(data);
|
||||
args.length = length;
|
||||
args.flags = flags;
|
||||
args.header = NULL;
|
||||
|
||||
return ioctl(socket, NET_STACK_SEND, &args, sizeof(args));
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
sendto(int socket, const void *data, size_t length, int flags,
|
||||
const struct sockaddr *address, socklen_t addressLength)
|
||||
{
|
||||
message_args args;
|
||||
msghdr header;
|
||||
memset(&header, 0, sizeof(header));
|
||||
|
||||
args.data = const_cast<void *>(data);
|
||||
args.length = length;
|
||||
args.flags = flags;
|
||||
args.header = &header;
|
||||
header.msg_name = (char *)const_cast<sockaddr *>(address);
|
||||
header.msg_namelen = addressLength;
|
||||
|
||||
return ioctl(socket, NET_STACK_SEND, &args, sizeof(args));
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
sendmsg(int socket, const struct msghdr *message, int flags)
|
||||
{
|
||||
message_args args;
|
||||
|
||||
if (message == NULL || (message->msg_iovlen > 0 && message->msg_iov == NULL))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
args.header = (msghdr *)message;
|
||||
args.flags = flags;
|
||||
|
||||
if (message->msg_iovlen > 0) {
|
||||
args.data = message->msg_iov[0].iov_base;
|
||||
args.length = message->msg_iov[0].iov_len;
|
||||
} else {
|
||||
args.data = NULL;
|
||||
args.length = 0;
|
||||
}
|
||||
|
||||
return ioctl(socket, NET_STACK_SEND, &args, sizeof(args));
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
getsockopt(int socket, int level, int option, void *value, socklen_t *_length)
|
||||
{
|
||||
sockopt_args args;
|
||||
args.level = level;
|
||||
args.option = option;
|
||||
args.value = value;
|
||||
args.length = _length ? *_length : 0;
|
||||
|
||||
if (ioctl(socket, NET_STACK_GETSOCKOPT, &args, sizeof(args)) < 0)
|
||||
return -1;
|
||||
|
||||
if (_length)
|
||||
*_length = args.length;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
setsockopt(int socket, int level, int option, const void *value, socklen_t length)
|
||||
{
|
||||
sockopt_args args;
|
||||
args.level = level;
|
||||
args.option = option;
|
||||
args.value = const_cast<void *>(value);
|
||||
args.length = length;
|
||||
|
||||
return ioctl(socket, NET_STACK_SETSOCKOPT, &args, sizeof(args));
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
getpeername(int socket, struct sockaddr *address, socklen_t *_addressLength)
|
||||
{
|
||||
sockaddr_args args;
|
||||
args.address = address;
|
||||
args.address_length = _addressLength ? *_addressLength : 0;
|
||||
|
||||
if (ioctl(socket, NET_STACK_GETPEERNAME, &args, sizeof(args)) < 0)
|
||||
return -1;
|
||||
|
||||
if (_addressLength != NULL)
|
||||
*_addressLength = args.address_length;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
getsockname(int socket, struct sockaddr *address, socklen_t *_addressLength)
|
||||
{
|
||||
sockaddr_args args;
|
||||
args.address = address;
|
||||
args.address_length = _addressLength ? *_addressLength : 0;
|
||||
|
||||
if (ioctl(socket, NET_STACK_GETSOCKNAME, &args, sizeof(args)) < 0)
|
||||
return -1;
|
||||
|
||||
if (_addressLength != NULL)
|
||||
*_addressLength = args.address_length;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
sockatmark(int socket)
|
||||
{
|
||||
// TODO: implement me!
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
socketpair(int family, int type, int protocol, int socketVector[2])
|
||||
{
|
||||
socketVector[0] = socket(family, type, protocol);
|
||||
if (socketVector[0] < 0)
|
||||
return -1;
|
||||
|
||||
socketVector[1] = socket(family, type, protocol);
|
||||
if (socketVector[1] < 0)
|
||||
goto err1;
|
||||
|
||||
socketpair_args args;
|
||||
args.second_socket = socketVector[1];
|
||||
|
||||
if (ioctl(socketVector[0], NET_STACK_SOCKETPAIR, &args, sizeof(args)) < 0)
|
||||
goto err2;
|
||||
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
close(socketVector[1]);
|
||||
err1:
|
||||
close(socketVector[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
static status_t
|
||||
std_ops(int32 op, ...)
|
||||
{
|
||||
switch (op) {
|
||||
case B_MODULE_INIT:
|
||||
case B_MODULE_UNINIT:
|
||||
return B_OK;
|
||||
|
||||
default:
|
||||
return B_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static socket_module_info sSocketModule = {
|
||||
{
|
||||
B_SOCKET_MODULE_NAME,
|
||||
0,
|
||||
std_ops
|
||||
},
|
||||
|
||||
accept,
|
||||
bind,
|
||||
connect,
|
||||
getpeername,
|
||||
getsockname,
|
||||
getsockopt,
|
||||
listen,
|
||||
recv,
|
||||
recvfrom,
|
||||
recvmsg,
|
||||
send,
|
||||
sendmsg,
|
||||
sendto,
|
||||
setsockopt,
|
||||
shutdown,
|
||||
socket,
|
||||
sockatmark,
|
||||
socketpair,
|
||||
};
|
||||
|
||||
module_info *modules[] = {
|
||||
(module_info *)&sSocketModule,
|
||||
NULL
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user