Commit 2a007bb8 authored by Arnaud Blanchard's avatar Arnaud Blanchard
Browse files

more options for image and networks

parent 7989f73c
doc @ 901d580d
Subproject commit fcd1634e59954561f8e1d31b0f6b2d6cb20fd138
Subproject commit 901d580d4ad8613f0703611ab9869a21297aac4e
......@@ -39,8 +39,10 @@ typedef struct blc_array
#ifdef __cplusplus
:blc_mem {
blc_array();
void init(char const *properties);
void vdef_array(uint32_t type, uint32_t format, int dims_nb, int length, va_list arguments);
void vdef_array(uint32_t type, uint32_t format, int dims_nb, int length0, va_list arguments);
void def_array(uint32_t type, uint32_t format, int dims_nb, int length0, ...);
void def_array(uint32_t type, uint32_t format, int dims_nb, blc_dim *dims);
void def_array(uint32_t type, uint32_t format, char const *dims_string);
......@@ -55,7 +57,18 @@ typedef struct blc_array
int fprint_dims(FILE *file) const;
void fprint_debug(FILE *file) const;
void fscan_dims(FILE *file);
void sscan_dims(char const* scan);
void sscan_properties(char const *string);
void fscan_properties(FILE *file);
void sprint_properties(char *buffer, size_t buffer_size);
void fprint_properties(FILE *file);
///Scan and interpret the string as the description of the dimensions of a **blc_channel**. **Return** how many chars have been interpreted.
int sscan_dims(char const* string);
int get_type_size();
size_t get_minimum_size();
......
//
// blc_network.h
// network
//
// Created by Arnaud Blanchard on 30/05/2015.
//
//
/**
@defgroup blc_network network
Few functions helping for pseudo realtime applications.
@{*/
#ifndef BLC_NETWORK_H
#define BLC_NETWORK_H
#include <stdio.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include "blc_mem.h"
/*By default it is a client*/
#define BLC_SERVER 1
#define BLC_UDP4 2
#define BLC_UDP4_SERVER (BLC_SERVER | BLC_UDP4)
#define BLC_NET_PROTOCOLE (BLC_UDP4) // FOr now it is use less but latter it will include all the protocoles
/* To be used with readv/writev, sendmsg/recvmsg. */
#define BLC_SET_IOVEC(iovec, variable) blc_set_iovec(iovec, &(variable), sizeof(variable), NULL)
#define BLC_SET_IOVEC2(iovec, variable1, variable2) blc_set_iovec(iovec, &(variable1), sizeof(variable1), &(variable2), sizeof(variable2), NULL)
#define BLC_SET_IOVEC3(iovec, variable1, variable2, variable3) blc_set_iovec(iovec, &(variable1), sizeof(variable1),&(variable2), sizeof(variable2),&(variable3), sizeof(variable3), NULL)
typedef void (*type_blc_network_callback)(char *, size_t size, void *arg);
typedef struct blc_network
#ifdef __cplusplus
:blc_mem{
/**Init a network connection in **mode** **BLC_UDP4** (udp IPv4) for now.
**address** can be null (usually for a server). Acceptable value for **address** is either a valid host name or a numeric host address string consisting of a dotted decimal IPv4
**port_name** is a port number as a string of a decimal number.
If buffer_size=0, you are responsible for allocating the memory in .data (use .allocate(size) for example).
*/
void init(char const *address_name, char const *port_name, int mode, size_t buffer_size=0);
void send();
void send_buffer(void* data, size_t size);
void close();
void close_and_free_buffer();
#else
{ blc_mem mem;
#endif
struct sockaddr_storage remote_address;
socklen_t remote_address_length;
int socket_fd;
struct msghdr msghdr;
}blc_network;
typedef struct blc_server
#ifdef __cplusplus
:blc_network {
/** start a *pthread* with a server listenning (*rcvmsg*) in the **port_name** (i.e. "3333") with **mode** BLC_UDP4 (only for now).
Each time the server receive data on the associated port it will call the callback with the data received as parameter.
**.mem**, the receiving buffer has to be allocated before with enough size to store all a received message.
*/
void start(char const *port_name, int mode, type_blc_network_callback on_receive_data, void *arg, size_t buffer_size=0);
/**stop (close(socket_fd)) the server*/
void stop();
/** stop the server and free the allocated receive buffer*/
void stop_and_free_buffer();
void send_back();
void send_back_buffer(void *buffer, size_t size);
#else
{ blc_network network;
#endif
pthread_t thread;
type_blc_network_callback callback;
void *callback_arg;
}blc_server;
typedef struct blc_client
#ifdef __cplusplus
:blc_network {
/** start a *pthread* with a server listenning (*rcvmsg*) in the **port_name** (i.e. "3333") with **mode** BLC_UDP4 (only for now).
Each time the server receive data on the associated port it will call the callback with the data received as parameter.
**.mem**, the receiving buffer has to be allocated before with enough size to store all a received message.
*/
void start(char const *port_name, int mode, type_blc_network_callback on_receive_data, void *arg, size_t buffer_size=0);
/**stop (close(socket_fd)) the server*/
void stop();
/** stop the server and free the allocated receive buffer*/
void stop_and_free_buffer();
#else
{ blc_network network;
#endif
pthread_t thread;
type_blc_network_callback callback;
void *callback_arg;
}blc_client;
START_EXTERN_C
///Set a **iovev struct** used by sendmsg/recvmsg, with all the buffers (couples pointer/size) in the list. The list **has** to finish by **NULL**.
int blc_set_iovec(struct iovec *iov, void *data, size_t size, ...);
void blc_network_init(blc_network *network, char const *address_name, char const *port_name, int mode);
void blc_server_start(blc_server *server, char const *port_name, int mode, type_blc_network_callback on_receive_data, void *);
void blc_server_allocate_mem_and_start(blc_server *server, char const *port_name, int mode, type_blc_network_callback on_receive_data, void *, size_t size);
END_EXTERN_C
#endif
///@}
\ No newline at end of file
......@@ -197,8 +197,8 @@ MANY_REALLOCATIONS(&values, 7);
///like sprintf but check that the buffer is big enough to contain the string. It only works with static buffer. It does not return the string size.
#define SPRINTF(buffer, ...) do{ if (snprintf(buffer, sizeof(buffer), __VA_ARGS__) >= (int)sizeof(buffer)) EXIT_ON_ERROR("The string is too long for the buffer of size '%ld'.", sizeof(buffer));}while(0)
///like strcpy but check that the buffer is big enough to contain the string. It only works with static buffer.
#define STRCPY(buffer, source) do {if (source==NULL) EXIT_ON_ERROR("source must not be NULL"); else if (buffer==NULL) EXIT_ON_ERROR("destination must not be NULL"); if (strlen(source)+1 > (int)sizeof(buffer)) EXIT_ON_ERROR("The length ('%d') of the your source ('%s') is longer than the receiving buffer: '%ld'.", strlen(source)+1, source, sizeof(buffer)); else strcpy(buffer, source);}while(0) //tricks to not have problem in a if
///like strcpy but check that the buffer is big enough to contain the string. ATTENTION: It only works with static buffer !
#define STRCPY(buffer, source) do {if (source==NULL) EXIT_ON_ERROR("source must not be NULL"); else if (buffer==NULL) EXIT_ON_ERROR("destination must not be NULL"); if (strlen(source)+1 > (int)sizeof(buffer)) EXIT_ON_ERROR("The length ('%d') of the your source ('%s') is longer than the receiving buffer: '%ld'.\nREMARQ: if the first argument is not a static buffer, this test is WRONG. The size of the pointer and not the size of the buffer is considered ! Use strncpy and make yourself the verification.", strlen(source)+1, source, sizeof(buffer)); else strcpy(buffer, source);}while(0) //tricks to not have problem in a if
/// Do a fscanf checking than the number of interpreted arguments corresponds to the first parameter.
#define FSCANF(fields_nb, file, ... ) if (fscanf(file, __VA_ARGS__) != fields_nb) EXIT_ON_ERROR("Failed reading %d fields.", fields_nb)
......
......@@ -26,6 +26,11 @@
blc_array::blc_array():dims(NULL), dims_nb(0){};
void blc_array::init(char const *properties){
sscan_properties(properties);
}
void blc_array::vdef_array(uint32_t type, uint32_t format, int dims_nb, int length, va_list arguments){
blc_dim *dim;
......@@ -117,22 +122,24 @@ void blc_array::set_dims(int dims_nb, int length, ...){
int blc_array::get_type_size(){
switch (type){
case 'INT8': case 'UIN8': case 'TEXT': return 1;
case 'INT8': case 'UIN8': return 1;
case 'UI16':case 'IN16': return 2;
case 'FL32':case 'UI32':case 'IN32': return 4;
case 'FL64': case'UI64':case 'IN64': return 8;
case 'CHAR': case 'TEXT': EXIT_ON_ARRAY_ERROR(this, "The type is unknown. You probably mean 'INT8'");
default: EXIT_ON_ARRAY_ERROR(this, "The type is unknown.");
}
return -1;
}
int blc_array::sprint_dims(char *string, int string_size){
int i, width=0;
if (dims_nb==0) width+=snprintf(string, string_size, "0");
if (dims_nb==0) width=snprintf(string, string_size, "0");
else {
width+=sprintf(string, "%lu", dims[0].length);
for(i=1; i<dims_nb; i++) width+=sprintf(string+width, "x%lu", dims[i].length);
width=snprintf(string, string_size, "%lu", dims[0].length);
for(i=1; i<dims_nb; i++) width+=snprintf(string+width, string_size-width, "x%lu", dims[i].length);
}
if (width >= string_size) EXIT_ON_ERROR("The reserved size %d is too small to store the %d dims.",size, dims_nb);
return width;
......@@ -170,25 +177,89 @@ void blc_array::fscan_dims(FILE *file){
}
}
void blc_array::sscan_dims(char const *string){
int blc_array::sscan_dims(char const *string){
blc_dim *dim;
int pos;
int pos, total_pos;
int length;
size=get_type_size();
SSCANF(1, string, "%d%n", &length, &pos);
total_pos=pos;
dims_nb=0;
if (length != 0){
do{
string+=pos;
total_pos+=pos;
dim=APPEND_ALLOCATION(&dims, &dims_nb, blc_dim);
dim->length=length;
dim->step=size;
size*=dim->length;
}while(sscanf(string, "x%lu%n", &dim->length, &pos)==1);
}while(sscanf(string+total_pos, "x%lu%n", &dim->length, &pos)==1);
}
return total_pos;
}
//Should use code in common with fprint_info
void blc_array::sprint_properties(char *buffer, size_t buffer_size){
int width;
uint32_t str_type;
uint32_t str_format;
if (type==0) EXIT_ON_ERROR("The type should not be NULL. Use 'NDEF' by default.");
if (format==0) EXIT_ON_ERROR("The format should not be NULL. Use 'NDEF' by default.");
width=snprintf(buffer, buffer_size, "%.4s %.4s ", UINT32_TO_STRING(str_type, type), UINT32_TO_STRING(str_format, format));
width+=sprint_dims(buffer+width,buffer_size-width);
}
void blc_array::fprint_properties(FILE *file){
int width;
uint32_t net_type = htonl(type);
uint32_t net_format = htonl(format);
if (type==0) EXIT_ON_ERROR("The type should not be NULL. Use 'NDEF' by default.");
if (format==0) EXIT_ON_ERROR("The format should not be NULL. Use 'NDEF' by default.");
fprintf(file, "%.4s %.4s ", (char*)&net_type, (char*)&net_format);
width=fprint_dims(file);
}
//Should use code in common with fscan_info
void blc_array::sscan_properties(char const *string){
int ret, pos;
dims_nb=0;
data=NULL;
size=0;
ret = sscanf(string, "%4c %4c%n", (char*)&type, (char*)&format, &pos);
if (ret == EOF) EXIT_ON_ERROR("End of FILE");
else if (ret!=2) EXIT_ON_ERROR("%d parameters have been read instead of 2 in '%s'.", ret, string);
string+=pos;
NTOHL(type);
NTOHL(format);
string+=sscan_dims(string);
}
void blc_array::fscan_properties(FILE *file){
int ret;
dims_nb=0;
data=NULL;
size=0;
ret = fscanf(file, "%4c %4c ", (char*)&type, (char*)&format);
if (ret == EOF) EXIT_ON_ERROR("End of FILE");
else if (ret!=2) EXIT_ON_ERROR("%d parameters have been read instead of 2", ret);
NTOHL(type);
NTOHL(format);
fscan_dims(file);
}
//usefull ??
......
//
// blc_network.cpp
// network
//
// Created by Arnaud Blanchard on 30/05/2015.
//
//
#include "blc_network.h"
#include "blc_mem.h"
#include "blc_realtime.h"
#include <unistd.h>
#include <pthread.h>
#include <netdb.h>
#include <sys/types.h>
static void* server_manager(void *arg)
{
blc_server *server=(blc_server*)arg;
ssize_t received_data_size;
if (server->data==NULL) EXIT_ON_ERROR("You have not allocated the receive buffer");
server->remote_address_length=sizeof(struct sockaddr_storage);
while(1) //pthread_cancel is used to stop it;
{
//What if bufffer is too small ?
SYSTEM_ERROR_CHECK(received_data_size = recvfrom(server->socket_fd, server->data, server->size, 0, (struct sockaddr*)&server->remote_address, &server->remote_address_length), -1, "Error receiving data.");
server->callback(server->chars, received_data_size, server->callback_arg);
}
return NULL;
}
int blc_set_iovec(struct iovec *iov, void *data, size_t size, ...)
{
int len;
va_list arguments;
va_start(arguments, size);
for(len=0; data != NULL; len++)
{
iov[len].iov_base = data;
iov[len].iov_len = size;
data = va_arg(arguments, void*);
size = va_arg(arguments, size_t);
}
va_end(arguments);
return len;
}
void blc_network::init(char const *address_name, char const *port_name, int mode, size_t buffer_size){
struct addrinfo hints, *results;
int ret;
CLEAR(hints);
hints.ai_flags = AI_NUMERICSERV; //We use only port number not service name ( faster )
if (mode & BLC_SERVER) hints.ai_flags|= AI_PASSIVE; // if address is NULL it is ANY_ADDR otherwise it would be loopback (~localhost)
switch (mode & BLC_NET_PROTOCOLE){
case BLC_UDP4:
hints.ai_family = PF_INET;
hints.ai_socktype = SOCK_DGRAM;
break;
default:
EXIT_ON_ERROR("Unknown mode %d. The possibility is 'BLC_UDP4'.", mode);
break;
}
ret=getaddrinfo(address_name, port_name, &hints, &results);
if (ret !=0) EXIT_ON_ERROR(gai_strerror(ret)); //, 0, "setting address: %s", address_name));
if(results->ai_next != NULL) EXIT_ON_ERROR("There is more than one possible address. It is not yet implemented.");
SYSTEM_ERROR_CHECK(socket_fd = socket(results->ai_family, results->ai_socktype, results->ai_protocol), -1, NULL); //We suppose there is only one result in 'results'
if (mode & BLC_SERVER) SYSTEM_ERROR_CHECK(bind(socket_fd, results->ai_addr, results->ai_addrlen), -1, "Socket %d", socket_fd);
else {
// SYSTEM_ERROR_CHECK(connect(socket_fd, results->ai_addr, results->ai_addrlen), -1, "Socket %d", socket_fd);
remote_address_length=results->ai_addrlen;
memcpy(&remote_address, (void*)results->ai_addr, results->ai_addrlen);
}
freeaddrinfo(results);
if (buffer_size) allocate(buffer_size);
}
void blc_network::send(){
if (this->data==NULL) EXIT_ON_ERROR("You have not allocated buffer.");
SYSTEM_ERROR_CHECK(sendto(socket_fd, this->data, this->size, 0, (struct sockaddr*)&remote_address, remote_address_length), -1, "socket_fd '%d', request first size '%lu'", socket_fd, remote_address_length);
SYSTEM_ERROR_CHECK(read(socket_fd, this->data, this->size), -1, NULL);
fprintf(stderr, "Recv %s\n", this->chars);
}
void blc_network::send_buffer(void* buffer, size_t size){
ssize_t ret;
SYSTEM_ERROR_CHECK(ret=write(socket_fd, buffer, size), -1, "socket_fd '%d', request first size '%lu'", socket_fd, msghdr.msg_iov[0].iov_len);
if ((size_t)ret!=size) EXIT_ON_ERROR("Only '%l' bytes sent instead of '%lu'", ret, size);
}
void blc_network::close(){
::close(socket_fd);
}
void blc_network::close_and_free_buffer(){
this->close();
this->free();
}
void blc_server::start(char const *port_name, int protocol, type_blc_network_callback on_receive_data, void *arg, size_t buffer_size){
callback = on_receive_data;
callback_arg = arg;
init(NULL, port_name, protocol | BLC_SERVER, buffer_size);
SYSTEM_SUCCESS_CHECK(pthread_create(&thread, NULL, server_manager, (void*)this), 0, "Starting server");
}
void blc_server::stop(){
int error;
callback = NULL;
callback_arg = NULL;
PTHREAD_CHECK(pthread_cancel(thread), error, NULL);
/*We wait that the thread has stopped before closing the socket*/
PTHREAD_CHECK(pthread_join(thread, NULL), error, NULL);
::close(socket_fd);
}
void blc_server::stop_and_free_buffer(){
stop();
free();
}
void blc_server::send_back(){
SYSTEM_ERROR_CHECK(sendto(socket_fd, data, size , NO_FLAG, (struct sockaddr*)&remote_address, remote_address_length), -1, "socket %d", socket_fd);
}
void blc_server::send_back_buffer(void *buffer, size_t buffer_size){
printf("%s\n", (char*)buffer);
SYSTEM_ERROR_CHECK(sendto(socket_fd, buffer, buffer_size , NO_FLAG, (struct sockaddr*)&remote_address, remote_address_length), -1, "socket %d", socket_fd);
}
/* Network */
START_EXTERN_C
void blc_network_init(blc_network *network, char const *address_name, char const *port_name, int mode){
network->init(address_name, port_name, mode);
}
void blc_server_start(blc_server *server, char const *port_name, int mode, type_blc_network_callback on_receive_data, void *arg){
server->start(port_name, mode, on_receive_data, arg);
}
void blc_server_allocate_mem_and_start(blc_server *server, char const *port_name, int mode, type_blc_network_callback on_receive_data, void *arg, size_t buffer_size){
server->start(port_name, mode, on_receive_data, arg, buffer_size);
}
END_EXTERN_C
......@@ -138,8 +138,7 @@ void *secure_malloc(const char *file, const char *function, int line, size_t siz
//Fait un realloc de taille 'size' sur le pointeur verifie qu'il n'a pas renvoye NULL et renvoie la nouvelle addresse du pointeur. Si le pointeur d'origine est NULL alors la fonction a le meme effet que secure_malloc. Si le realloc a renvoiye NULL alors une erreur fatal est generee avec le filename, name_of_function, et line comme parametres.
void secure_realloc(const char *file, const char *function, int line, void** pointer, size_t size)
{
*pointer = realloc(*pointer, size);
if (*pointer == NULL) if (size != 0) fatal_error(file, function, line, "realloc of size %d has failed (return NULL)", size);
SYSTEM_ERROR_CHECK(*pointer = realloc(*pointer, size), NULL, "size: '%lu'", size);
}
void *append_allocation(const char *file, const char *function, int line, void** pointer, size_t pointer_content_size, int *items_nb, size_t item_size)
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment