blob: 91360d1557ac4a3437cd09dd28bd139656896532 [file] [log] [blame] [raw]
/*
copyright: Boaz segev, 2016
license: MIT
Feel free to copy, use and enjoy according to the license provided.
*/
#ifndef LIB_BUFFER_H
#define LIB_BUFFER_H
/**
v. 0.2.0 Changes
- more closely connected to the Server library.
- more copy friendly, requiring more memory and allowing for a packet pool with
minimal malloc on copy.
- Allows for writing hooks to replace the `write` function, so that SSL sockets
and other extensions could, eventually, be utilized.
*/
#define LIB_BUFFER_VERSION "0.2.0"
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include "lib-server.h"
/************************************************/ /**
This library introduces a packet based Buffer object for network data output.
The buffer is pretty much a wrapper for a binary tree with mutexes.
To Create a Buffer use:
`void * Buffer.new(0)` - the offset sets a pre-sent amount for the first packet.
To destroy a Buffer use:
`void Buffer.destroy(void * buffer)`
To add data to a Buffer use any of:
* `write` will copy the data to a new buffer packet.
`size_t Buffer.write(void * buffer, void * data, size_t length)`
* `write_move` will take ownership of the data, wrap it in a buffer packet and
free the mempry once the packet was sent.
A NULL packet sent using write_move will close the connection once it had
been reached (all previous data was sent) - same as `close_when_done`.
`size_t Buffer.write_move(void * buffer, void * data, size_t length)`
* `write_next` will COPY the data, and place it as the first packet in the
queue. `write_next` will protect the current packet from being interrupted in
the middle and the data will be sent as soon as possible without cutting any
packets in half.
`size_t Buffer.write_next(void * buffer, void * data, size_t length)`
To send data from a Buffer to a socket / pipe (file descriptor) use:
`size_t Buffer.flush(void * buffer, int fd)`
*/
extern const struct BufferClass {
/**
Creates a new buffer object, reserving memory for the core data and creating a
mutex.
The buffer object should require ~96 bytes (system dependent), including the
mutex object.
*/
void* (*new)(server_pt owner);
/**
Clears the buffer and destroys the buffer object - releasing it's core memory
and the mutex associated with the buffer.
*/
void (*destroy)(void* buffer);
/**
Clears all the data in the buffer (freeing the data's memory), closes any
pending files and resets the writing hook.
*/
void (*clear)(void* buffer);
/**
Sets a writing hook (needs to be reset any time the buffer is cleared).
A writing hook will be used instead of the `write` function to send data to
the socket. This allows this buffer to be used for special protocol extension
or transport layers, such as SSL/TLS.
A writing hook is a function that takes in a pointer to the server (the
buffer's owner), the socket to which writing should be performed (fd), a
pointer to the data to be written and the length of the data to be written:
A writing hook should return the number of bytes actually sent from the data
buffer (not the number of bytes sent through the socket, but the number of
bytes that can be marked as sent).
A writing hook should return -1 if the data couldn't be sent and processing
should be stop (the connection was lost or suffered a fatal error).
A writing hook should return 0 if no data was sent, but the connection should
remain open or no fatal error occured.
i.e.:
ssize_t writing_hook(server_pt srv, int fd, void* data, size_t len) {
int sent = write(fd, data, len);
if (sent < 0 && (errno & (EWOULDBLOCK | EAGAIN | EINTR)))
sent = 0;
return sent;
}
*/
void (*set_whook)(
void* buffer,
ssize_t (*writing_hook)(server_pt srv, int fd, void* data, size_t len));
/**
Flushes the buffer data through the socket. Returns the number of bytes sent,
if any. returns -1 on error.
*/
ssize_t (*flush)(void* buffer, int fd);
/**
Takes ownership of a FILE pointer and buffers the file data chunk by chunk
(each chunk will be no more then ~64Kb in size), minimizing memory usage when
sending large files.
The file will be automatically closed (using fclose) once all the data was
sent (or once the buffer is cleared).
*/
int (*sendfile)(void* buffer, FILE* file);
/**
Creates a copy of the data and pushes the copy to the buffer.
*/
size_t (*write)(void* buffer, void* data, size_t length);
/**
Takes ownership of the data and pushes the pointer to the buffer. The buffer
will call `free` to deallocate the data once the data was sent.
*/
size_t (*write_move)(void* buffer, void* data, size_t length);
/**
Creates a copy of the data and pushes the copy to the buffer.
The data will be pushed as "next in line", meaning that no "packet" or file
will be interrapted in the middle (a packet is data scheduled to be sent using
`write`/`write_move`/etc').
*/
size_t (*write_next)(void* buffer, void* data, size_t length);
/**
Takes ownership of the data and pushes the pointer to the buffer. The buffer
will call `free` to deallocate the data once the data was sent.
The data will be pushed as "next in line", meaning that no "packet" or file
will be interrapted in the middle (a packet is data scheduled to be sent using
`write`/`write_move`/etc').
*/
size_t (*write_move_next)(void* buffer, void* data, size_t length);
/**
Marks the connection to closes once the current buffer data was sent.
*/
void (*close_when_done)(void* buffer, int fd);
/** returns true (1) if the buffer is empty, otherwise returns false (0). */
char (*is_empty)(void* buffer);
} Buffer;
#endif