blob: 60d2e8728a5940bfead5cb272fd5a1fc5625d8fb [file] [log] [blame] [raw]
/*
copyright: Boaz segev, 2015
license: MIT
Feel free to copy, use and enjoy according to the license provided.
*/
#ifndef LIB_SERVER_H
#define LIB_SERVER_H
#define LIB_SERVER_VERSION 0.1.0
// lib server is based off and requires the following libraries:
#include "libreact.h"
#include "libasync.h"
#include "libbuffer.h"
/////////////////
// General info
// The following types are defined for the userspace of this library:
typedef struct Server* server_pt; // used internally. no public data exposed.
struct ServerSettings;
struct Protocol;
// The start_server(...) macro is a shortcut that allows to easily create a
// ServerSettings structure and start the server.
#define start_server(...) Server.listen((struct ServerSettings){__VA_ARGS__})
/////////////////
// The Protocol
// the Protocol struct defines the callbacks used for the connection and sets
// the behaviour for the connection's protocol.
struct Protocol {
// a string to identify the protocol's service (i.e. "http").
char* service;
// called when a connection is opened
void (*on_open)(struct Server*, int sockfd);
// called when a data is available
void (*on_data)(struct Server*, int sockfd);
// called when the socket is ready to be written to.
void (*on_ready)(struct Server*, int sockfd);
// called when the server is shutting down, but before closing the connection.
void (*on_shutdown)(struct Server*, int sockfd);
// called when the connection was closed
void (*on_close)(struct Server*, int sockfd);
// called when the connection's timeout was reached
void (*ping)(struct Server*, int sockfd);
};
/////////////////
// The Server Settings
// these settings will be used to setup server behaviour. missing settings will
// be filled in with default values. only the `protocol` setting, which sets the
// default protocol, is required.
struct ServerSettings {
// the default protocol.
struct Protocol* protocol;
// the port to listen to. defaults to 3000.
char* port;
// the address to bind to. defaults to NULL (all localhost addresses)
char* address;
// called when the server starts, allowing for further initialization, such
// as timed event scheduling.
// this will be called seperately for every process.
void (*on_init)(struct Server* server);
// called when the server is done, to clean up any leftovers.
void (*on_finish)(struct Server* server);
// called whenever an event loop had cycled (a "tick").
void (*on_tick)(struct Server* server);
// called if an event loop cycled with no pending events.
void (*on_idle)(struct Server* server);
// called each time a new worker thread is spawned (within the new thread).
void (*on_init_thread)(struct Server* server);
// sets the amount of threads to be created for the server's thread-pool.
// Defaults to 1 - all `on_data`/`on_message` callbacks are deffered to a
// single working thread, protecting the reactor from blocking code.
// Use a negative value (-1) to disable the creation of any working threads.
int threads;
// sets the amount of processes to be used (processes will be forked).
// Defaults to 1 working processes (no forking).
int processes;
// a NULL terminated string for when the server is busy (defaults to NULL - a
// simple disconnection with no message).
char* busy_msg;
// opaque user data.
void* udata;
// sets the timeout for new connections. defaults to 5 seconds.
unsigned char timeout;
};
/////////////////
// The Server API
// and helper functions
/** The main `Server` variable allows access to helper functions and defines a
namespace
for the API in this library. */
extern const struct ServerClass {
/** listens to a server with the following server settings (which MUST include
a default protocol). */
int (*listen)(struct ServerSettings);
/// returns the computed capacity for any server instance on the system.
long (*capacity)(void);
/// stops a specific server, closing any open connections.
void (*stop)(struct Server* server);
/// stops any and all server instances, closing any open connections.
void (*stop_all)(void);
/// allows direct access to the reactor object. use with care.
struct ReactorSettings* (*reactor)(struct Server* server);
/// allows direct access to the reactor object. use with care.
struct ServerSettings* (*settings)(struct Server* server);
/// retrives the active protocol object for the requested file descriptor.
struct Protocol* (*get_protocol)(struct Server* server, int sockfd);
/// sets the active protocol object for the requested file descriptor.
void (*set_protocol)(struct Server* server,
int sockfd,
struct Protocol* new_protocol);
/** retrives an opaque pointer set by `set_udata` and associated with the
connection.
since no new connections are expected on fd == 0..2, it's possible to store
global data in these locations. */
void* (*get_udata)(struct Server* server, int sockfd);
/** sets the opaque pointer to be associated with the connection. returns the
old pointer, if any. */
void* (*set_udata)(struct Server* server, int sockfd, void* udata);
/** Connects an existing connection (fd) with the server's reactor and
protocol management system, so that the server can be used also to manage
connection based resources asynchronously (i.e. database resources etc').
since no new connections are expected on fd == 0..2, it's possible to store
global data in these locations.
*/
int (*connect)(struct Server* server, int sockfd, struct Protocol* protocol);
/** counts the number of connections for the specified protocol (NULL = all
protocols). */
long (*count)(struct Server* server, char* service);
// schedules a specific task to run asyncronously for each connection.
// a NULL service identifier == all connections (all protocols).
long (*each)(struct Server* server,
char* service,
void (*task)(struct Server* server, int fd, void* arg),
void* arg);
/** schedules a specific task to run for each connection, in a blocking
manner. a NULL service identifier == all connections (all protocols).
*/
long (*each_block)(struct Server* server,
char* service,
void (*task)(struct Server* server, int fd, void* arg),
void* arg);
/** schedules a specific task to run asyncronously for a specific connection.
a NULL service identifier == all connections (all protocols).
returns -1 on failure, 0 on success (success being scheduling or performing
the task).
*/
int (*fd_task)(struct Server* server,
int sockfd,
void (*task)(struct Server* server, int fd, void* arg),
void* arg);
/** Runs an asynchronous task, IF threading is enabled (set the
`threads` to 1 (the default) or greater). Returns -1 on error or 0
on
succeess.
*/
int (*run_async)(struct Server* self, void (*task)(void*), void* arg);
/** Creates a system timer (at the cost of 1 file descriptor) and pushes the
timer to the reactor. The task will NOT repeat. Returns -1 on error or the
new file descriptor on succeess.
NOTICE: Do NOT create timers from within the on_close callback, as this might
block resources from being properly freed (if the timer and the on_close
object share the same fd number).
*/
int (*run_after)(struct Server* self,
long milliseconds,
void (*task)(void*),
void* arg);
/** Creates a system timer (at the cost of 1 file descriptor) and pushes the
timer to the reactor. The task will repeat `repetitions` times. if
`repetitions` is set to 0, task will repeat forever. Returns -1 on error
or the new file descriptor on succeess.
NOTICE: Do NOT create timers from within the on_close callback, as this might
block resources from being properly freed (if the timer and the on_close
object share the same fd number).
*/
int (*run_every)(struct Server* self,
long milliseconds,
int repetitions,
void (*task)(void*),
void* arg);
/// "touches" a socket, reseting it's timeout counter.
void (*touch)(struct Server* server, int sockfd);
/** sets the timeout limit for the specified connectionl, in seconds, up to
255 seconds (the maximum allowed timeout count). */
void (*set_timeout)(struct Server* server, int sockfd, unsigned char timeout);
/** returns true if the a specific connection's protected callback is running
protected callbacks include only the `on_message` callback and tasks
forwarded to the connection using the `each` function.
*/
unsigned char (*is_busy)(struct Server* server, int sockfd);
/** reads up to `max_len` of data from a socket. the data is stored in the
`buffer` and the number of bytes received is returned. Returns -1 if no
data was available. Returns 0 if an error was raised and the connection
was closed. */
ssize_t (*read)(int sockfd, void* buffer, size_t max_len);
/** Copies & writes data to the socket, managing an asyncronous buffer if
needed.
Copy is only performed if a buffer is needed.
returns 0 on success. success means that the data is in a buffer waiting to
be written. If the socket is closed at this point, the buffer will be
destroyed (never sent).
on error, returns either -1 (closed socket or socket error) or the number
of bytes actually sent (unable to initialize a buffer).
*/
ssize_t (*write)(struct Server* server, int sockfd, void* data, size_t len);
/** Writes data to the socket, managing an asyncronous buffer if needed.
The memory is always freed once the data was written.
returns 0 on success. success means that the data is in a buffer waiting to
be written. If the socket is closed at this point, the buffer will be
destroyed (never sent).
on error, returns either -1 (closed socket or socket error) or the number
of bytes actually sent (unable to initialize a buffer).
*/
ssize_t (*write_move)(struct Server* server,
int sockfd,
void* data,
size_t len);
/** Copies & writes data to the socket, managing an asyncronous buffer if
needed.
Copy is only performed if a buffer is needed.
If a buffer with a number of packets exists (multiple `write` calls),
the data will be pushed forward as the next packet (so as not to divide)
existing packets.
*/
ssize_t (*write_urgent)(struct Server* server,
int sockfd,
void* data,
size_t len);
/** Writes data to the socket, managing an asyncronous buffer if
needed.
Copy is only performed if a buffer is needed.
If a buffer with a number of packets exists (multiple `write` calls),
the data will be pushed forward as the next packet (so as not to divide)
existing packets.
*/
ssize_t (*write_move_urgent)(struct Server* server,
int sockfd,
void* data,
size_t len);
/** Copies & writes data to the socket, managing an asyncronous buffer if
needed.
Copy is only performed if a buffer is needed.
returns 0 on success. success means that the data is in a buffer waiting to
be written. If the socket is closed at this point, the buffer will be
destroyed (never sent).
on error, returns either -1 (closed socket or socket error) or the number
of bytes actually sent (unable to initialize a buffer).
*/
int (*sendfile)(struct Server* server, int sockfd, FILE* file);
/** closes the connection. If any data is waiting to be written, close will
return immediately and the connection will only be closed once all the data
was sent. */
void (*close)(struct Server* server, int sockfd);
/** Hijack a socket (file descriptor) from the server, clearing up it's
resources. The control of hte socket is totally relinquished.
This method will block until all the data in the buffer is sent before
releasing control of the socket. */
int (*hijack)(struct Server* server, int sockfd);
// TODO: implement `attach` (un-hijack)
} Server;
#endif