libSystem/src/appserver.c
2005-09-23 22:50:03 +00:00

275 lines
5.8 KiB
C

/* appserver.c */
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#ifdef DEBUG
# include <stdio.h>
#endif
#include "array.h"
#include "string.h"
#include "appinterface.h"
#include "appserver.h"
/* AppServerClient */
/* types */
typedef enum _AppServerClientState
{
ASCS_NEW,
ASCS_LOGGED
} AppServerClientState;
typedef struct _AppServerClient
{
AppServerClientState state;
int fd;
uint32_t addr; /* FIXME uint8_t[4] instead? */
uint16_t port;
#define ASC_BUFSIZE 65536 /* FIXME */
char buf_read[ASC_BUFSIZE];
unsigned int buf_read_cnt;
char buf_write[ASC_BUFSIZE];
unsigned int buf_write_cnt;
} AppServerClient;
/* functions */
AppServerClient * appserverclient_new(int fd, uint32_t addr, uint16_t port)
{
AppServerClient * asc;
if((asc = malloc(sizeof(AppServerClient))) == NULL)
return NULL;
asc->state = ASCS_NEW;
asc->fd = fd;
asc->addr = addr;
asc->port = port;
asc->buf_read_cnt = 0;
asc->buf_write_cnt = 0;
return asc;
}
void appserverclient_delete(AppServerClient * appserverclient)
{
/* FIXME find a way to properly report error */
#ifdef DEBUG
if(close(appserverclient->fd) != 0)
perror("close");
# else
close(appserverclient->fd);
#endif
free(appserverclient);
}
/* AppServer */
/* private */
/* types */
ARRAY(AppServerClient *, AppServerClient);
struct _AppServer
{
AppInterface * interface;
Event * event;
AppServerClientArray * clients;
};
/* functions */
static int _appserver_read(int fd, AppServer * appserver);
static int _appserver_accept(int fd, AppServer * appserver)
{
struct sockaddr_in sa;
int sa_size = sizeof(struct sockaddr_in);
int newfd;
AppServerClient * asc;
#ifdef DEBUG
fprintf(stderr, "%s%d%s%p%s", "_appserver_accept(", fd, ", ", appserver,
")\n");
#endif
if((newfd = accept(fd, (struct sockaddr *)&sa, &sa_size)) == -1)
return 1;
if((asc = appserverclient_new(newfd, sa.sin_addr.s_addr, sa.sin_port))
== NULL)
{
/* FIXME report error */
close(newfd);
return 0;
}
array_append(appserver->clients, asc);
event_register_io_read(appserver->event, newfd,
(EventIOFunc)_appserver_read, appserver);
return 0;
}
static int _read_process(AppServer * appserver, AppServerClient * asc);
static int _appserver_read(int fd, AppServer * appserver)
{
AppServerClient * asc = NULL;
unsigned int i;
ssize_t len;
for(i = 0; i < array_count(appserver->clients); i++)
{
if(array_get(appserver->clients, i, &asc))
break;
if(fd == asc->fd)
break;
asc = NULL;
}
if(asc == NULL)
return 1;
if((len = sizeof(asc->buf_read) - asc->buf_read_cnt) < 0
|| (len = read(fd, &asc->buf_read[asc->buf_read_cnt],
len)) <= 0)
{
/* FIXME do all this in appserverclient_delete() or something
* like appserver_remove_client() */
if(asc->buf_write_cnt > 0)
event_unregister_io_write(appserver->event, fd);
event_unregister_io_read(appserver->event, fd);
appserverclient_delete(asc);
array_remove_pos(appserver->clients, i);
return 1;
}
asc->buf_read_cnt+=len;
#ifdef DEBUG
fprintf(stderr, "%s%d%s%d%s", "_appserver_read(", fd,
", appserver): ", len, " characters read\n");
#endif
return _read_process(appserver, asc);
}
static int _read_logged(AppServer * appserver, AppServerClient * asc);
static int _read_process(AppServer * appserver, AppServerClient * asc)
{
switch(asc->state)
{
case ASCS_NEW:
/* FIXME authenticate */
case ASCS_LOGGED:
return _read_logged(appserver, asc);
}
return 1;
}
static int _appserver_receive(AppServer * appserver, AppServerClient * asc);
static int _read_logged(AppServer * appserver, AppServerClient * asc)
{
if(_appserver_receive(appserver, asc) != 0)
{
close(asc->fd);
return 1;
}
return 0;
}
static int _appserver_receive(AppServer * appserver, AppServerClient * asc)
{
int i;
if((i = appinterface_receive(appserver->interface, asc->buf_read,
asc->buf_read_cnt)) == -1)
return -1;
if(i <= 0 || i > asc->buf_read_cnt)
return -1;
memmove(asc->buf_read, &asc->buf_read[i], asc->buf_read_cnt-i);
asc->buf_read_cnt-=i;
return 0;
}
/* public */
/* functions */
/* appserver_new */
AppServer * appserver_new(const char * app, int options)
{
AppServer * appserver;
Event * event;
if((event = event_new()) == NULL)
return NULL;
if((appserver = appserver_new_event(app, options, event)) == NULL)
{
event_delete(event);
return NULL;
}
return appserver;
}
/* appserver_new_event */
static int _new_server(AppServer * appserver, int options);
AppServer * appserver_new_event(char const * app, int options, Event * event)
{
AppServer * appserver;
if((appserver = malloc(sizeof(AppServer))) == NULL)
return NULL;
appserver->interface = NULL;
appserver->event = event;
appserver->clients = NULL;
if((appserver->clients = AppServerClientarray_new()) == NULL
|| (appserver->interface = appinterface_new_server(app))
== NULL
|| _new_server(appserver, options) != 0)
{
if(appserver->clients != NULL)
array_delete(appserver->clients);
if(appserver->interface != NULL)
appinterface_delete(appserver->interface);
free(appserver);
return NULL;
}
return appserver;
}
static int _new_server(AppServer * appserver, int options)
{
int fd;
struct sockaddr_in sa;
if((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
return 1;
sa.sin_family = AF_INET;
sa.sin_port = htons(4242); /* FIXME */
sa.sin_addr.s_addr = htonl(options & ASO_LOCAL ? INADDR_LOOPBACK
: INADDR_ANY);
if(bind(fd, (struct sockaddr *)&sa, sizeof(sa)) != 0
|| listen(fd, 5) != 0)
{
/* FIXME report error */
#ifdef DEBUG
if(close(fd) != 0)
perror("close");
# else
close(fd);
#endif
return 1;
}
event_register_io_read(appserver->event, fd,
(EventIOFunc)_appserver_accept, appserver);
return 0;
}
/* appserver_delete */
void appserver_delete(AppServer * appserver)
{
event_delete(appserver->event);
free(appserver);
}
/* useful */
int appserver_loop(AppServer * appserver)
{
return event_loop(appserver->event);
}