cake
/
libp7
Archived
1
0
Fork 1
This repository has been archived on 2024-03-16. You can view files and clone it, but cannot push or open issues or pull requests.
libp7/src/packet/data.c

484 lines
13 KiB
C

/* *****************************************************************************
* packet/data.c -- data packet and buffer sending.
* Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
*
* This file is part of libp7.
* libp7 is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3.0 of the License,
* or (at your option) any later version.
*
* libp7 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with libp7; if not, see <http://www.gnu.org/licenses/>.
*
* These functions are about sending and receiving data buffers.
* ************************************************************************** */
#include <libp7/internals.h>
#include <stdlib.h>
#include <string.h>
/* ************************************************************************** */
/* Main functions */
/* ************************************************************************** */
/**
* p7_send_data_packet:
* Send data packet.
*
* Carries 'raw' data in the context of a command. E.g. file data.
* Maximum data size is 256 octets.
*
* @arg handle the libp7 handle
* @arg total the total number of data packets in trans
* @arg id the packet id
* @arg data the data part
* @arg datasize the data part size (in bytes)
* @arg resp should listen to response (shifting-related)
* @return if it worked
*/
static int p7_send_data_packet(p7_handle_t *handle,
p7ushort_t total, p7ushort_t id,
const void *data, unsigned int datasize, int resp)
{
/* make new buffer */
unsigned char buf[8 + datasize];
p7_putascii(buf, total, 4);
p7_putascii(&buf[4], id, 4);
memcpy(&buf[8], data, datasize);
/* send packet */
return (p7_send_ext(handle, p7_pt_data, handle->_last_sent_command,
buf, 8 + datasize, resp));
}
/**
* p7_send_quick_data_packet:
* Send data packet.
*
* Carries 'raw' data in the context of a command. E.g. file data.
* Maximum data size is 256 octets. Buffer must have 8 spare bytes because
* that's the advantages of this function above the one before : it doesn't
* memcpy again.
*
* @arg handle the libp7 handle
* @arg total the total number of data packets in trans
* @arg id the packet id
* @arg buf the buffer with 8 spare bytes at the beginning
* @arg datasize the data part size (in bytes)
* @arg resp should listen to response (shifting-related)
* @return if it worked
*/
static int p7_send_quick_data_packet(p7_handle_t *handle,
p7ushort_t total, p7ushort_t id,
void *buf, p7ushort_t datasize, int resp)
{
/* make new buffer */
unsigned char *cbuf = buf;
p7_putascii(cbuf, total, 4);
p7_putascii(&cbuf[4], id, 4);
/* send packet */
return (p7_send_ext(handle, p7_pt_data, handle->_last_sent_command,
buf, 8 + datasize, resp));
}
/* ************************************************************************** */
/* Shifting utilities */
/* ************************************************************************** */
/**
* unshift:
* Unshift packet.
*
* @arg handle the libp7 handle
* @return if it worked
*/
static int unshift(p7_handle_t *handle)
{
/* truly unshift */
int err;
if ((err = p7_recv(handle, 1)))
return (err);
handle->_flags &= ~p7_intflag_shifted;
/* then return */
return (0);
}
/* ************************************************************************** */
/* Exchanging data functions */
/* ************************************************************************** */
#define BUFNUM 1024
/**
* p7_send_buffer:
* Part of the packet flows where data is sent.
*
* @arg handle the libp7 handle
* @arg buffer the buffer to read from
* @arg shift should shift?
* @arg disp the display callback
* @return the error (0 if ok)
*/
int p7_send_buffer(p7_handle_t *handle, const p7_buffer_t *buffer,
int shift, void (*disp)(p7ushort_t, p7ushort_t))
{
int err = 0;
/* dynamically allocate buffer */
unsigned int bufsize = MAX_RAWDATA_SIZE * BUFNUM;
bufsize = buffer->size < bufsize ? buffer->size : bufsize;
unsigned char *buf = malloc(8 + bufsize);
if (!buf) {
log_fatal("Couldn't allocate file buffer");
return (p7_error_alloc);
}
/* get total and last packet size */
unsigned int lastpacket_size = buffer->size % MAX_RAWDATA_SIZE;
unsigned int total = buffer->size / MAX_RAWDATA_SIZE
+ !!lastpacket_size; /* left data */
if (!lastpacket_size) lastpacket_size = MAX_RAWDATA_SIZE;
/* call disp for initialization */
if (disp) (*disp)(1, 0);
/* send data loop */
unsigned int datasize = MAX_RAWDATA_SIZE;
for (unsigned int id = 1; id <= total;) {
/* read big block */
if ((err = (*buffer->read)(buffer->cookie, 8 + buf, bufsize)))
return (err);
/* then send each block */
unsigned char *b = buf;
unsigned int bufnum = BUFNUM;
for (; bufnum-- && id <= total; id++) {
/* get datasize */
if (id == total) datasize = lastpacket_size;
/* logging */
log_info("sending packet %u/%u (%uo)", id, total, datasize);
/* displaying */
if (disp) (*disp)(id, total);
/* send data packet */
if ((err = p7_send_quick_data_packet(handle, total, id, b,
datasize, !(shift && id == 1)))) {
log_error("could not send data/receive response");
goto fail;
}
/* - check response - */
if (response.type != p7_pt_ack) {
log_error("calculator didn't send ack, weird");
err = p7_error_unknown;
goto fail;
}
/* increment buf pointer */
b += datasize;
}
}
/* unshift */
if (shift) err = unshift(handle);
/* free */
fail:
free(buf);
return (err);
}
/**
* p7_get_buffer:
* Part of the packet flows where data is received.
*
* Do not send an ack before going in this function, it will do it.
*
* @arg handle the libp7 handle
* @arg buffer the buffer to write to.
* @arg shift should shift?
* @arg disp the display callback
* @return the error (0 if ok)
*/
int p7_get_buffer(p7_handle_t *handle, const p7_buffer_t *buffer, p7uint_t size,
int shift, void (*disp)(p7ushort_t, p7ushort_t))
{
int err = 0;
/* announce */
if (buffer->announce && (err = (*buffer->announce)(buffer->cookie, size)))
return (err);
/* dynamically allocate buf size */
size_t bufsize = MAX_RAWDATA_SIZE * BUFNUM;
log_info("buffer size is %" PRIuSIZE, bufsize);
unsigned char *buf = malloc(bufsize);
if (!buf) {
log_fatal("Couldn't allocate file buffer");
return (p7_error_alloc);
}
/* call disp for initialization */
if (disp) (*disp)(1, 0);
/* responding with acks */
log_info("starting main loop");
unsigned char *b = buf; unsigned int fillsize = 0;
/* shift */
if (shift) p7_send_ack(handle, 0);
/* main loop */
while (size) {
/* send ack */
log_info("send ack");
if ((err = p7_send_ack(handle, 1))) {
log_fatal("couldn't send ack/didn't receive answer");
goto fail;
}
/* if packet is not data, wtf casio? */
if (response.type != p7_pt_data) {
log_fatal("packet type was unplanned, wtf ?");
err = p7_error_unknown;
goto fail;
}
/* displaying */
if (disp) (*disp)(response.id, response.total);
/* check overflow */
if ((size_t)response.data_size > size) {
log_fatal("%" PRIuP7SHORT " bytes received... "
"that's more than the %" PRIuSIZE " expected. "
"Taking the first bytes.",
response.data_size, size);
response.data_size = size;
}
/* copy the data */
log_info("is data, put it in buffer");
memcpy(b, response.data, response.data_size);
fillsize += response.data_size; b += response.data_size;
size -= response.data_size;
/* check if we should empty the buffer */
if (fillsize > bufsize - MAX_RAWDATA_SIZE || !size) {
log_info("buffer too full, should be emptied");
/* empty buffer in file
* TODO: read error and terminate if problem? */
(*buffer->write)(buffer->cookie, buf, fillsize);
b = buf; fillsize = 0;
}
}
/* send last ack */
if ((err = p7_send_ack(handle, 1))) {
log_fatal("couldn't send ack/didn't receive answer");
goto fail;
}
/* unshift */
if (shift) err = unshift(handle);
/* end */
fail:
free(buf);
return (err);
}
/* ************************************************************************** */
/* Exchanging data functions - buffer versions */
/* ************************************************************************** */
/**
* p7_send_data:
* Part of the packet flow where data is sent - buffer version.
*
* @arg handle the handle.
* @arg vbuf the buffer.
* @arg size the number of bytes of the buffer to send.
* @arg shift should shift?
* @arg disp the display
* @return the error code (0 if ok)
*/
int p7_send_data(p7_handle_t *handle, const void *vbuf, p7uint_t size,
int shift, void (*disp)(p7ushort_t, p7ushort_t))
{
int err = 0;
const unsigned char *buf = (const unsigned char*)vbuf;
/* get total and last packet size */
unsigned int lastpacket_size = size % MAX_RAWDATA_SIZE;
unsigned int total = size / MAX_RAWDATA_SIZE
+ !!lastpacket_size; /* left data */
if (!lastpacket_size) lastpacket_size = MAX_RAWDATA_SIZE;
/* call disp for initialization */
if (disp) (*disp)(1, 0);
/* send data loop */
unsigned int datasize = MAX_RAWDATA_SIZE;
for (unsigned int id = 0; id <= total;) {
/* get datasize */
if (id == total) datasize = lastpacket_size;
/* logging */
log_info("sending packet %u/%u (%uo)", id, total, datasize);
/* display */
if (disp) (*disp)(id, total);
/* send data packet */
if ((err = p7_send_data_packet(handle, total, id, buf, datasize,
!(shift && id == 1)))) {
log_error("couldn't send data/receive response");
return (err);
}
/* check response */
if (response.type != p7_pt_ack) {
log_error("calculator didn't send ack, weird");
return (p7_error_unknown);
}
/* increment buf pointer */
buf += datasize;
}
/* unshift */
if (shift) err = unshift(handle);
/* no error */
return (0);
}
/**
* p7_get_data:
* Part of the packet flow where data is received - buffer version.
*
* @arg handle the handle.
* @arg vbuf the final buffer (uncasted)
* @arg size the buffer size (and size to receive)
* @arg shift should shift?
* @arg disp the display
* @return the error code (0 if ok).
*/
int p7_get_data(p7_handle_t *handle, void *vbuf, p7uint_t size,
int shift, void (*disp)(p7ushort_t, p7ushort_t))
{
int err = 0;
unsigned char *buf = (unsigned char*)vbuf;
/* call disp for initialization */
if (disp) (*disp)(1, 0);
/* responding with acks */
log_info("starting main loop");
/* shift */
if (shift) p7_send_ack(handle, 0);
/* main loop */
while (size) {
/* send ack */
log_info("send ack");
if ((err = p7_send_ack(handle, 1))) {
log_fatal("couldn't send ack/didn't receive answer");
return (p7_error_unknown);
}
/* if packet is not data, wtf casio? */
if (response.type != p7_pt_data) {
log_fatal("packet type was unplanned, wtf ?");
return (p7_error_unknown);
}
/* displaying */
if (disp) (*disp)(response.id, response.total);
/* check overflow */
if (response.data_size > size) {
log_fatal("%" PRIuP7SHORT " bytes received... "
"that's more than the %" PRIuSIZE " expected. "
"Taking the first bytes.",
response.data_size, size);
response.data_size = size;
}
/* data! continue */
log_info("is data, put it in buffer");
memcpy(buf, response.data, response.data_size);
buf += response.data_size; size -= response.data_size;
}
/* send last ack */
if ((err = p7_send_ack(handle, 1))) {
log_fatal("couldn't send ack/didn't receive answer");
return (p7_error_unknown);
}
/* unshift */
if (shift)
err = unshift(handle);
/* end */
return (err);
}
/* ************************************************************************** */
/* Decode a data packet data */
/* ************************************************************************** */
/* Layout of it */
typedef struct {
unsigned char total_number[4];
unsigned char current_number[4];
unsigned char data[];
} packetdata_data_t;
/**
* decode_data:
* Get data from data packet data field.
*
* @arg handle the handle
* @arg raw raw data
* @arg raw_size raw data size
* @return if there was an error.
*/
int p7_decode_data(p7_handle_t *handle,
const void *raw, p7ushort_t raw_size)
{
p7_packet_t *packet = &handle->_response;
const packetdata_data_t *d = raw;
/* total number */
packet->total = p7_getascii(d->total_number, 4);
log_info("Total data packets : %" PRIuP7SHORT, packet->total);
/* current id */
packet->id = p7_getascii(d->current_number, 4);
log_info("Data packet ID : %" PRIuP7SHORT, packet->id);
/* data */
packet->data_size = raw_size - 8;
memcpy(packet->data, d->data, raw_size - 8);
log_info("Decoded data (%" PRIuP7SHORT "o) :", packet->data_size);
logm_info(packet->data, packet->data_size);
/* no error */
return (0);
}