Commit d868d573 authored by Arnaud Blanchard's avatar Arnaud Blanchard

Separate server and simple client functions. Allow to receive less data than the buffer size

parent c7ef09ae
......@@ -16,8 +16,8 @@ set(CMAKE_MACOSX_RPATH 0) #avoid warning in MACOSX
#source files
set(sources
src/blc_server.cpp
src/blc_network.cpp
src/blc_net_array.cpp
)
find_package(blc_core REQUIRED)
......
......@@ -13,65 +13,14 @@
#ifndef BLC_NETWORK_H
#define BLC_NETWORK_H
#include <stdio.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/socket.h>
#include "blc_core.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 struct blc_server blc_server;
//typedef void (*type_blc_server_callback)(blc_server *server);
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).
*/
~blc_network();
void init(char const *address_name, char const *port_name, int mode, size_t buffer_size=0);
void send();
void send_buffer(void const* data, size_t size);
// Return 1 if data as been read, 0 otherwise (timeout)
int recv_timeout(uint64_t us_timeout);
int recv_buffer_timeout(void *buffer, size_t size, uint64_t us_timeout);
void get_remote_address(char *channel_name, socklen_t name_size, char *port_name, socklen_t port_name_size);
#else
{ blc_mem mem;
#endif
struct sockaddr_storage remote_address;
socklen_t remote_address_length;
int socket_fd;
}blc_network;
#include "blc_network_base.h"
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.
Each time the server receive data on the associated port it will call the callback with the data server as parameter.
You can therefore read the data with server->data getting the size with server->receive_data, your arg with server->callback_arg, ...
*/
void start(char const *port_name, int mode, void(*on_receive_data)(blc_server*) , void *arg, size_t buffer_size=0);
......@@ -90,15 +39,9 @@ typedef struct blc_server
pthread_t thread;
void(*callback)(blc_server*);
void *callback_arg;
size_t received_data;
}blc_server;
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_set_msghdr(struct msghdr *msghdr, 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, void(*on_receive_data)(blc_server*), void *);
void blc_server_allocate_mem_and_start(blc_server *server, char const *port_name, int mode, void(*on_receive_data)(blc_server*), void *, size_t size);
END_EXTERN_C
......
//
// blc_network.h
// network
//
// Created by Arnaud Blanchard on 30/05/2015.
//
//
/**
@defgroup blc_network network
Few functions helping with UDP network.
@{*/
#ifndef BLC_NETWORK_BASE_H
#define BLC_NETWORK_BASE_H
#include <stdio.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/socket.h>
#include "blc_core.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 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).
*/
~blc_network();
void init(char const *address_name, char const *port_name, int mode, size_t buffer_size=0);
void send();
void send_buffer(void const* data, size_t size);
// Return 1 if data as been read, 0 otherwise (timeout)
int recv_timeout(uint64_t us_timeout);
int recv_buffer_timeout(void *buffer, size_t size, uint64_t us_timeout);
void get_remote_address(char *channel_name, socklen_t name_size, char *port_name, socklen_t port_name_size);
#else
{ blc_mem mem;
#endif
struct sockaddr_storage remote_address;
socklen_t remote_address_length;
int socket_fd;
size_t received_data;
}blc_network;
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_set_msghdr(struct msghdr *msghdr, void *data, size_t size, ...);
void blc_network_init(blc_network *network, char const *address_name, char const *port_name, int mode);
END_EXTERN_C
#endif
///@}
......@@ -14,61 +14,6 @@
#include <netdb.h>
#include <sys/types.h>
int blc_network::recv_buffer_timeout(void *buffer, size_t buffer_size, uint64_t us_timeout){
fd_set fdset={{0}};
ssize_t ret;
struct timeval timeout;
div_t result;
FD_SET(socket_fd, &fdset);
result=div(us_timeout, 1000000);
timeout.tv_sec=result.quot;
timeout.tv_usec=result.rem;
SYSTEM_ERROR_CHECK(ret=select(socket_fd+1, &fdset, NULL, NULL, &timeout), -1, "Waiting server channel data"); //It would be nice to check errorfds
if (ret==0) return 0;
else{
SYSTEM_ERROR_CHECK(ret=read(socket_fd, buffer, buffer_size), -1, NULL);
if (ret != (ssize_t)buffer_size) EXIT_ON_ERROR("Reading data: '%lu' bytes instead of '%lu'", ret, buffer_size);
}
return 1;
}
int blc_network::recv_timeout(uint64_t us_timeout){
fd_set fdset = {{0}};
ssize_t ret;
struct timeval timeout;
div_t result;
FD_SET(socket_fd, &fdset);
result=div(us_timeout, 1000000);
timeout.tv_sec=result.quot;
timeout.tv_usec=result.rem;
SYSTEM_ERROR_CHECK(ret=select(socket_fd+1, &fdset, NULL, NULL, &timeout), -1, "Waiting server channel data"); //It would be nice to check errorfds
if (ret==0) return 0;
else{
SYSTEM_ERROR_CHECK(ret=read(socket_fd, data, size), -1, NULL);
if (ret != (ssize_t)size) EXIT_ON_ERROR("Reading data: '%lu' bytes instead of '%lu'", ret, size);
}
return 1;
}
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->received_data=received_data_size;
server->callback(server);
}
return NULL;
}
static int blc_vset_iovec(struct iovec *iov, void *data, size_t size, va_list arguments){
int len;
......@@ -104,7 +49,6 @@ void blc_set_msghdr(struct msghdr *msghdr, void *data, size_t size, ...)
}
/* In the default case (client) we do not use connect to be able to read response from the server*/
void blc_network::init(char const *address_name, char const *port_name, int mode, size_t buffer_size){
struct addrinfo hints, *results;
......@@ -112,7 +56,6 @@ void blc_network::init(char const *address_name, char const *port_name, int mode
struct sockaddr_storage address;
socklen_t address_size;
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. If not server it is loopback (~localhost)
......@@ -151,6 +94,29 @@ void blc_network::get_remote_address(char *channel_name, socklen_t name_size, ch
if (ret !=0) EXIT_ON_ERROR(gai_strerror(ret)); //, 0, "setting address: %s", address_name));
}
int blc_network::recv_buffer_timeout(void *buffer, size_t buffer_size, uint64_t us_timeout){
fd_set fdset={{0}};
ssize_t ret;
struct timeval timeout;
div_t result;
FD_SET(socket_fd, &fdset);
result=div(us_timeout, 1000000);
timeout.tv_sec=result.quot;
timeout.tv_usec=result.rem;
SYSTEM_ERROR_CHECK(ret=select(socket_fd+1, &fdset, NULL, NULL, &timeout), -1, "Waiting server channel data"); //It would be nice to check errorfds
if (ret==0) return 0;
else{
SYSTEM_ERROR_CHECK(ret=recv(socket_fd, buffer, buffer_size, MSG_TRUNC), -1, "Socket '%d', data: '%p', size: '%lu'", socket_fd, data, size);
if (ret > (ssize_t)buffer_size) EXIT_ON_ERROR("Buffer too small '%lu' bytes with a buffer of '%lu' bytes", ret, size);
received_data=ret;
}
return 1;
}
int blc_network::recv_timeout(uint64_t us_timeout){
return recv_buffer_timeout(data,size, us_timeout );
}
void blc_network::send(){
if (this->data==NULL) EXIT_ON_ERROR("You have not allocated buffer.");
......@@ -168,51 +134,9 @@ blc_network::~blc_network(){
close(socket_fd);
}
void blc_server::start(char const *port_name, int protocol, void(*on_receive_data)(blc_server*), 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(){
callback = NULL;
callback_arg = NULL;
BLC_PTHREAD_CHECK(pthread_cancel(thread), NULL);
/*We wait that the thread has stopped before closing the socket*/
BLC_PTHREAD_CHECK(pthread_join(thread, NULL), NULL);
close(socket_fd);
}
void blc_server::stop_and_free_buffer(){
stop();
}
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 const *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, void(*on_receive_data)(blc_server*), 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, void(*on_receive_data)(blc_server*), void *arg, size_t buffer_size){
server->start(port_name, mode, on_receive_data, arg, buffer_size);
}
END_EXTERN_C
//
// blc_server.cpp
// network
//
// Created by Arnaud Blanchard on November 2018.
//
#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->received_data=received_data_size;
server->callback(server);
}
return NULL;
}
void blc_server::start(char const *port_name, int protocol, void(*on_receive_data)(blc_server*), 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(){
callback = NULL;
callback_arg = NULL;
BLC_PTHREAD_CHECK(pthread_cancel(thread), NULL);
/*We wait that the thread has stopped before closing the socket*/
BLC_PTHREAD_CHECK(pthread_join(thread, NULL), NULL);
close(socket_fd);
}
void blc_server::stop_and_free_buffer(){
stop();
}
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 const *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_server_start(blc_server *server, char const *port_name, int mode, void(*on_receive_data)(blc_server*), 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, void(*on_receive_data)(blc_server*), void *arg, size_t buffer_size){
server->start(port_name, mode, on_receive_data, arg, buffer_size);
}
END_EXTERN_C
Markdown is supported
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