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,66 +13,15 @@
#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);
/**stop (close(socket_fd)) the server*/
......@@ -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