First userland tesbed/net_server-like network stack app host commited.
Userland network modules build still not available, will come later. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@1912 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
40e492bc4c
commit
eca926b1cf
10
src/tests/servers/net/net_server/Jamfile
Normal file
10
src/tests/servers/net/net_server/Jamfile
Normal file
@ -0,0 +1,10 @@
|
||||
SubDir OBOS_TOP src tests servers net net_server ;
|
||||
|
||||
UsePrivateHeaders net ;
|
||||
|
||||
SimpleTest net_server :
|
||||
userland_modules.cpp
|
||||
userland_ipc.c
|
||||
net_server.cpp
|
||||
: be
|
||||
;
|
46
src/tests/servers/net/net_server/net_server.cpp
Normal file
46
src/tests/servers/net/net_server/net_server.cpp
Normal file
@ -0,0 +1,46 @@
|
||||
/* Userland modules emulation support
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <app/Application.h>
|
||||
#include <drivers/module.h>
|
||||
|
||||
#include <core_module.h>
|
||||
#include <userland_ipc.h>
|
||||
|
||||
struct core_module_info * core = NULL;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char buffer[8];
|
||||
int ret = -1;
|
||||
|
||||
new BApplication("application/x-vnd-OBOS-net_server");
|
||||
|
||||
if (init_userland_ipc() < B_OK)
|
||||
goto exit;
|
||||
|
||||
if (get_module(NET_CORE_MODULE_NAME, (module_info **) &core) != B_OK) {
|
||||
shutdown_userland_ipc();
|
||||
goto exit;
|
||||
}
|
||||
|
||||
puts("Starting core module...");
|
||||
core->start();
|
||||
|
||||
puts("Userland net stack (net_server) is running. Press <Return> to quit.");
|
||||
fgets(buffer,sizeof(buffer), stdin);
|
||||
|
||||
put_module(NET_CORE_MODULE_NAME);;
|
||||
shutdown_userland_ipc();
|
||||
|
||||
ret = 0;
|
||||
|
||||
exit:;
|
||||
delete be_app;
|
||||
return ret;
|
||||
}
|
||||
|
554
src/tests/servers/net/net_server/userland_ipc.c
Normal file
554
src/tests/servers/net/net_server/userland_ipc.c
Normal file
@ -0,0 +1,554 @@
|
||||
/* userland_ipc - Communication between the network driver
|
||||
** and the userland stack.
|
||||
**
|
||||
** Initial version by Axel Dörfler, axeld@pinc-software.de
|
||||
** This file may be used under the terms of the OpenBeOS License.
|
||||
*/
|
||||
|
||||
|
||||
#include "userland_ipc.h"
|
||||
|
||||
#include "sys/socket.h"
|
||||
#include "net_misc.h"
|
||||
#include "core_module.h"
|
||||
#include "net_module.h"
|
||||
#include "sys/sockio.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
extern struct core_module_info *core;
|
||||
|
||||
// installs a main()
|
||||
//#define COMMUNICATION_TEST
|
||||
|
||||
#define NUM_COMMANDS 32
|
||||
#define CONNECTION_BUFFER_SIZE (65536 + 4096 - CONNECTION_COMMAND_SIZE)
|
||||
|
||||
#define ROUND_TO_PAGE_SIZE(x) (((x) + (B_PAGE_SIZE) - 1) & ~((B_PAGE_SIZE) - 1))
|
||||
|
||||
struct socket; /* forward declaration */
|
||||
|
||||
typedef struct {
|
||||
port_id localPort,port;
|
||||
area_id area;
|
||||
struct socket * socket;
|
||||
|
||||
uint8 *buffer;
|
||||
net_command *commands;
|
||||
sem_id commandSemaphore;
|
||||
|
||||
int32 openFlags;
|
||||
|
||||
thread_id runner;
|
||||
|
||||
// for socket select events support
|
||||
port_id socket_event_port;
|
||||
void * notify_cookie;
|
||||
} connection_cookie;
|
||||
|
||||
|
||||
port_id gStackPort = -1;
|
||||
thread_id gConnectionOpener = -1;
|
||||
|
||||
// prototypes
|
||||
static int32 connection_runner(void *_cookie);
|
||||
static status_t init_connection(net_connection *connection, connection_cookie **_cookie);
|
||||
static void shutdown_connection(connection_cookie *cookie);
|
||||
|
||||
|
||||
static void
|
||||
delete_cloned_areas(net_area_info *area)
|
||||
{
|
||||
int32 i;
|
||||
for (i = 0;i < MAX_NET_AREAS;i++) {
|
||||
if (area[i].id == 0)
|
||||
continue;
|
||||
|
||||
delete_area(area[i].id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
clone_command_areas(net_area_info *localArea,net_command *command)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
memset(localArea,0,sizeof(net_area_info) * MAX_NET_AREAS);
|
||||
|
||||
for (i = 0;i < MAX_NET_AREAS;i++) {
|
||||
if (command->area[i].id <= 0)
|
||||
continue;
|
||||
|
||||
localArea[i].id = clone_area("net connection",(void **)&localArea[i].offset,B_ANY_ADDRESS,
|
||||
B_READ_AREA | B_WRITE_AREA,command->area[i].id);
|
||||
if (localArea[i].id < B_OK)
|
||||
return localArea[i].id;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static uint8 *
|
||||
convert_address(net_area_info *fromArea,net_area_info *toArea,uint8 *data)
|
||||
{
|
||||
if (data == NULL)
|
||||
return NULL;
|
||||
|
||||
if (data < fromArea->offset) {
|
||||
printf("could not translate address: %p\n",data);
|
||||
return data;
|
||||
}
|
||||
|
||||
return data - fromArea->offset + toArea->offset;
|
||||
}
|
||||
|
||||
|
||||
static inline void *
|
||||
convert_to_local(net_area_info *foreignArea,net_area_info *localArea,void *data)
|
||||
{
|
||||
return convert_address(foreignArea,localArea,data);
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
convert_to_foreign(net_area_info *foreignArea,net_area_info *localArea,void *data)
|
||||
{
|
||||
return convert_address(localArea,foreignArea,data);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
on_socket_event(void * socket, uint32 event, void * cookie)
|
||||
{
|
||||
connection_cookie * cc = (connection_cookie *) cookie;
|
||||
struct socket_event_data sed;
|
||||
status_t status;
|
||||
|
||||
if (!cc)
|
||||
return;
|
||||
|
||||
if (cc->socket != socket) {
|
||||
printf("on_socket_event(%p, %ld, %p): socket is higly suspect! Aborting.\n", socket, event, cookie);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("on_socket_event(%p, %ld, %p)\n", socket, event, cookie);
|
||||
|
||||
sed.event = event;
|
||||
sed.cookie = cc->notify_cookie;
|
||||
|
||||
// TODO: don't block here => write_port_etc() ?
|
||||
status = write_port(cc->socket_event_port, NET_STACK_SOCKET_EVENT_NOTIFICATION,
|
||||
&sed, sizeof(sed));
|
||||
if (status != B_OK)
|
||||
printf("write_port(NET_STACK_SOCKET_EVENT_NOTIFICATION) failure: %s\n",
|
||||
strerror(status));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int32
|
||||
connection_runner(void *_cookie)
|
||||
{
|
||||
connection_cookie *cookie = (connection_cookie *)_cookie;
|
||||
bool run = true;
|
||||
|
||||
while (run) {
|
||||
net_area_info area[MAX_NET_AREAS];
|
||||
net_command *command;
|
||||
status_t status = B_OK;
|
||||
uint8 *data;
|
||||
int32 index;
|
||||
ssize_t bytes = read_port(cookie->localPort,&index,NULL,0);
|
||||
if (bytes < B_OK)
|
||||
break;
|
||||
|
||||
if (index >= NUM_COMMANDS || index < 0) {
|
||||
printf("got bad command index: %lx\n",index);
|
||||
continue;
|
||||
}
|
||||
command = cookie->commands + index;
|
||||
if (clone_command_areas(area,command) < B_OK) {
|
||||
printf("could not clone command areas!\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
data = convert_to_local(&command->area[0],&area[0],command->data);
|
||||
printf("command %lx (index = %ld), buffer = %p, length = %ld, result = %ld\n",command->op,index,data,command->length,command->result);
|
||||
|
||||
switch (command->op) {
|
||||
case NET_STACK_OPEN:
|
||||
{
|
||||
struct int_args *args = (struct int_args *)data;
|
||||
cookie->openFlags = args->value;
|
||||
printf("opening socket, mode = %lx!\n",cookie->openFlags);
|
||||
break;
|
||||
}
|
||||
case NET_STACK_CLOSE:
|
||||
printf("closing socket...\n");
|
||||
run = false;
|
||||
break;
|
||||
|
||||
case NET_STACK_SOCKET:
|
||||
{
|
||||
struct socket_args *args = (struct socket_args *)data;
|
||||
|
||||
printf("open a socket... family = %d, type = %d, proto = %d\n",args->family,args->type,args->proto);
|
||||
status = core->socket_init(&cookie->socket);
|
||||
if (status == 0)
|
||||
status = core->socket_create(cookie->socket, args->family, args->type, args->proto);
|
||||
break;
|
||||
}
|
||||
case NET_STACK_GETSOCKOPT:
|
||||
case NET_STACK_SETSOCKOPT:
|
||||
{
|
||||
struct sockopt_args *sockopt = (struct sockopt_args *)data;
|
||||
|
||||
if (command->op == NET_STACK_GETSOCKOPT) {
|
||||
status = core->socket_getsockopt(cookie->socket,sockopt->level,sockopt->option,
|
||||
convert_to_local(&command->area[1],&area[1],sockopt->optval),
|
||||
(size_t *)&sockopt->optlen);
|
||||
} else {
|
||||
status = core->socket_setsockopt(cookie->socket,sockopt->level,sockopt->option,
|
||||
(const void *)convert_to_local(&command->area[1],&area[1],sockopt->optval),
|
||||
sockopt->optlen);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NET_STACK_CONNECT:
|
||||
case NET_STACK_BIND:
|
||||
case NET_STACK_GETSOCKNAME:
|
||||
case NET_STACK_GETPEERNAME:
|
||||
{
|
||||
struct sockaddr_args *args = (struct sockaddr_args *)data;
|
||||
caddr_t addr = (caddr_t)convert_to_local(&command->area[1],&area[1],args->addr);
|
||||
|
||||
switch (command->op) {
|
||||
case NET_STACK_CONNECT:
|
||||
status = core->socket_connect(cookie->socket,addr,args->addrlen);
|
||||
break;
|
||||
case NET_STACK_BIND:
|
||||
status = core->socket_bind(cookie->socket,addr,args->addrlen);
|
||||
break;
|
||||
case NET_STACK_GETSOCKNAME:
|
||||
status = core->socket_getsockname(cookie->socket,(struct sockaddr *)addr,&args->addrlen);
|
||||
break;
|
||||
case NET_STACK_GETPEERNAME:
|
||||
status = core->socket_getpeername(cookie->socket,(struct sockaddr *)addr,&args->addrlen);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NET_STACK_LISTEN:
|
||||
status = core->socket_listen(cookie->socket,((struct int_args *)data)->value);
|
||||
break;
|
||||
|
||||
case NET_STACK_GET_COOKIE:
|
||||
/* this is needed by accept() call, to be able to pass back
|
||||
* in NET_STACK_ACCEPT opcode the cookie of the filedescriptor to
|
||||
* use for the new accepted socket
|
||||
*/
|
||||
*((void **)data) = cookie;
|
||||
break;
|
||||
|
||||
case NET_STACK_ACCEPT:
|
||||
{
|
||||
struct accept_args *args = (struct accept_args *)data;
|
||||
connection_cookie *otherCookie = (connection_cookie *)args->cookie;
|
||||
status = core->socket_accept(cookie->socket,&otherCookie->socket,
|
||||
convert_to_local(&command->area[1],&area[1],args->addr),
|
||||
&args->addrlen);
|
||||
}
|
||||
case NET_STACK_SEND:
|
||||
{
|
||||
struct data_xfer_args *args = (struct data_xfer_args *)data;
|
||||
struct iovec iov;
|
||||
int flags = 0;
|
||||
|
||||
iov.iov_base = convert_to_local(&command->area[1],&area[1],args->data);
|
||||
iov.iov_len = args->datalen;
|
||||
|
||||
status = core->socket_writev(cookie->socket,&iov,flags);
|
||||
break;
|
||||
}
|
||||
case NET_STACK_RECV:
|
||||
{
|
||||
struct data_xfer_args *args = (struct data_xfer_args *)data;
|
||||
struct iovec iov;
|
||||
int flags = 0;
|
||||
|
||||
iov.iov_base = convert_to_local(&command->area[1],&area[1],args->data);
|
||||
iov.iov_len = args->datalen;
|
||||
|
||||
/* flags gets ignored here... */
|
||||
status = core->socket_readv(cookie->socket,&iov,&flags);
|
||||
break;
|
||||
}
|
||||
case NET_STACK_RECVFROM:
|
||||
{
|
||||
struct msghdr *msg = (struct msghdr *)data;
|
||||
int received;
|
||||
|
||||
msg->msg_name = convert_to_local(&command->area[1],&area[1],msg->msg_name);
|
||||
msg->msg_iov = convert_to_local(&command->area[2],&area[2],msg->msg_iov);
|
||||
msg->msg_control = convert_to_local(&command->area[3],&area[3],msg->msg_control);
|
||||
|
||||
status = core->socket_recv(cookie->socket, msg, (caddr_t)&msg->msg_namelen,&received);
|
||||
if (status == 0)
|
||||
status = received;
|
||||
|
||||
msg->msg_name = convert_to_foreign(&command->area[1],&area[1],msg->msg_name);
|
||||
msg->msg_iov = convert_to_foreign(&command->area[2],&area[2],msg->msg_iov);
|
||||
msg->msg_control = convert_to_foreign(&command->area[3],&area[3],msg->msg_control);
|
||||
break;
|
||||
}
|
||||
case NET_STACK_SENDTO:
|
||||
{
|
||||
struct msghdr *msg = (struct msghdr *)data;
|
||||
int sent;
|
||||
|
||||
msg->msg_name = convert_to_local(&command->area[1],&area[1],msg->msg_name);
|
||||
msg->msg_iov = convert_to_local(&command->area[2],&area[2],msg->msg_iov);
|
||||
msg->msg_control = convert_to_local(&command->area[3],&area[3],msg->msg_control);
|
||||
|
||||
status = core->socket_send(cookie->socket,msg,msg->msg_flags,&sent);
|
||||
if (status == 0)
|
||||
status = sent;
|
||||
|
||||
msg->msg_name = convert_to_foreign(&command->area[1],&area[1],msg->msg_name);
|
||||
msg->msg_iov = convert_to_foreign(&command->area[2],&area[2],msg->msg_iov);
|
||||
msg->msg_control = convert_to_foreign(&command->area[3],&area[3],msg->msg_control);
|
||||
break;
|
||||
}
|
||||
|
||||
case NET_STACK_NOTIFY_SOCKET_EVENT:
|
||||
{
|
||||
struct notify_socket_event_args *args = (struct notify_socket_event_args *)data;
|
||||
|
||||
cookie->socket_event_port = args->notify_port;
|
||||
cookie->notify_cookie = args->cookie;
|
||||
|
||||
if (cookie->socket_event_port != -1)
|
||||
// start notify socket event
|
||||
status = core->socket_set_event_callback(cookie->socket, on_socket_event, cookie, 0);
|
||||
else
|
||||
// stop notify socket event
|
||||
status = core->socket_set_event_callback(cookie->socket, NULL, NULL, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case NET_STACK_SYSCTL:
|
||||
{
|
||||
struct sysctl_args *args = (struct sysctl_args *)data;
|
||||
|
||||
status = core->net_sysctl(convert_to_local(&command->area[1],&area[1],args->name),
|
||||
args->namelen,convert_to_local(&command->area[2],&area[2],args->oldp),
|
||||
convert_to_local(&command->area[3],&area[3],args->oldlenp),
|
||||
convert_to_local(&command->area[4],&area[4],args->newp),
|
||||
args->newlen);
|
||||
break;
|
||||
}
|
||||
|
||||
case NET_STACK_STOP:
|
||||
core->stop();
|
||||
break;
|
||||
|
||||
case B_SET_BLOCKING_IO:
|
||||
cookie->openFlags &= ~O_NONBLOCK;
|
||||
break;
|
||||
|
||||
case B_SET_NONBLOCKING_IO:
|
||||
cookie->openFlags |= O_NONBLOCK;
|
||||
break;
|
||||
|
||||
case OSIOCGIFCONF:
|
||||
case SIOCGIFCONF:
|
||||
{
|
||||
struct ifconf *ifc = (struct ifconf *)data;
|
||||
ifc->ifc_buf = convert_to_local(&command->area[1],&area[1],ifc->ifc_buf);
|
||||
|
||||
status = core->socket_ioctl(cookie->socket,command->op,(char *)data);
|
||||
|
||||
ifc->ifc_buf = convert_to_foreign(&command->area[1],&area[1],ifc->ifc_buf);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
status = core->socket_ioctl(cookie->socket,command->op,(char *)data);
|
||||
break;
|
||||
}
|
||||
// mark the command as done
|
||||
command->result = status;
|
||||
command->op = 0;
|
||||
delete_cloned_areas(area);
|
||||
|
||||
// notify the command pipeline that we're done with the command
|
||||
release_sem(cookie->commandSemaphore);
|
||||
}
|
||||
|
||||
cookie->runner = -1;
|
||||
shutdown_connection(cookie);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
init_connection(net_connection *connection,connection_cookie **_cookie)
|
||||
{
|
||||
connection_cookie *cookie;
|
||||
net_command *commands;
|
||||
|
||||
cookie = (connection_cookie *)malloc(sizeof(connection_cookie));
|
||||
if (cookie == NULL) {
|
||||
fprintf(stderr,"couldn't allocate memory for cookie.\n");
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
connection->area = create_area("net connection",(void *)&commands,B_ANY_ADDRESS,
|
||||
CONNECTION_BUFFER_SIZE + CONNECTION_COMMAND_SIZE,
|
||||
B_NO_LOCK,B_READ_AREA | B_WRITE_AREA);
|
||||
if (connection->area < B_OK) {
|
||||
fprintf(stderr,"couldn't create area: %s.\n",strerror(connection->area));
|
||||
free(cookie);
|
||||
return connection->area;
|
||||
}
|
||||
memset(commands,0,NUM_COMMANDS * sizeof(net_command));
|
||||
|
||||
connection->port = create_port(CONNECTION_QUEUE_LENGTH,"net stack connection");
|
||||
if (connection->port < B_OK) {
|
||||
fprintf(stderr,"couldn't create port: %s.\n",strerror(connection->port));
|
||||
delete_area(connection->area);
|
||||
free(cookie);
|
||||
return connection->port;
|
||||
}
|
||||
|
||||
connection->commandSemaphore = create_sem(0,"net command queue");
|
||||
if (connection->commandSemaphore < B_OK) {
|
||||
fprintf(stderr,"couldn't create semaphore: %s.\n",strerror(connection->commandSemaphore));
|
||||
delete_area(connection->area);
|
||||
delete_port(connection->port);
|
||||
free(cookie);
|
||||
return connection->commandSemaphore;
|
||||
}
|
||||
|
||||
cookie->runner = spawn_thread(connection_runner,"connection runner",B_NORMAL_PRIORITY,cookie);
|
||||
if (cookie->runner < B_OK) {
|
||||
fprintf(stderr,"couldn't create thread: %s.\n",strerror(cookie->runner));
|
||||
delete_sem(connection->commandSemaphore);
|
||||
delete_area(connection->area);
|
||||
delete_port(connection->port);
|
||||
free(cookie);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
connection->numCommands = NUM_COMMANDS;
|
||||
connection->bufferSize = CONNECTION_BUFFER_SIZE;
|
||||
|
||||
// setup connection cookie
|
||||
cookie->area = connection->area;
|
||||
cookie->commands = commands;
|
||||
cookie->buffer = (uint8 *)commands + CONNECTION_COMMAND_SIZE;
|
||||
cookie->commandSemaphore = connection->commandSemaphore;
|
||||
cookie->localPort = connection->port;
|
||||
cookie->openFlags = 0;
|
||||
|
||||
cookie->socket_event_port = -1;
|
||||
cookie->notify_cookie = NULL;
|
||||
|
||||
resume_thread(cookie->runner);
|
||||
|
||||
*_cookie = cookie;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
shutdown_connection(connection_cookie *cookie)
|
||||
{
|
||||
printf("free cookie: %p\n",cookie);
|
||||
kill_thread(cookie->runner);
|
||||
|
||||
delete_port(cookie->localPort);
|
||||
delete_sem(cookie->commandSemaphore);
|
||||
delete_area(cookie->area);
|
||||
|
||||
free(cookie);
|
||||
}
|
||||
|
||||
|
||||
static int32
|
||||
connection_opener(void *_unused)
|
||||
{
|
||||
while(true) {
|
||||
port_id port;
|
||||
int32 msg;
|
||||
ssize_t bytes = read_port(gStackPort,&msg,&port,sizeof(port_id));
|
||||
if (bytes < B_OK)
|
||||
return bytes;
|
||||
|
||||
if (msg == NET_STACK_NEW_CONNECTION) {
|
||||
net_connection connection;
|
||||
connection_cookie *cookie;
|
||||
|
||||
printf("incoming connection...\n");
|
||||
if (init_connection(&connection,&cookie) == B_OK)
|
||||
write_port(port,NET_STACK_NEW_CONNECTION,&connection,sizeof(net_connection));
|
||||
} else
|
||||
fprintf(stderr,"connection_opener: received unknown command: %lx (expected = %lx)\n",msg,(int32)NET_STACK_NEW_CONNECTION);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
init_userland_ipc(void)
|
||||
{
|
||||
gStackPort = create_port(CONNECTION_QUEUE_LENGTH,NET_STACK_PORTNAME);
|
||||
if (gStackPort < B_OK)
|
||||
return gStackPort;
|
||||
|
||||
gConnectionOpener = spawn_thread(connection_opener,"connection opener",B_NORMAL_PRIORITY,NULL);
|
||||
if (resume_thread(gConnectionOpener) < B_OK) {
|
||||
delete_port(gStackPort);
|
||||
if (gConnectionOpener >= B_OK) {
|
||||
kill_thread(gConnectionOpener);
|
||||
return B_BAD_THREAD_STATE;
|
||||
}
|
||||
return gConnectionOpener;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
shutdown_userland_ipc(void)
|
||||
{
|
||||
delete_port(gStackPort);
|
||||
kill_thread(gConnectionOpener);
|
||||
}
|
||||
|
||||
|
||||
#ifdef COMMUNICATION_TEST
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
char buffer[8];
|
||||
|
||||
if (init_userland_ipc() < B_OK)
|
||||
return -1;
|
||||
|
||||
puts("Userland_ipc - test is running. Press <Return> to quit.");
|
||||
fgets(buffer,sizeof(buffer),stdin);
|
||||
|
||||
shutdown_userland_ipc();
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* COMMUNICATION_TEST */
|
837
src/tests/servers/net/net_server/userland_modules.cpp
Normal file
837
src/tests/servers/net/net_server/userland_modules.cpp
Normal file
@ -0,0 +1,837 @@
|
||||
/* Userland modules emulation support
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <app/Application.h>
|
||||
#include <app/Roster.h>
|
||||
#include <kernel/OS.h>
|
||||
#include <kernel/image.h>
|
||||
#include <drivers/module.h>
|
||||
#include <storage/StorageDefs.h>
|
||||
#include <storage/FindDirectory.h>
|
||||
#include <storage/Path.h>
|
||||
#include <storage/Directory.h>
|
||||
|
||||
#define ASSERT(condition) if (!(condition)) { debugger("Assertion failed!"); }
|
||||
|
||||
typedef enum {
|
||||
MODULE_LOADED = 0,
|
||||
MODULE_INITING,
|
||||
MODULE_READY,
|
||||
MODULE_UNINITING,
|
||||
MODULE_ERROR
|
||||
} module_state;
|
||||
|
||||
typedef struct module {
|
||||
struct module * next;
|
||||
uint32 id;
|
||||
char * name;
|
||||
module_info * info;
|
||||
struct module_addon * addon; // the module addon this module live in
|
||||
// if NULL, builtin module addon
|
||||
int32 ref_count; // reference count of get_module() made on this module
|
||||
bool keep_loaded;
|
||||
module_state state;
|
||||
} module;
|
||||
|
||||
typedef struct module_addon {
|
||||
struct module_addon * next;
|
||||
int32 ref_count; // reference count of get_module() made using this addon
|
||||
bool keep_loaded;
|
||||
char * path;
|
||||
image_id addon_image; // if -1, not loaded in memory currently
|
||||
module_info ** infos; // valid only when addon_image != -1
|
||||
} module_addon;
|
||||
|
||||
typedef struct module_list_cookie {
|
||||
char * prefix;
|
||||
char * search_paths;
|
||||
char * search_path;
|
||||
char * next_path_token;
|
||||
BList * dir_stack;
|
||||
module_addon * ma; // current module addon looked up
|
||||
module_info ** mi; // current module addon module info
|
||||
} module_list_cookie;
|
||||
|
||||
#define LOCK_MODULES acquire_sem(g_modules_lock)
|
||||
#define UNLOCK_MODULES release_sem(g_modules_lock)
|
||||
|
||||
// local prototypes
|
||||
// ------------------
|
||||
|
||||
static module * search_module(const char * name);
|
||||
static status_t init_module(module * m);
|
||||
static status_t uninit_module(module * m);
|
||||
static module * find_loaded_module_by_name(const char * name);
|
||||
static module * find_loaded_module_by_id(uint32 id);
|
||||
|
||||
static module_addon * load_module_addon(const char * path);
|
||||
static status_t unload_module_addon(module_addon * ma);
|
||||
|
||||
// globals
|
||||
// ------------------
|
||||
|
||||
static sem_id g_modules_lock = -1; // One lock for rule them all, etc...
|
||||
static module * g_modules = NULL;
|
||||
static module_addon * g_module_addons = NULL;
|
||||
static int32 g_next_module_id = 1;
|
||||
|
||||
|
||||
// Public routines
|
||||
// ---------------
|
||||
|
||||
_EXPORT status_t get_module(const char * name, module_info ** mi)
|
||||
{
|
||||
module * m;
|
||||
|
||||
printf("get_module(%s)\n", name);
|
||||
|
||||
m = find_loaded_module_by_name(name);
|
||||
if (!m)
|
||||
m = search_module(name);
|
||||
|
||||
if (!m)
|
||||
return B_NAME_NOT_FOUND;
|
||||
|
||||
*mi = m->info;
|
||||
|
||||
if (m->addon) // built-in modules don't comes from addon...
|
||||
atomic_add(&m->addon->ref_count, 1);
|
||||
|
||||
if (atomic_add(&m->ref_count, 1) == 0)
|
||||
// first time we reference this module, so let's init it:
|
||||
return init_module(m);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
_EXPORT status_t put_module(const char * name)
|
||||
{
|
||||
module * m;
|
||||
|
||||
printf("put_module(%s)\n", name);
|
||||
|
||||
m = find_loaded_module_by_name(name);
|
||||
if (!m)
|
||||
// Hum??? Sorry, this module name was never get_module()'d
|
||||
return B_NAME_NOT_FOUND;
|
||||
|
||||
if (atomic_add(&m->ref_count, -1) <= 1)
|
||||
// this module is no more used...
|
||||
uninit_module(m);
|
||||
|
||||
if (!m->addon)
|
||||
// built-in modules are module addon less...
|
||||
return B_OK;
|
||||
|
||||
if (atomic_add(&m->addon->ref_count, -1) > 1)
|
||||
// Still other module(s) using this module addon
|
||||
return B_OK;
|
||||
|
||||
// okay, this module addon is no more used
|
||||
// let's free up some memory
|
||||
return unload_module_addon(m->addon);
|
||||
}
|
||||
|
||||
|
||||
_EXPORT status_t get_next_loaded_module_name(uint32 *cookie, char *buf, size_t *bufsize)
|
||||
{
|
||||
module * m;
|
||||
status_t status;
|
||||
|
||||
if (buf == NULL && bufsize == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
LOCK_MODULES;
|
||||
|
||||
if (*cookie == 0)
|
||||
// first call expected value
|
||||
m = g_modules;
|
||||
else {
|
||||
// find last loaded module returned, and seek to next one
|
||||
m = (module *) find_loaded_module_by_id((int) *cookie);
|
||||
if (m)
|
||||
m = m->next;
|
||||
};
|
||||
|
||||
// find next loaded module
|
||||
while (m) {
|
||||
if (m->ref_count)
|
||||
break;
|
||||
m = m->next;
|
||||
};
|
||||
|
||||
status = B_OK;
|
||||
if (m) {
|
||||
ASSERT(m->info);
|
||||
if (buf != NULL)
|
||||
strncpy(buf, m->info->name, *bufsize);
|
||||
else
|
||||
*bufsize = strlen(m->info->name + 1);
|
||||
*cookie = m->id;
|
||||
} else
|
||||
status = B_BAD_INDEX;
|
||||
|
||||
UNLOCK_MODULES;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
_EXPORT void * open_module_list(const char *prefix)
|
||||
{
|
||||
module_list_cookie * mlc;
|
||||
char * addon_path;
|
||||
|
||||
if (prefix == NULL)
|
||||
return NULL;
|
||||
|
||||
mlc = (module_list_cookie *) malloc(sizeof(*mlc));
|
||||
mlc->prefix = strdup(prefix);
|
||||
|
||||
addon_path = getenv("ADDON_PATH");
|
||||
mlc->search_paths = (addon_path ? strdup(addon_path) : NULL);
|
||||
mlc->search_path = strtok_r(mlc->search_paths, ":", &mlc->next_path_token);
|
||||
mlc->dir_stack = new BList();
|
||||
mlc->ma = NULL;
|
||||
mlc->mi = NULL;
|
||||
|
||||
return mlc;
|
||||
}
|
||||
|
||||
|
||||
_EXPORT status_t read_next_module_name(void *cookie, char *buf, size_t *bufsize)
|
||||
{
|
||||
module_list_cookie * mlc = (module_list_cookie *) cookie;
|
||||
|
||||
if (!bufsize)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (!mlc)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
/* Okay, take some time to understand how this function works!
|
||||
Basicly, we iterate thru:
|
||||
- each searchable add-ons path root
|
||||
- each (sub-)directory under the current add-ons path root
|
||||
- each module add-on file in the current (sub-)directory
|
||||
- each module name published by current module add-on
|
||||
|
||||
As the iteration involve sub-directory walks, we use recursive calls.
|
||||
Sorry if this code sounds too complex...
|
||||
*/
|
||||
|
||||
if (mlc->ma && mlc->mi) {
|
||||
// we have a module addon still loaded from a last call
|
||||
// so keep looking at his exported module names list
|
||||
while (*mlc->mi) {
|
||||
module_info * mi = *mlc->mi;
|
||||
mlc->mi++;
|
||||
if(strstr(mi->name, mlc->prefix)) {
|
||||
// We find a matching module name. At least. Yeah!!!
|
||||
if (buf) strncpy(buf, mi->name, *bufsize);
|
||||
*bufsize = strlen(mi->name);
|
||||
return B_OK;
|
||||
};
|
||||
};
|
||||
|
||||
// We've iterate all module names of this module addon. Find another one...
|
||||
unload_module_addon(mlc->ma);
|
||||
mlc->ma = NULL;
|
||||
mlc->mi = NULL;
|
||||
};
|
||||
|
||||
// Iterate all searchable add-ons paths
|
||||
while (mlc->search_path) {
|
||||
BDirectory * dir;
|
||||
BEntry entry;
|
||||
BPath path;
|
||||
status_t status;
|
||||
|
||||
// Get current directory
|
||||
dir = (BDirectory *) mlc->dir_stack->LastItem();
|
||||
if (!dir) {
|
||||
// find add-ons root directory in this search path
|
||||
if (strncmp(mlc->search_path, "%A/", 3) == 0) {
|
||||
// resolve "%A/..." path
|
||||
app_info ai;
|
||||
|
||||
be_app->GetAppInfo(&ai);
|
||||
entry.SetTo(&ai.ref);
|
||||
entry.GetPath(&path);
|
||||
path.GetParent(&path);
|
||||
path.Append(mlc->search_path + 3);
|
||||
} else {
|
||||
path.SetTo(mlc->search_path);
|
||||
};
|
||||
|
||||
// We look *only* under prefix-matching sub-path
|
||||
path.Append(mlc->prefix);
|
||||
|
||||
printf("Looking module(s) in %s/%s...\n", mlc->search_path, mlc->prefix);
|
||||
|
||||
dir = new BDirectory(path.Path());
|
||||
if (dir)
|
||||
mlc->dir_stack->AddItem(dir);
|
||||
};
|
||||
|
||||
// Iterate current directory content
|
||||
if (dir) {
|
||||
while (dir->GetNextEntry(&entry) == B_OK) {
|
||||
entry.GetPath(&path);
|
||||
// printf(" %s ?\n", path.Path());
|
||||
|
||||
if (entry.IsDirectory()) {
|
||||
BDirectory * subdir;
|
||||
// push this directory on dir_stack
|
||||
subdir = new BDirectory(path.Path());
|
||||
if (!subdir)
|
||||
continue;
|
||||
|
||||
mlc->dir_stack->AddItem(subdir);
|
||||
// recursivly search this sub-directory
|
||||
return read_next_module_name(cookie, buf, bufsize);
|
||||
};
|
||||
|
||||
if (entry.IsFile()) {
|
||||
mlc->ma = load_module_addon(path.Path());
|
||||
if (!mlc->ma)
|
||||
// Oh-oh, not a loadable module addon!?
|
||||
// WTF it's doing there?!?
|
||||
continue;
|
||||
|
||||
// call ourself to enter the module names list iteration at
|
||||
// function begining code...
|
||||
mlc->mi = mlc->ma->infos;
|
||||
return read_next_module_name(cookie, buf, bufsize);
|
||||
};
|
||||
};
|
||||
|
||||
// We walk thru all this directory content, go back to parent
|
||||
status = mlc->dir_stack->RemoveItem(dir);
|
||||
delete dir;
|
||||
};
|
||||
|
||||
if (!mlc->dir_stack->IsEmpty())
|
||||
continue;
|
||||
|
||||
// We walk thru all this search path content, next now
|
||||
mlc->search_path = strtok_r(NULL, ":", &mlc->next_path_token);
|
||||
};
|
||||
|
||||
// Module(s) list search done, ending...
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
_EXPORT status_t close_module_list(void *cookie)
|
||||
{
|
||||
module_list_cookie * mlc = (module_list_cookie *) cookie;
|
||||
BDirectory * dir;
|
||||
|
||||
ASSERT(mlc);
|
||||
ASSERT(mlc->prefix);
|
||||
|
||||
if (mlc->ma)
|
||||
unload_module_addon(mlc->ma);
|
||||
|
||||
while((dir = (BDirectory *) mlc->dir_stack->FirstItem())) {
|
||||
mlc->dir_stack->RemoveItem(dir);
|
||||
delete dir;
|
||||
};
|
||||
|
||||
delete mlc->dir_stack;
|
||||
|
||||
free(mlc->search_paths);
|
||||
free(mlc->prefix);
|
||||
free(mlc);
|
||||
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
// Some KernelExport.h support from userland
|
||||
|
||||
_EXPORT void dprintf(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
vprintf(fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
|
||||
_EXPORT void kprintf(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
vprintf(fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
|
||||
_EXPORT status_t load_driver_symbols(const char *driver_name)
|
||||
{
|
||||
// Userland debugger will extract symbols itself...
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
_EXPORT thread_id spawn_kernel_thread(thread_entry func, const char *name, long priority, void *arg)
|
||||
{
|
||||
return spawn_thread(func, name, priority, arg);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
// Private routines
|
||||
|
||||
static module_addon * load_module_addon(const char * path)
|
||||
{
|
||||
module_addon * ma;
|
||||
image_id addon_id;
|
||||
module_info ** mi;
|
||||
status_t status;
|
||||
|
||||
ASSERT(path);
|
||||
|
||||
addon_id = load_add_on(path);
|
||||
if (addon_id < 0) {
|
||||
printf("Failed to load %s addon: %s.\n", path, strerror(addon_id));
|
||||
return NULL;
|
||||
};
|
||||
|
||||
// printf("Addon %s loaded.\n", path);
|
||||
|
||||
ma = NULL;
|
||||
|
||||
status = get_image_symbol(addon_id, "modules", B_SYMBOL_TYPE_DATA, (void **) &mi);
|
||||
if (status != B_OK) {
|
||||
// No "modules" symbol found in this addon
|
||||
printf("Symbol \"modules\" not found in %s addon: not a module addon!\n", path);
|
||||
goto error;
|
||||
};
|
||||
|
||||
ma = (module_addon *) malloc(sizeof(*ma));
|
||||
if (!ma)
|
||||
// Gasp: not enough memory!
|
||||
goto error;
|
||||
|
||||
LOCK_MODULES;
|
||||
|
||||
ma->ref_count = 0;
|
||||
ma->keep_loaded = false;
|
||||
ma->path = strdup(path);
|
||||
ma->addon_image = addon_id;
|
||||
ma->infos = mi;
|
||||
|
||||
while(*mi) {
|
||||
module * m;
|
||||
|
||||
m = (module *) malloc(sizeof(*m));
|
||||
if (!m)
|
||||
// Gasp, again: not enough memory!
|
||||
goto error;
|
||||
|
||||
m->ref_count = 0;
|
||||
m->id = atomic_add(&g_next_module_id, 1);
|
||||
m->info = (*mi);
|
||||
m->name = strdup(m->info->name);
|
||||
m->addon = ma;
|
||||
m->keep_loaded = (m->info->flags & B_KEEP_LOADED) ? true : false;
|
||||
|
||||
m->state = MODULE_LOADED;
|
||||
|
||||
m->next = g_modules;
|
||||
g_modules = m;
|
||||
|
||||
mi++;
|
||||
};
|
||||
|
||||
// add this module addon to the list
|
||||
ma->next = g_module_addons;
|
||||
g_module_addons = ma;
|
||||
|
||||
UNLOCK_MODULES;
|
||||
|
||||
return ma;
|
||||
|
||||
error:
|
||||
printf("Error while load_module_addon(%s)\n", path);
|
||||
|
||||
if (ma) {
|
||||
// remove any appended modules by this module addon until we got error...
|
||||
module * prev;
|
||||
module * m;
|
||||
|
||||
prev = NULL;
|
||||
m = g_modules;
|
||||
while (m) {
|
||||
if (m->addon == ma) {
|
||||
module * tmp = m;
|
||||
|
||||
m = tmp->next;
|
||||
|
||||
if (prev)
|
||||
prev->next = tmp->next;
|
||||
else
|
||||
g_modules = tmp->next;
|
||||
|
||||
if (tmp->name)
|
||||
free(tmp->name);
|
||||
free(tmp);
|
||||
continue;
|
||||
};
|
||||
|
||||
prev = m;
|
||||
m = m->next;
|
||||
};
|
||||
|
||||
|
||||
UNLOCK_MODULES;
|
||||
|
||||
if (ma->path)
|
||||
free(ma->path);
|
||||
free(ma);
|
||||
};
|
||||
|
||||
unload_add_on(addon_id);
|
||||
printf("Addon %s unloaded.\n", path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static status_t unload_module_addon(module_addon * ma)
|
||||
{
|
||||
module * m;
|
||||
module * prev;
|
||||
status_t status;
|
||||
|
||||
ASSERT(ma);
|
||||
|
||||
if (ma->keep_loaded) {
|
||||
printf("B_KEEP_LOADED flag set for %s module addon. Will be *never* unloaded!\n",
|
||||
ma->path);
|
||||
return B_OK;
|
||||
};
|
||||
|
||||
if (ma->ref_count)
|
||||
// still someone needing this module addon, it seems?
|
||||
return B_OK;
|
||||
|
||||
if (ma->addon_image < 0)
|
||||
// built-in addon, it seems...
|
||||
return B_OK;
|
||||
|
||||
status = unload_add_on(ma->addon_image);
|
||||
if (status != B_OK) {
|
||||
printf("Failed to unload %s addon: %s.\n", ma->path, strerror(status));
|
||||
return status;
|
||||
};
|
||||
// printf("Addon %s unloaded.\n", ma->path);
|
||||
|
||||
LOCK_MODULES;
|
||||
|
||||
// remove the modules coming from this module addon from g_modules list
|
||||
prev = NULL;
|
||||
m = g_modules;
|
||||
while (m) {
|
||||
if (m->addon == ma) {
|
||||
module * tmp = m;
|
||||
|
||||
m = tmp->next;
|
||||
|
||||
if (prev)
|
||||
prev->next = tmp->next;
|
||||
else
|
||||
g_modules = tmp->next;
|
||||
|
||||
if (tmp->name)
|
||||
free(tmp->name);
|
||||
free(tmp);
|
||||
continue;
|
||||
};
|
||||
|
||||
prev = m;
|
||||
m = m->next;
|
||||
};
|
||||
|
||||
// remove the module addon from g_module_addons list:
|
||||
if (g_module_addons == ma)
|
||||
g_module_addons = ma->next;
|
||||
else {
|
||||
module_addon * tmp;
|
||||
tmp = g_module_addons;
|
||||
while (tmp && tmp->next != ma)
|
||||
tmp = tmp->next;
|
||||
|
||||
ASSERT(tmp);
|
||||
tmp->next = ma->next;
|
||||
};
|
||||
|
||||
if (ma->path)
|
||||
free(ma->path);
|
||||
free(ma);
|
||||
|
||||
UNLOCK_MODULES;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static module * search_module(const char * name)
|
||||
{
|
||||
BPath path;
|
||||
BPath addons_path;
|
||||
BEntry entry;
|
||||
module * found_module;
|
||||
char * search_paths;
|
||||
char * search_path;
|
||||
char * next_path_token;
|
||||
|
||||
printf("search_module(%s):\n", name);
|
||||
|
||||
search_paths = getenv("ADDON_PATH");
|
||||
if (!search_paths)
|
||||
// Nowhere to search addons!!!
|
||||
return NULL;
|
||||
|
||||
search_paths = strdup(search_paths);
|
||||
search_path = strtok_r(search_paths, ":", &next_path_token);
|
||||
|
||||
found_module = NULL;
|
||||
while (search_path && found_module == NULL) {
|
||||
if (strncmp(search_path, "%A/", 3) == 0) {
|
||||
// compute "%A/..." path
|
||||
app_info ai;
|
||||
|
||||
be_app->GetAppInfo(&ai);
|
||||
entry.SetTo(&ai.ref);
|
||||
entry.GetPath(&addons_path);
|
||||
addons_path.GetParent(&addons_path);
|
||||
addons_path.Append(search_path + 3);
|
||||
} else {
|
||||
addons_path.SetTo(search_path);
|
||||
};
|
||||
|
||||
printf("Looking into %s\n", search_path);
|
||||
|
||||
path.SetTo(addons_path.Path());
|
||||
path.Append(name);
|
||||
|
||||
while(path != addons_path) {
|
||||
printf(" %s ?\n", path.Path());
|
||||
entry.SetTo(path.Path());
|
||||
if (entry.IsFile()) {
|
||||
module_addon * ma;
|
||||
|
||||
// try to load the module addon
|
||||
ma = load_module_addon(path.Path());
|
||||
if (ma) {
|
||||
found_module = find_loaded_module_by_name(name);
|
||||
if (found_module)
|
||||
break;
|
||||
|
||||
unload_module_addon(ma);
|
||||
}; // if (ma)
|
||||
}; // if (entry.IsFile())
|
||||
|
||||
// okay, remove the current path leaf and try again...
|
||||
path.GetParent(&path);
|
||||
};
|
||||
|
||||
search_path = strtok_r(NULL, ":", &next_path_token);
|
||||
};
|
||||
|
||||
free(search_paths);
|
||||
|
||||
if (found_module)
|
||||
printf(" Found it in %s addon module!\n",
|
||||
found_module->addon ? found_module->addon->path : "BUILTIN");
|
||||
|
||||
return found_module;
|
||||
}
|
||||
|
||||
|
||||
static status_t init_module(module * m)
|
||||
{
|
||||
status_t status;
|
||||
|
||||
ASSERT(m);
|
||||
|
||||
switch (m->state) {
|
||||
case MODULE_LOADED:
|
||||
m->state = MODULE_INITING;
|
||||
ASSERT(m->info);
|
||||
printf("Initing module %s... ", m->name);
|
||||
status = m->info->std_ops(B_MODULE_INIT);
|
||||
printf("done (%s).\n", strerror(status));
|
||||
m->state = (status == B_OK) ? MODULE_READY : MODULE_LOADED;
|
||||
|
||||
if (m->state == MODULE_READY && m->keep_loaded && m->addon) {
|
||||
// one module (at least) was inited and request to never being
|
||||
// unload from memory, so keep the corresponding addon loaded
|
||||
printf("module %s set B_KEEP_LOADED flag:\nmodule addon %s will never be unloaded!\n",
|
||||
m->name, m->addon->path);
|
||||
m->addon->keep_loaded = true;
|
||||
};
|
||||
break;
|
||||
|
||||
case MODULE_READY:
|
||||
status = B_OK;
|
||||
break;
|
||||
|
||||
case MODULE_INITING: // circular reference!!!
|
||||
case MODULE_UNINITING: // initing a module currently unloading...
|
||||
case MODULE_ERROR: // module failed to unload previously...
|
||||
default: // Unknown module state!!!
|
||||
status = B_ERROR;
|
||||
break;
|
||||
};
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static status_t uninit_module(module * m)
|
||||
{
|
||||
status_t status;
|
||||
|
||||
ASSERT(m);
|
||||
|
||||
switch (m->state) {
|
||||
case MODULE_READY:
|
||||
m->state = MODULE_UNINITING;
|
||||
ASSERT(m->info);
|
||||
printf("Uniniting module %s... ", m->name);
|
||||
status = m->info->std_ops(B_MODULE_UNINIT);
|
||||
printf("done (%s).\n", strerror(status));
|
||||
m->state = (status == B_OK) ? MODULE_LOADED : MODULE_ERROR;
|
||||
break;
|
||||
|
||||
case MODULE_LOADED:
|
||||
// No need to uninit it, all is fine so.
|
||||
status = B_OK;
|
||||
break;
|
||||
|
||||
case MODULE_INITING: // uniniting while initializing
|
||||
case MODULE_UNINITING: // uniniting already pending
|
||||
case MODULE_ERROR: // module failed previously...
|
||||
default: // Unknown module state!!!
|
||||
status = B_ERROR;
|
||||
break;
|
||||
};
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static module * find_loaded_module_by_name(const char * name)
|
||||
{
|
||||
module * m;
|
||||
|
||||
LOCK_MODULES;
|
||||
|
||||
m = g_modules;
|
||||
while (m) {
|
||||
if (strcmp(name, m->name) == 0)
|
||||
break;
|
||||
m = m->next;
|
||||
};
|
||||
|
||||
UNLOCK_MODULES;
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
static module * find_loaded_module_by_id(uint32 id)
|
||||
{
|
||||
module * m;
|
||||
|
||||
LOCK_MODULES;
|
||||
|
||||
m = g_modules;
|
||||
while (m) {
|
||||
if (m->id == id)
|
||||
break;
|
||||
m = m->next;
|
||||
};
|
||||
|
||||
UNLOCK_MODULES;
|
||||
return m;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// #pragma mark -
|
||||
|
||||
#define NET_CORE_MODULE_NAME "network/core/v1"
|
||||
#define NET_ETHERNET_MODULE_NAME "network/interfaces/ethernet"
|
||||
#define NET_IPV4_MODULE_NAME "network/protocols/ipv4/v1"
|
||||
|
||||
#define MODULE_LIST_PREFIX "network"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
module_info * core;
|
||||
module_info * ethernet;
|
||||
module_info * ipv4;
|
||||
char module_name[256];
|
||||
uint32 cookie;
|
||||
size_t sz;
|
||||
void * ml_cookie;
|
||||
|
||||
new BApplication("application/x-vnd-OBOS-net_server");
|
||||
|
||||
printf("open_module_list(%s):\n", MODULE_LIST_PREFIX);
|
||||
ml_cookie = open_module_list(MODULE_LIST_PREFIX);
|
||||
sz = sizeof(module_name);
|
||||
while(read_next_module_name(ml_cookie, module_name, &sz) == B_OK) {
|
||||
if (strlen(module_name))
|
||||
printf(" %s\n", module_name);
|
||||
sz = sizeof(module_name);
|
||||
};
|
||||
close_module_list(ml_cookie);
|
||||
printf("close_module_list()\n");
|
||||
// return 0;
|
||||
|
||||
core = NULL;
|
||||
get_module(NET_CORE_MODULE_NAME, (module_info **) &core);
|
||||
|
||||
ethernet = NULL;
|
||||
get_module(NET_ETHERNET_MODULE_NAME, (module_info **) ðernet);
|
||||
|
||||
ipv4 = NULL;
|
||||
get_module(NET_IPV4_MODULE_NAME, (module_info **) &ipv4);
|
||||
|
||||
printf("get_next_loaded_module_name() test:\n");
|
||||
cookie = 0;
|
||||
sz = sizeof(module_name);
|
||||
while (get_next_loaded_module_name(&cookie, module_name, &sz) == B_OK)
|
||||
printf("%ld: %s\n", cookie, module_name);
|
||||
|
||||
if (ipv4)
|
||||
put_module(NET_IPV4_MODULE_NAME);
|
||||
|
||||
if (ethernet)
|
||||
put_module(NET_ETHERNET_MODULE_NAME);
|
||||
|
||||
if (core)
|
||||
put_module(NET_CORE_MODULE_NAME);
|
||||
|
||||
printf("get_next_loaded_module_name() test:\n");
|
||||
cookie = 0;
|
||||
sz = sizeof(module_name);
|
||||
while (get_next_loaded_module_name(&cookie, module_name, &sz) == B_OK)
|
||||
printf("%ld: %s\n", cookie, module_name);
|
||||
|
||||
delete be_app;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user