mirror of
https://github.com/outbackdingo/UltraGrid.git
synced 2026-04-07 02:05:11 +00:00
Merge branch 'aes' into trunk
Conflicts: src/rtp/decoders.c
This commit is contained in:
@@ -55,4 +55,6 @@ UltraGrid - A High Definition Collaboratory
|
||||
at Lawrence Berkeley Laboratory.
|
||||
|
||||
This product uses the RSA Data Security, Inc. MD5 Message-Digest Algorithm.
|
||||
This product includes software developed by the OpenSSL Project
|
||||
for use in the OpenSSL Toolkit. (http://www.openssl.org/)
|
||||
|
||||
|
||||
@@ -89,10 +89,13 @@ OBJS = @OBJS@ \
|
||||
src/compat/platform_spin.o \
|
||||
src/compat/platform_time.o \
|
||||
src/compat/usleep.o \
|
||||
src/crypto/crc_32.o \
|
||||
src/crypto/crypt_aes.o \
|
||||
src/crypto/crypt_aes_impl.o \
|
||||
src/crypto/crypt_des.o \
|
||||
src/crypto/md5.o \
|
||||
src/crypto/openssl_encrypt.o \
|
||||
src/crypto/openssl_decrypt.o \
|
||||
src/crypto/random.o \
|
||||
src/ihdtv/ihdtv.o \
|
||||
src/module.o \
|
||||
|
||||
28
configure.ac
28
configure.ac
@@ -2526,6 +2526,33 @@ fi
|
||||
|
||||
AC_SUBST(IMPORT_CONTROL_KEYBOARD_LIBS)
|
||||
|
||||
# -------------------------------------------------------------------------------------------------
|
||||
# OpenSSL-libcrypto
|
||||
# -------------------------------------------------------------------------------------------------
|
||||
crypto=no
|
||||
crypto_req=auto
|
||||
AC_ARG_ENABLE(openssl,
|
||||
AS_HELP_STRING([--disable-openssl], [disable OpenSSL support(default is auto)]),
|
||||
[crypto_req=$enableval],
|
||||
[crypto_req=auto]
|
||||
)
|
||||
|
||||
PKG_CHECK_MODULES([CRYPTO], [libcrypto], [crypto=yes], [crypto=no])
|
||||
|
||||
if test $crypto_req != no -a $crypto = yes; then
|
||||
AC_DEFINE([HAVE_CRYPTO], [1], [Build with OpenSSL support])
|
||||
CFLAGS="$CFLAGS $CRYPTO_CFLAGS"
|
||||
CXXFLAGS="$CXXFLAGS $CRYPTO_CFLAGS"
|
||||
CPPFLAGS="$CPPFLAGS $CRYPTO_CFLAGS"
|
||||
LIBS="$LIBS $CRYPTO_LIBS"
|
||||
else
|
||||
crypto=no
|
||||
fi
|
||||
|
||||
if test $crypto_req = yes -a $crypto = no; then
|
||||
AC_MSG_ERROR([OpenSSL not found]);
|
||||
fi
|
||||
|
||||
# -------------------------------------------------------------------------------------------------
|
||||
# Run subsequent configure scripts
|
||||
# -------------------------------------------------------------------------------------------------
|
||||
@@ -2552,6 +2579,7 @@ RESULT=\
|
||||
Standalone modules .......... $build_libraries
|
||||
License ..................... $license
|
||||
iHDTV support ............... $ihdtv
|
||||
OpenSSL-libcrypto ........... $crypto
|
||||
|
||||
Bluefish444 ................. $bluefish444 (audio: $blue_audio)
|
||||
DeckLink .................... $decklink
|
||||
|
||||
@@ -129,6 +129,8 @@ struct state_audio {
|
||||
echo_cancellation_t *echo_state;
|
||||
struct audio_export *exporter;
|
||||
int resample_to;
|
||||
|
||||
char *requested_encryption;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -181,7 +183,8 @@ static void audio_scale_usage(void)
|
||||
*/
|
||||
struct state_audio * audio_cfg_init(struct module *parent, char *addrs, int recv_port, int send_port,
|
||||
const char *send_cfg, const char *recv_cfg,
|
||||
char *jack_cfg, char *fec_cfg, char *audio_channel_map, const char *audio_scale,
|
||||
char *jack_cfg, char *fec_cfg, const char *encryption,
|
||||
char *audio_channel_map, const char *audio_scale,
|
||||
bool echo_cancellation, bool use_ipv6, char *mcast_if, audio_codec_t audio_codec,
|
||||
int resample_to)
|
||||
{
|
||||
@@ -259,8 +262,12 @@ struct state_audio * audio_cfg_init(struct module *parent, char *addrs, int recv
|
||||
} else {
|
||||
s->echo_state = NULL;
|
||||
}
|
||||
|
||||
if(encryption) {
|
||||
s->requested_encryption = strdup(encryption);
|
||||
}
|
||||
|
||||
s->tx_session = tx_init(&s->mod, 1500, TX_MEDIA_AUDIO, fec_cfg);
|
||||
s->tx_session = tx_init(&s->mod, 1500, TX_MEDIA_AUDIO, fec_cfg, encryption);
|
||||
if(!s->tx_session) {
|
||||
fprintf(stderr, "Unable to initialize audio transmit.\n");
|
||||
goto error;
|
||||
@@ -420,6 +427,8 @@ void audio_done(struct state_audio *s)
|
||||
pdb_destroy(&s->audio_participants);
|
||||
}
|
||||
audio_export_destroy(s->exporter);
|
||||
module_done(&s->mod);
|
||||
free(s->requested_encryption);
|
||||
free(s);
|
||||
}
|
||||
}
|
||||
@@ -457,7 +466,7 @@ static void *audio_receiver_thread(void *arg)
|
||||
memset(&pbuf_data.buffer, 0, sizeof(struct audio_frame));
|
||||
memset(&device_desc, 0, sizeof(struct audio_desc));
|
||||
|
||||
pbuf_data.decoder = audio_decoder_init(s->audio_channel_map, s->audio_scale);
|
||||
pbuf_data.decoder = audio_decoder_init(s->audio_channel_map, s->audio_scale, s->requested_encryption);
|
||||
assert(pbuf_data.decoder != NULL);
|
||||
|
||||
printf("Audio receiving started.\n");
|
||||
|
||||
@@ -120,7 +120,8 @@ struct module;
|
||||
|
||||
struct state_audio * audio_cfg_init(struct module *parent, char *addrs, int recv_port, int send_port,
|
||||
const char *send_cfg, const char *recv_cfg,
|
||||
char *jack_cfg, char *fec_cfg, char *audio_channel_map, const char *audio_scale,
|
||||
char *jack_cfg, char *fec_cfg, const char *encryption,
|
||||
char *audio_channel_map, const char *audio_scale,
|
||||
bool echo_cancellation, bool use_ipv6, char *mcast_iface, audio_codec_t audio_codec,
|
||||
int resample_to);
|
||||
void audio_finish(struct state_audio *s);
|
||||
|
||||
@@ -52,13 +52,19 @@
|
||||
|
||||
#include "control.h"
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "debug.h"
|
||||
#include "messaging.h"
|
||||
#include "module.h"
|
||||
#include "stats.h"
|
||||
#include "tv.h"
|
||||
|
||||
#define DEFAULT_CONTROL_PORT 5054
|
||||
#define MAX_CLIENTS 16
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct client {
|
||||
int fd;
|
||||
char buff[1024];
|
||||
@@ -69,10 +75,14 @@ struct client {
|
||||
};
|
||||
|
||||
struct control_state {
|
||||
struct module mod;
|
||||
pthread_t thread_id;
|
||||
int local_fd[2];
|
||||
int network_port;
|
||||
struct module *root_module;
|
||||
|
||||
set<struct stats *> stats;
|
||||
pthread_mutex_t stats_lock;
|
||||
};
|
||||
|
||||
#define CONTROL_EXIT -1
|
||||
@@ -84,6 +94,10 @@ static ssize_t write_all(int fd, const void *buf, size_t count);
|
||||
static void * control_thread(void *args);
|
||||
static void send_response(int fd, struct response *resp);
|
||||
|
||||
/**
|
||||
* This function writes all data (in contrast to write() which
|
||||
* can write only part of passed buffer)
|
||||
*/
|
||||
static ssize_t write_all(int fd, const void *buf, size_t count)
|
||||
{
|
||||
unsigned char *p = (unsigned char *) buf;
|
||||
@@ -103,10 +117,16 @@ static ssize_t write_all(int fd, const void *buf, size_t count)
|
||||
|
||||
int control_init(int port, struct control_state **state, struct module *root_module)
|
||||
{
|
||||
struct control_state *s = (struct control_state *) malloc(sizeof(struct control_state));
|
||||
control_state *s = new control_state;
|
||||
|
||||
s->root_module = root_module;
|
||||
|
||||
pthread_mutex_init(&s->stats_lock, NULL);
|
||||
|
||||
module_init_default(&s->mod);
|
||||
s->mod.cls = MODULE_CLASS_CONTROL;
|
||||
s->mod.priv_data = s;
|
||||
|
||||
if(port == -1) {
|
||||
s->network_port = DEFAULT_CONTROL_PORT;
|
||||
} else {
|
||||
@@ -125,6 +145,8 @@ int control_init(int port, struct control_state **state, struct module *root_mod
|
||||
return -1;
|
||||
}
|
||||
|
||||
module_register(&s->mod, root_module);
|
||||
|
||||
*state = s;
|
||||
return 0;
|
||||
}
|
||||
@@ -207,15 +229,6 @@ static int process_msg(struct control_state *s, int client_fd, char *message)
|
||||
append_message_path(path, sizeof(path), (enum module_class[]){ MODULE_CLASS_COMPRESS, MODULE_CLASS_NONE });
|
||||
resp = send_message(s->root_module, path, (struct message *) msg);
|
||||
}
|
||||
} else if(prefix_matches(message, "stats ")) {
|
||||
struct msg_stats *msg = (struct msg_stats *)
|
||||
new_message(sizeof(struct msg_stats));
|
||||
char *stats = suffix(message, "stats ");
|
||||
|
||||
strncpy(msg->what, stats, sizeof(msg->what) - 1);
|
||||
|
||||
// resp = send_message(s->root_module, "blblbla", &data);
|
||||
resp = new_response(RESPONSE_NOT_FOUND, strdup("statistics currently not working"));
|
||||
} else if(strcasecmp(message, "bye") == 0) {
|
||||
ret = CONTROL_CLOSE_HANDLE;
|
||||
resp = new_response(RESPONSE_OK, NULL);
|
||||
@@ -284,6 +297,9 @@ static bool parse_msg(char *buffer, char buffer_len, /* out */ char *message, in
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#define is_internal_port(x) (x == s->local_fd[1])
|
||||
|
||||
static void * control_thread(void *args)
|
||||
{
|
||||
struct control_state *s = (struct control_state *) args;
|
||||
@@ -310,7 +326,7 @@ static void * control_thread(void *args)
|
||||
|
||||
struct client *clients = NULL;
|
||||
|
||||
struct client *new_client = malloc(sizeof(struct client));
|
||||
struct client *new_client = (struct client *) malloc(sizeof(struct client));
|
||||
new_client->fd = s->local_fd[1];
|
||||
new_client->prev = NULL;
|
||||
new_client->next = NULL;
|
||||
@@ -319,25 +335,39 @@ static void * control_thread(void *args)
|
||||
|
||||
bool should_exit = false;
|
||||
|
||||
struct timeval last_report_sent;
|
||||
const int report_interval_sec = 5;
|
||||
gettimeofday(&last_report_sent, NULL);
|
||||
|
||||
while(!should_exit) {
|
||||
fd_set set;
|
||||
FD_ZERO(&set);
|
||||
FD_SET(fd, &set);
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(fd, &fds);
|
||||
int max_fd = fd + 1;
|
||||
|
||||
struct client *cur = clients;
|
||||
|
||||
while(cur) {
|
||||
FD_SET(cur->fd, &set);
|
||||
FD_SET(cur->fd, &fds);
|
||||
if(cur->fd + 1 > max_fd) {
|
||||
max_fd = cur->fd + 1;
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
if(select(max_fd, &set, NULL, NULL, NULL) >= 1) {
|
||||
if(FD_ISSET(fd, &set)) {
|
||||
struct client *new_client = malloc(sizeof(struct client));
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = report_interval_sec;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
struct timeval *timeout_ptr = NULL;
|
||||
if(clients->next != NULL) { // some remote client
|
||||
timeout_ptr = &timeout;
|
||||
}
|
||||
|
||||
if(select(max_fd, &fds, NULL, NULL, timeout_ptr) >= 1) {
|
||||
if(FD_ISSET(fd, &fds)) {
|
||||
struct client *new_client = (struct client *)
|
||||
malloc(sizeof(struct client));
|
||||
new_client->fd = accept(fd, (struct sockaddr *) &client_addr, &len);
|
||||
new_client->prev = NULL;
|
||||
new_client->next = clients;
|
||||
@@ -348,7 +378,7 @@ static void * control_thread(void *args)
|
||||
struct client *cur = clients;
|
||||
|
||||
while(cur) {
|
||||
if(FD_ISSET(cur->fd, &set)) {
|
||||
if(FD_ISSET(cur->fd, &fds)) {
|
||||
ssize_t ret = read(cur->fd, cur->buff + cur->buff_len,
|
||||
sizeof(cur->buff) - cur->buff_len);
|
||||
if(ret == -1) {
|
||||
@@ -381,7 +411,7 @@ static void * control_thread(void *args)
|
||||
cur->buff_len = cur_buffer_len;
|
||||
|
||||
int ret = process_msg(s, cur->fd, msg);
|
||||
if(ret == CONTROL_EXIT) {
|
||||
if(ret == CONTROL_EXIT && is_internal_port(cur->fd)) {
|
||||
should_exit = true;
|
||||
} else if(ret == CONTROL_CLOSE_HANDLE) {
|
||||
shutdown(cur->fd, SHUT_RDWR);
|
||||
@@ -394,6 +424,42 @@ static void * control_thread(void *args)
|
||||
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
struct timeval curr_time;
|
||||
gettimeofday(&curr_time, NULL);
|
||||
if(tv_diff(curr_time, last_report_sent) > report_interval_sec) {
|
||||
char buffer[1025];
|
||||
bool empty = true;
|
||||
memset(buffer, '\0', sizeof(buffer));
|
||||
strncpy(buffer + strlen(buffer), "stats", sizeof(buffer) -
|
||||
strlen(buffer) - 1);
|
||||
pthread_mutex_lock(&s->stats_lock);
|
||||
for(set<struct stats *>::iterator it = s->stats.begin();
|
||||
it != s->stats.end(); ++it) {
|
||||
empty = false;
|
||||
strncpy(buffer + strlen(buffer), " ", sizeof(buffer) -
|
||||
strlen(buffer) - 1);
|
||||
stats_format(*it, buffer + strlen(buffer),
|
||||
sizeof(buffer) - strlen(buffer));
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&s->stats_lock);
|
||||
strncpy(buffer + strlen(buffer), "\r\n", sizeof(buffer) -
|
||||
strlen(buffer) - 1);
|
||||
|
||||
if(strlen(buffer) < 1024 && !empty) {
|
||||
cur = clients;
|
||||
while(cur) {
|
||||
if(is_internal_port(cur->fd)) { // skip local FD
|
||||
cur = cur->next;
|
||||
continue;
|
||||
}
|
||||
write_all(cur->fd, buffer, strlen(buffer));
|
||||
cur = cur->next;
|
||||
}
|
||||
}
|
||||
last_report_sent = curr_time;
|
||||
}
|
||||
}
|
||||
|
||||
struct client *cur = clients;
|
||||
@@ -415,10 +481,30 @@ void control_done(struct control_state *s)
|
||||
return;
|
||||
}
|
||||
|
||||
module_done(&s->mod);
|
||||
|
||||
write_all(s->local_fd[0], "quit\r\n", 6);
|
||||
|
||||
pthread_join(s->thread_id, NULL);
|
||||
|
||||
close(s->local_fd[0]);
|
||||
|
||||
pthread_mutex_destroy(&s->stats_lock);
|
||||
|
||||
delete s;
|
||||
}
|
||||
|
||||
void control_add_stats(struct control_state *s, struct stats *stats)
|
||||
{
|
||||
pthread_mutex_lock(&s->stats_lock);
|
||||
s->stats.insert(stats);
|
||||
pthread_mutex_unlock(&s->stats_lock);
|
||||
}
|
||||
|
||||
void control_remove_stats(struct control_state *s, struct stats *stats)
|
||||
{
|
||||
pthread_mutex_lock(&s->stats_lock);
|
||||
s->stats.erase(stats);
|
||||
pthread_mutex_unlock(&s->stats_lock);
|
||||
}
|
||||
|
||||
@@ -45,8 +45,13 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
struct control_state;
|
||||
struct module;
|
||||
struct stats;
|
||||
|
||||
#define CONTROL_DEFAULT_PORT -1
|
||||
|
||||
@@ -55,4 +60,10 @@ struct module;
|
||||
*/
|
||||
int control_init(int port, struct control_state **state, struct module *root_module);
|
||||
void control_done(struct control_state *s);
|
||||
void control_add_stats(struct control_state *state, struct stats *stats);
|
||||
void control_remove_stats(struct control_state *state, struct stats *stats);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
|
||||
|
||||
57
src/crypto/crc.h
Normal file
57
src/crypto/crc.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
** CRC.H - header file for SNIPPETS CRC and checksum functions
|
||||
*/
|
||||
|
||||
#ifndef CRC__H
|
||||
#define CRC__H
|
||||
|
||||
#include <stdlib.h> /* For size_t */
|
||||
|
||||
/*
|
||||
** File: ARCCRC16.C
|
||||
*/
|
||||
|
||||
void init_crc_table(void);
|
||||
uint16_t crc_calc(uint16_t crc, char *buf, unsigned nbytes);
|
||||
void do_file(char *fn);
|
||||
|
||||
/*
|
||||
** File: CRC-16.C
|
||||
*/
|
||||
|
||||
uint16_t crc16(char *data_p, uint16_t length);
|
||||
|
||||
/*
|
||||
** File: CRC-16F.C
|
||||
*/
|
||||
|
||||
uint16_t updcrc(uint16_t icrc, uint8_t *icp, size_t icnt);
|
||||
|
||||
/*
|
||||
** File: CRC_32.C
|
||||
*/
|
||||
|
||||
#define UPDC32(octet,crc) (crc_32_tab[((crc)\
|
||||
^ ((uint8_t)octet)) & 0xff] ^ ((crc) >> 8))
|
||||
|
||||
uint32_t updateCRC32(unsigned char ch, uint32_t crc);
|
||||
bool crc32file(char *name, uint32_t *crc, long *charcnt);
|
||||
uint32_t crc32buf(char *buf, size_t len);
|
||||
|
||||
uint32_t crc32buf_with_oldcrc(char *buf, size_t len, uint32_t oldcrc);
|
||||
|
||||
/*
|
||||
** File: CHECKSUM.C
|
||||
*/
|
||||
|
||||
unsigned checksum(void *buffer, size_t len, unsigned int seed);
|
||||
|
||||
/*
|
||||
** File: CHECKEXE.C
|
||||
*/
|
||||
|
||||
void checkexe(char *fname);
|
||||
|
||||
|
||||
|
||||
#endif /* CRC__H */
|
||||
206
src/crypto/crc_32.c
Normal file
206
src/crypto/crc_32.c
Normal file
@@ -0,0 +1,206 @@
|
||||
/* Crc - 32 BIT ANSI X3.66 CRC checksum files */
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#include "config_unix.h"
|
||||
#include "config_win32.h"
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include "crc.h"
|
||||
|
||||
#ifdef __TURBOC__
|
||||
#pragma warn -cln
|
||||
#endif
|
||||
|
||||
/**********************************************************************\
|
||||
|* Demonstration program to compute the 32-bit CRC used as the frame *|
|
||||
|* check sequence in ADCCP (ANSI X3.66, also known as FIPS PUB 71 *|
|
||||
|* and FED-STD-1003, the U.S. versions of CCITT's X.25 link-level *|
|
||||
|* protocol). The 32-bit FCS was added via the Federal Register, *|
|
||||
|* 1 June 1982, p.23798. I presume but don't know for certain that *|
|
||||
|* this polynomial is or will be included in CCITT V.41, which *|
|
||||
|* defines the 16-bit CRC (often called CRC-CCITT) polynomial. FIPS *|
|
||||
|* PUB 78 says that the 32-bit FCS reduces otherwise undetected *|
|
||||
|* errors by a factor of 10^-5 over 16-bit FCS. *|
|
||||
\**********************************************************************/
|
||||
|
||||
/* Need an unsigned type capable of holding 32 bits; */
|
||||
|
||||
typedef uint32_t UNS_32_BITS;
|
||||
|
||||
/* Copyright (C) 1986 Gary S. Brown. You may use this program, or
|
||||
code or tables extracted from it, as desired without restriction.*/
|
||||
|
||||
/* First, the polynomial itself and its table of feedback terms. The */
|
||||
/* polynomial is */
|
||||
/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */
|
||||
/* Note that we take it "backwards" and put the highest-order term in */
|
||||
/* the lowest-order bit. The X^32 term is "implied"; the LSB is the */
|
||||
/* X^31 term, etc. The X^0 term (usually shown as "+1") results in */
|
||||
/* the MSB being 1. */
|
||||
|
||||
/* Note that the usual hardware shift register implementation, which */
|
||||
/* is what we're using (we're merely optimizing it by doing eight-bit */
|
||||
/* chunks at a time) shifts bits into the lowest-order term. In our */
|
||||
/* implementation, that means shifting towards the right. Why do we */
|
||||
/* do it this way? Because the calculated CRC must be transmitted in */
|
||||
/* order from highest-order term to lowest-order term. UARTs transmit */
|
||||
/* characters in order from LSB to MSB. By storing the CRC this way, */
|
||||
/* we hand it to the UART in the order low-byte to high-byte; the UART */
|
||||
/* sends each low-bit to hight-bit; and the result is transmission bit */
|
||||
/* by bit from highest- to lowest-order term without requiring any bit */
|
||||
/* shuffling on our part. Reception works similarly. */
|
||||
|
||||
/* The feedback terms table consists of 256, 32-bit entries. Notes: */
|
||||
/* */
|
||||
/* 1. The table can be generated at runtime if desired; code to do so */
|
||||
/* is shown later. It might not be obvious, but the feedback */
|
||||
/* terms simply represent the results of eight shift/xor opera- */
|
||||
/* tions for all combinations of data and CRC register values. */
|
||||
/* */
|
||||
/* 2. The CRC accumulation logic is the same for all CRC polynomials, */
|
||||
/* be they sixteen or thirty-two bits wide. You simply choose the */
|
||||
/* appropriate table. Alternatively, because the table can be */
|
||||
/* generated at runtime, you can start by generating the table for */
|
||||
/* the polynomial in question and use exactly the same "updcrc", */
|
||||
/* if your application needn't simultaneously handle two CRC */
|
||||
/* polynomials. (Note, however, that XMODEM is strange.) */
|
||||
/* */
|
||||
/* 3. For 16-bit CRCs, the table entries need be only 16 bits wide; */
|
||||
/* of course, 32-bit entries work OK if the high 16 bits are zero. */
|
||||
/* */
|
||||
/* 4. The values must be right-shifted by eight bits by the "updcrc" */
|
||||
/* logic; the shift must be unsigned (bring in zeroes). On some */
|
||||
/* hardware you could probably optimize the shift in assembler by */
|
||||
/* using byte-swap instructions. */
|
||||
|
||||
static UNS_32_BITS crc_32_tab[] = { /* CRC polynomial 0xedb88320 */
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
|
||||
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
||||
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
|
||||
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
||||
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
|
||||
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
|
||||
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
|
||||
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
||||
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
|
||||
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
|
||||
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
|
||||
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
||||
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
|
||||
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
|
||||
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
|
||||
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
||||
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
|
||||
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
|
||||
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
|
||||
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
||||
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
|
||||
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
|
||||
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
|
||||
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
||||
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
|
||||
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
|
||||
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
|
||||
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
||||
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
|
||||
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
|
||||
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
|
||||
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
||||
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
|
||||
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
|
||||
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
|
||||
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
||||
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
|
||||
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
|
||||
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
|
||||
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
||||
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
|
||||
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
|
||||
};
|
||||
|
||||
uint32_t updateCRC32(unsigned char ch, uint32_t crc)
|
||||
{
|
||||
return UPDC32(ch, crc);
|
||||
}
|
||||
|
||||
bool crc32file(char *name, uint32_t *crc, long *charcnt)
|
||||
{
|
||||
register FILE *fin;
|
||||
register uint32_t oldcrc32;
|
||||
register int c;
|
||||
|
||||
oldcrc32 = 0xFFFFFFFF; *charcnt = 0;
|
||||
#ifdef MSDOS
|
||||
if ((fin=fopen(name, "rb"))==NULL)
|
||||
#else
|
||||
if ((fin=fopen(name, "r"))==NULL)
|
||||
#endif
|
||||
{
|
||||
perror(name);
|
||||
return false;
|
||||
}
|
||||
while ((c=getc(fin))!=EOF)
|
||||
{
|
||||
++*charcnt;
|
||||
oldcrc32 = UPDC32(c, oldcrc32);
|
||||
}
|
||||
|
||||
if (ferror(fin))
|
||||
{
|
||||
perror(name);
|
||||
*charcnt = -1;
|
||||
}
|
||||
fclose(fin);
|
||||
|
||||
*crc = oldcrc32 = ~oldcrc32;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t crc32buf(char *buf, size_t len)
|
||||
{
|
||||
register uint32_t oldcrc32;
|
||||
|
||||
oldcrc32 = 0xFFFFFFFF;
|
||||
|
||||
for ( ; len; --len, ++buf)
|
||||
{
|
||||
oldcrc32 = UPDC32(*buf, oldcrc32);
|
||||
}
|
||||
|
||||
return ~oldcrc32;
|
||||
}
|
||||
|
||||
uint32_t crc32buf_with_oldcrc(char *buf, size_t len, uint32_t old_crc)
|
||||
{
|
||||
register uint32_t oldcrc32;
|
||||
|
||||
oldcrc32 = old_crc;
|
||||
|
||||
for ( ; len; --len, ++buf)
|
||||
{
|
||||
oldcrc32 = UPDC32(*buf, oldcrc32);
|
||||
}
|
||||
|
||||
return ~oldcrc32;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
uint32_t crc;
|
||||
long charcnt;
|
||||
register errors = 0;
|
||||
|
||||
while(--argc > 0)
|
||||
{
|
||||
errors |= crc32file(*++argv, &crc, &charcnt);
|
||||
printf("%08lX %7ld %s\n", crc, charcnt, *argv);
|
||||
}
|
||||
return(errors != 0);
|
||||
}
|
||||
|
||||
#endif /* TEST */
|
||||
185
src/crypto/openssl_decrypt.c
Normal file
185
src/crypto/openssl_decrypt.c
Normal file
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* FILE: aes_decrypt.c
|
||||
* AUTHOR: Colin Perkins <csp@csperkins.org>
|
||||
* Ladan Gharai
|
||||
* Martin Benes <martinbenesh@gmail.com>
|
||||
* Lukas Hejtmanek <xhejtman@ics.muni.cz>
|
||||
* Petr Holub <hopet@ics.muni.cz>
|
||||
* Milos Liska <xliska@fi.muni.cz>
|
||||
* Jiri Matela <matela@ics.muni.cz>
|
||||
* Dalibor Matura <255899@mail.muni.cz>
|
||||
* Ian Wesley-Smith <iwsmith@cct.lsu.edu>
|
||||
*
|
||||
* Copyright (c) 2001-2004 University of Southern California
|
||||
* Copyright (c) 2005-2010 CESNET z.s.p.o.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, is permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
*
|
||||
* This product includes software developed by the University of Southern
|
||||
* California Information Sciences Institute. This product also includes
|
||||
* software developed by CESNET z.s.p.o.
|
||||
*
|
||||
* 4. Neither the name of the University, Institute, CESNET nor the names of
|
||||
* its contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#include "config_unix.h"
|
||||
#include "config_win32.h"
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
#ifdef HAVE_CRYPTO
|
||||
|
||||
#include "crypto/crc.h"
|
||||
#include "crypto/md5.h"
|
||||
#include "crypto/openssl_decrypt.h"
|
||||
#include "debug.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <openssl/aes.h>
|
||||
|
||||
struct openssl_decrypt {
|
||||
AES_KEY key;
|
||||
|
||||
enum openssl_mode mode;
|
||||
|
||||
unsigned char ivec[AES_BLOCK_SIZE];
|
||||
unsigned char ecount[AES_BLOCK_SIZE];
|
||||
unsigned int num;
|
||||
};
|
||||
|
||||
int openssl_decrypt_init(struct openssl_decrypt **state,
|
||||
const char *passphrase,
|
||||
enum openssl_mode mode)
|
||||
{
|
||||
struct openssl_decrypt *s =
|
||||
(struct openssl_decrypt *)
|
||||
calloc(1, sizeof(struct openssl_decrypt));
|
||||
|
||||
MD5_CTX context;
|
||||
unsigned char hash[16];
|
||||
|
||||
MD5Init(&context);
|
||||
MD5Update(&context, (unsigned char *) passphrase,
|
||||
strlen(passphrase));
|
||||
MD5Final(hash, &context);
|
||||
|
||||
switch(mode) {
|
||||
case MODE_AES128_ECB:
|
||||
AES_set_decrypt_key(hash, 128, &s->key);
|
||||
break;
|
||||
case MODE_AES128_CTR:
|
||||
AES_set_encrypt_key(hash, 128, &s->key);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
s->mode = mode;
|
||||
|
||||
*state = s;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void openssl_decrypt_destroy(struct openssl_decrypt *s)
|
||||
{
|
||||
if(!s)
|
||||
return;
|
||||
free(s);
|
||||
}
|
||||
|
||||
static void openssl_decrypt_block(struct openssl_decrypt *s,
|
||||
unsigned char *ciphertext, unsigned char *plaintext, const char *nonce_and_counter,
|
||||
int len)
|
||||
{
|
||||
if(nonce_and_counter) {
|
||||
memcpy(s->ivec, nonce_and_counter, AES_BLOCK_SIZE);
|
||||
s->num = 0;
|
||||
}
|
||||
|
||||
switch(s->mode) {
|
||||
case MODE_AES128_ECB:
|
||||
assert(len == AES_BLOCK_SIZE);
|
||||
AES_ecb_encrypt(ciphertext, plaintext,
|
||||
&s->key, AES_DECRYPT);
|
||||
break;
|
||||
case MODE_AES128_CTR:
|
||||
AES_ctr128_encrypt(ciphertext, plaintext, len, &s->key, s->ivec,
|
||||
s->ecount, &s->num);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
int openssl_decrypt(struct openssl_decrypt *decrypt,
|
||||
const char *ciphertext, int ciphertext_len,
|
||||
const char *aad, int aad_len,
|
||||
char *plaintext)
|
||||
{
|
||||
UNUSED(ciphertext_len);
|
||||
uint32_t data_len;
|
||||
memcpy(&data_len, ciphertext, sizeof(uint32_t));
|
||||
ciphertext += sizeof(uint32_t);
|
||||
|
||||
const char *nonce_and_counter = ciphertext;
|
||||
ciphertext += 16;
|
||||
uint32_t expected_crc;
|
||||
uint32_t crc = 0xffffffff;
|
||||
if(aad > 0) {
|
||||
crc = crc32buf_with_oldcrc((char *) aad, aad_len, crc);
|
||||
}
|
||||
for(unsigned int i = 0; i < data_len; i += 16) {
|
||||
int block_length = 16;
|
||||
if(data_len - i < 16) block_length = data_len - i;
|
||||
#ifdef HAVE_CRYPTO
|
||||
openssl_decrypt_block(decrypt,
|
||||
(unsigned char *) ciphertext + i,
|
||||
(unsigned char *) plaintext + i,
|
||||
nonce_and_counter, block_length);
|
||||
#endif // HAVE_CRYPTO
|
||||
nonce_and_counter = NULL;
|
||||
crc = crc32buf_with_oldcrc((char *) plaintext + i, block_length, crc);
|
||||
}
|
||||
#ifdef HAVE_CRYPTO
|
||||
openssl_decrypt_block(decrypt,
|
||||
(unsigned char *) ciphertext + data_len,
|
||||
(unsigned char *) &expected_crc,
|
||||
0, sizeof(uint32_t));
|
||||
#endif // HAVE_CRYPTO
|
||||
if(crc != expected_crc) {
|
||||
return 0;
|
||||
}
|
||||
return data_len;
|
||||
}
|
||||
|
||||
#endif // HAVE_CRYPTO
|
||||
|
||||
93
src/crypto/openssl_decrypt.h
Normal file
93
src/crypto/openssl_decrypt.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* FILE: openssl_encrypt.h
|
||||
* AUTHOR: Colin Perkins <csp@isi.edu>
|
||||
* Martin Benes <martinbenesh@gmail.com>
|
||||
* Lukas Hejtmanek <xhejtman@ics.muni.cz>
|
||||
* Petr Holub <hopet@ics.muni.cz>
|
||||
* Milos Liska <xliska@fi.muni.cz>
|
||||
* Jiri Matela <matela@ics.muni.cz>
|
||||
* Dalibor Matura <255899@mail.muni.cz>
|
||||
* Ian Wesley-Smith <iwsmith@cct.lsu.edu>
|
||||
*
|
||||
* Copyright (c) 2001-2002 University of Southern California
|
||||
* Copyright (c) 2005-2010 CESNET z.s.p.o.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, is permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
*
|
||||
* This product includes software developed by the University of Southern
|
||||
* California Information Sciences Institute. This product also includes
|
||||
* software developed by CESNET z.s.p.o.
|
||||
*
|
||||
* 4. Neither the name of the University, Institute, CESNET nor the names of
|
||||
* its contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef OPENSSL_DECRYPT_H_
|
||||
#define OPENSSL_DECRYPT_H_
|
||||
|
||||
#include "crypto/openssl_encrypt.h"
|
||||
|
||||
struct openssl_decrypt;
|
||||
|
||||
/**
|
||||
* Creates decryption state
|
||||
*
|
||||
* @param[out] state state pointer
|
||||
* @param[in] passphrase key material (NULL-terminated)
|
||||
* @param[in] mode mode
|
||||
* @retval 0 ok
|
||||
* @retval <0 failure
|
||||
* @retval >0 state was not created
|
||||
*/
|
||||
int openssl_decrypt_init(struct openssl_decrypt **state,
|
||||
const char *passphrase, enum openssl_mode mode);
|
||||
/**
|
||||
* Destroys decryption state
|
||||
*/
|
||||
void openssl_decrypt_destroy(struct openssl_decrypt *state);
|
||||
/**
|
||||
* Decrypts block of data
|
||||
*
|
||||
* @param[in] decrypt decrypt state
|
||||
* @param[in] ciphertext encrypted text
|
||||
* @param[in] ciphertext_len lenght of encrypted text
|
||||
* @param[in] aad Aditional Authenticated Data (see openssl_encrypt documentation)
|
||||
* @param[in] aad_len length of aad block
|
||||
* @param[out] plaintext otput plaintext
|
||||
* @retval 0 if checksum doesn't match
|
||||
* @retval >0 length of output plaintext
|
||||
*/
|
||||
int openssl_decrypt(struct openssl_decrypt *decrypt,
|
||||
const char *ciphertext, int ciphertext_len,
|
||||
const char *aad, int aad_len,
|
||||
char *plaintext);
|
||||
|
||||
#endif // OPENSSL_DECRYPT_H_
|
||||
|
||||
186
src/crypto/openssl_encrypt.c
Normal file
186
src/crypto/openssl_encrypt.c
Normal file
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* FILE: aes_encrypt.c
|
||||
* AUTHOR: Colin Perkins <csp@csperkins.org>
|
||||
* Ladan Gharai
|
||||
* Martin Benes <martinbenesh@gmail.com>
|
||||
* Lukas Hejtmanek <xhejtman@ics.muni.cz>
|
||||
* Petr Holub <hopet@ics.muni.cz>
|
||||
* Milos Liska <xliska@fi.muni.cz>
|
||||
* Jiri Matela <matela@ics.muni.cz>
|
||||
* Dalibor Matura <255899@mail.muni.cz>
|
||||
* Ian Wesley-Smith <iwsmith@cct.lsu.edu>
|
||||
*
|
||||
* Copyright (c) 2001-2004 University of Southern California
|
||||
* Copyright (c) 2005-2010 CESNET z.s.p.o.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, is permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
*
|
||||
* This product includes software developed by the University of Southern
|
||||
* California Information Sciences Institute. This product also includes
|
||||
* software developed by CESNET z.s.p.o.
|
||||
*
|
||||
* 4. Neither the name of the University, Institute, CESNET nor the names of
|
||||
* its contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#include "config_unix.h"
|
||||
#include "config_win32.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CRYPTO
|
||||
|
||||
#include "crypto/crc.h"
|
||||
#include "crypto/md5.h"
|
||||
#include "crypto/openssl_encrypt.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
struct openssl_encrypt {
|
||||
AES_KEY key;
|
||||
|
||||
enum openssl_mode mode;
|
||||
|
||||
unsigned char ivec[16];
|
||||
unsigned int num;
|
||||
unsigned char ecount[16];
|
||||
};
|
||||
|
||||
int openssl_encrypt_init(struct openssl_encrypt **state, const char *passphrase,
|
||||
enum openssl_mode mode)
|
||||
{
|
||||
struct openssl_encrypt *s = (struct openssl_encrypt *)
|
||||
calloc(1, sizeof(struct openssl_encrypt));
|
||||
|
||||
MD5_CTX context;
|
||||
unsigned char hash[16];
|
||||
|
||||
if (!RAND_bytes(s->ivec, 8)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
MD5Init(&context);
|
||||
MD5Update(&context, (unsigned char *) passphrase,
|
||||
strlen(passphrase));
|
||||
MD5Final(hash, &context);
|
||||
|
||||
AES_set_encrypt_key(hash, 128, &s->key);
|
||||
s->mode = mode;
|
||||
assert(s->mode == MODE_AES128_CTR); // only functional by now
|
||||
|
||||
*state = s;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void openssl_encrypt_block(struct openssl_encrypt *s, unsigned char *plaintext,
|
||||
unsigned char *ciphertext, char *nonce_plus_counter, int len)
|
||||
{
|
||||
if(nonce_plus_counter) {
|
||||
memcpy(nonce_plus_counter, (char *) s->ivec, 16);
|
||||
/* We do start a new block so we zero the byte counter
|
||||
* Please NB that counter doesn't need to be incremented
|
||||
* because the counter is incremented everytime s->num == 0,
|
||||
* presumably before encryption, so setting it to 0 forces
|
||||
* counter increment as well.
|
||||
*/
|
||||
if(s->num != 0) {
|
||||
s->num = 0;
|
||||
}
|
||||
}
|
||||
|
||||
switch(s->mode) {
|
||||
case MODE_AES128_CTR:
|
||||
AES_ctr128_encrypt(plaintext, ciphertext, len, &s->key, s->ivec,
|
||||
s->ecount, &s->num);
|
||||
break;
|
||||
case MODE_AES128_ECB:
|
||||
assert(len == AES_BLOCK_SIZE);
|
||||
AES_ecb_encrypt(plaintext, ciphertext,
|
||||
&s->key, AES_ENCRYPT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void openssl_encrypt_destroy(struct openssl_encrypt *s)
|
||||
{
|
||||
free(s);
|
||||
}
|
||||
|
||||
int openssl_encrypt(struct openssl_encrypt *encryption,
|
||||
char *plaintext, int data_len, char *aad, int aad_len, char *ciphertext) {
|
||||
uint32_t crc = 0xffffffff;
|
||||
memcpy(ciphertext, &data_len, sizeof(uint32_t));
|
||||
ciphertext += sizeof(uint32_t);
|
||||
char *nonce_and_counter = ciphertext;
|
||||
ciphertext += 16;
|
||||
|
||||
if(aad_len > 0) {
|
||||
crc = crc32buf_with_oldcrc(aad, aad_len, crc);
|
||||
}
|
||||
|
||||
for(int i = 0; i < data_len; i+=16) {
|
||||
int block_length = 16;
|
||||
if(data_len - i < 16) block_length = data_len - i;
|
||||
crc = crc32buf_with_oldcrc(plaintext + i, block_length, crc);
|
||||
#ifdef HAVE_CRYPTO
|
||||
openssl_encrypt_block(encryption,
|
||||
(unsigned char *) plaintext + i,
|
||||
(unsigned char *) ciphertext + i,
|
||||
nonce_and_counter,
|
||||
block_length);
|
||||
nonce_and_counter = NULL;
|
||||
#endif // HAVE_CRYPTO
|
||||
}
|
||||
#ifdef HAVE_CRYPTO
|
||||
openssl_encrypt_block(encryption,
|
||||
(unsigned char *) &crc,
|
||||
(unsigned char *) ciphertext + data_len,
|
||||
NULL,
|
||||
sizeof(uint32_t));
|
||||
#endif // HAVE_CRYPTO
|
||||
return data_len + sizeof(crc) + 16 + sizeof(uint32_t);
|
||||
}
|
||||
|
||||
int openssl_get_overhead(struct openssl_encrypt *s)
|
||||
{
|
||||
switch(s->mode) {
|
||||
case MODE_AES128_CTR:
|
||||
return sizeof(uint32_t) /* data_len */ +
|
||||
16 /* nonce + counter */ + sizeof(uint32_t) /* crc */;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // HAVE_CRYPTO
|
||||
|
||||
113
src/crypto/openssl_encrypt.h
Normal file
113
src/crypto/openssl_encrypt.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* FILE: aes_encrypt.h
|
||||
* AUTHOR: Colin Perkins <csp@isi.edu>
|
||||
* Martin Benes <martinbenesh@gmail.com>
|
||||
* Lukas Hejtmanek <xhejtman@ics.muni.cz>
|
||||
* Petr Holub <hopet@ics.muni.cz>
|
||||
* Milos Liska <xliska@fi.muni.cz>
|
||||
* Jiri Matela <matela@ics.muni.cz>
|
||||
* Dalibor Matura <255899@mail.muni.cz>
|
||||
* Ian Wesley-Smith <iwsmith@cct.lsu.edu>
|
||||
*
|
||||
* Copyright (c) 2001-2002 University of Southern California
|
||||
* Copyright (c) 2005-2010 CESNET z.s.p.o.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, is permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
*
|
||||
* This product includes software developed by the University of Southern
|
||||
* California Information Sciences Institute. This product also includes
|
||||
* software developed by CESNET z.s.p.o.
|
||||
*
|
||||
* 4. Neither the name of the University, Institute, CESNET nor the names of
|
||||
* its contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef OPENSSL_ENCRYPT_H_
|
||||
#define OPENSSL_ENCRYPT_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
struct openssl_encrypt;
|
||||
|
||||
enum openssl_mode {
|
||||
MODE_AES128_CTR, // no autenticity, only integrity (CRC)
|
||||
MODE_AES128_ECB // do not use
|
||||
};
|
||||
|
||||
#define MAX_CRYPTO_EXTRA_DATA 24 // == maximal overhead of available encryptions
|
||||
#define MAX_CRYPTO_PAD 0 // CTR does not need padding
|
||||
#define MAX_CRYPTO_EXCEED (MAX_CRYPTO_EXTRA_DATA + MAX_CRYPTO_PAD)
|
||||
|
||||
/**
|
||||
* Initializes encryption
|
||||
* @param[out] state created state
|
||||
* @param[in] passphrase key material (NULL-terminated)
|
||||
* @param[in] mode
|
||||
* @retval 0 success
|
||||
* @retval <0 failure
|
||||
* @retval >0 state not created
|
||||
*/
|
||||
int openssl_encrypt_init(struct openssl_encrypt **state,
|
||||
const char *passphrase, enum openssl_mode mode);
|
||||
/**
|
||||
* Destroys state
|
||||
*/
|
||||
void openssl_encrypt_destroy(struct openssl_encrypt *state);
|
||||
/**
|
||||
* Encrypts a block of data
|
||||
*
|
||||
* @param[in] encryption state
|
||||
* @param[in] plaintext plain text
|
||||
* @param[in] plaintext_len length of plain text
|
||||
* @param[in] aad Additional Authenticated Data
|
||||
* this won't be encrypted but passed in plaintext along ciphertext.
|
||||
* These data are autheticated only if working in some AE mode
|
||||
* @param[in] aad_len length of AAD text
|
||||
* @param[out] ciphertext resulting ciphertext, can be up to (plaintext_len + MAX_CRYPTO_EXCEED) length
|
||||
* @returns size of writen ciphertext
|
||||
*/
|
||||
int openssl_encrypt(struct openssl_encrypt *encryption,
|
||||
char *plaintext, int plaintext_len, char *aad, int aad_len, char *ciphertext);
|
||||
/**
|
||||
* Returns maximal number of bytest that the ciphertext length may exceed plaintext for selected
|
||||
* encryption.
|
||||
*
|
||||
* @param[in] encryption state
|
||||
* @returns max overhead (must be <= MAX_CRYPTO_EXCEED)
|
||||
*/
|
||||
int openssl_get_overhead(struct openssl_encrypt *encryption);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // OPENSSL_ENCRYPT_H_
|
||||
|
||||
@@ -171,7 +171,8 @@ void *recompress_init(struct module *parent,
|
||||
|
||||
s->required_compress = strdup(compress);
|
||||
s->frame = NULL;
|
||||
s->tx = tx_init(s->parent, mtu, TX_MEDIA_VIDEO, fec);
|
||||
const char *requested_encryption = NULL;
|
||||
s->tx = tx_init(s->parent, mtu, TX_MEDIA_VIDEO, fec, requested_encryption);
|
||||
|
||||
gettimeofday(&s->start_time, NULL);
|
||||
|
||||
|
||||
73
src/main.c
73
src/main.c
@@ -122,6 +122,7 @@
|
||||
#define OPT_IMPORT (('I' << 8) | 'M')
|
||||
#define OPT_AUDIO_CODEC (('A' << 8) | 'C')
|
||||
#define OPT_CAPTURE_FILTER (('O' << 8) | 'F')
|
||||
#define OPT_ENCRYPTION (('E' << 8) | 'N')
|
||||
|
||||
#ifdef HAVE_MACOSX
|
||||
#define INITIAL_VIDEO_RECV_BUFFER_SIZE 5944320
|
||||
@@ -162,6 +163,12 @@ struct state_uv {
|
||||
pthread_mutex_t master_lock;
|
||||
|
||||
struct video_export *video_exporter;
|
||||
|
||||
struct sender_data sender_data;
|
||||
|
||||
struct module *root_module;
|
||||
|
||||
const char *requested_encryption;
|
||||
};
|
||||
|
||||
static volatile int wait_to_finish = FALSE;
|
||||
@@ -309,6 +316,8 @@ static void usage(void)
|
||||
printf("\n");
|
||||
printf("\t--capture-filter <filter>\tCapture filter(s)\n");
|
||||
printf("\n");
|
||||
printf("\t--encryption <passphrase>\tKey material for encryption\n");
|
||||
printf("\n");
|
||||
printf("\taddress(es) \tdestination address\n");
|
||||
printf("\n");
|
||||
printf("\t \tIf comma-separated list of addresses\n");
|
||||
@@ -454,13 +463,6 @@ static void destroy_devices(struct rtp ** network_devices)
|
||||
free(network_devices);
|
||||
}
|
||||
|
||||
static struct tx *initialize_transmit(struct module *parent, unsigned requested_mtu, char *fec)
|
||||
{
|
||||
/* Currently this is trivial. It'll get more complex once we */
|
||||
/* have multiple codecs and/or error correction. */
|
||||
return tx_init(parent, requested_mtu, TX_MEDIA_VIDEO, fec);
|
||||
}
|
||||
|
||||
#ifdef HAVE_IHDTV
|
||||
static void *ihdtv_receiver_thread(void *arg)
|
||||
{
|
||||
@@ -504,7 +506,8 @@ static struct vcodec_state *new_decoder(struct state_uv *uv) {
|
||||
|
||||
if(state) {
|
||||
state->messages = simple_linked_list_init();
|
||||
state->decoder = decoder_init(uv->decoder_mode, uv->postprocess, uv->display_device);
|
||||
state->decoder = decoder_init(uv->decoder_mode, uv->postprocess, uv->display_device,
|
||||
uv->requested_encryption);
|
||||
|
||||
if(!state->decoder) {
|
||||
fprintf(stderr, "Error initializing decoder (incorrect '-M' or '-p' option?).\n");
|
||||
@@ -563,7 +566,11 @@ static void *receiver_thread(void *arg)
|
||||
|
||||
fr = 1;
|
||||
|
||||
stat_loss = stats_new_statistics("loss");
|
||||
struct module *control_mod = get_module(get_root_module(uv->root_module), "control");
|
||||
stat_loss = stats_new_statistics(
|
||||
(struct control_state *) control_mod,
|
||||
"loss");
|
||||
unlock_module(control_mod);
|
||||
|
||||
while (!should_exit_receiver) {
|
||||
/* Housekeeping and RTCP... */
|
||||
@@ -712,7 +719,6 @@ static void *compress_thread(void *arg)
|
||||
{
|
||||
struct module *uv_mod = (struct module *)arg;
|
||||
struct state_uv *uv = (struct state_uv *) uv_mod->priv_data;
|
||||
struct sender_data sender_data;
|
||||
|
||||
struct video_frame *tx_frame;
|
||||
struct audio_frame *audio;
|
||||
@@ -722,17 +728,17 @@ static void *compress_thread(void *arg)
|
||||
struct compress_state *compression;
|
||||
int ret = compress_init(uv_mod, uv->requested_compression, &compression);
|
||||
|
||||
sender_data.parent = uv_mod; /// @todo should be compress thread module
|
||||
sender_data.connections_count = uv->connections_count;
|
||||
sender_data.tx_protocol = uv->tx_protocol;
|
||||
uv->sender_data.parent = uv_mod; /// @todo should be compress thread module
|
||||
uv->sender_data.connections_count = uv->connections_count;
|
||||
uv->sender_data.tx_protocol = uv->tx_protocol;
|
||||
if(uv->tx_protocol == ULTRAGRID_RTP) {
|
||||
sender_data.network_devices = uv->network_devices;
|
||||
uv->sender_data.network_devices = uv->network_devices;
|
||||
} else {
|
||||
sender_data.sage_tx_device = uv->sage_tx_device;
|
||||
uv->sender_data.sage_tx_device = uv->sage_tx_device;
|
||||
}
|
||||
sender_data.tx = uv->tx;
|
||||
uv->sender_data.tx = uv->tx;
|
||||
|
||||
if(!sender_init(&sender_data)) {
|
||||
if(!sender_init(&uv->sender_data)) {
|
||||
fprintf(stderr, "Error initializing sender.\n");
|
||||
exit_uv(1);
|
||||
pthread_mutex_unlock(&uv->master_lock);
|
||||
@@ -780,13 +786,13 @@ static void *compress_thread(void *arg)
|
||||
nonblock = false;
|
||||
}
|
||||
|
||||
sender_post_new_frame(&sender_data, tx_frame, nonblock);
|
||||
sender_post_new_frame(&uv->sender_data, tx_frame, nonblock);
|
||||
}
|
||||
}
|
||||
|
||||
vidcap_finish(uv_state->capture_device);
|
||||
|
||||
sender_done(&sender_data);
|
||||
sender_done(&uv->sender_data);
|
||||
|
||||
compress_done:
|
||||
module_done(CAST_MODULE(compression));
|
||||
@@ -933,12 +939,13 @@ int main(int argc, char *argv[])
|
||||
{"audio-host", required_argument, 0, 'A'},
|
||||
{"audio-codec", required_argument, 0, OPT_AUDIO_CODEC},
|
||||
{"capture-filter", required_argument, 0, OPT_CAPTURE_FILTER},
|
||||
{"encryption", required_argument, 0, OPT_ENCRYPTION},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
int option_index = 0;
|
||||
|
||||
// uv = (struct state_uv *) calloc(1, sizeof(struct state_uv));
|
||||
uv = (struct state_uv *)malloc(sizeof(struct state_uv));
|
||||
uv = (struct state_uv *) calloc(1, sizeof(struct state_uv));
|
||||
uv_state = uv;
|
||||
|
||||
uv->audio = NULL;
|
||||
@@ -962,6 +969,7 @@ int main(int argc, char *argv[])
|
||||
uv->sage_tx_device = NULL;
|
||||
|
||||
init_root_module(&root_mod, uv);
|
||||
uv->root_module = &root_mod;
|
||||
|
||||
pthread_mutex_init(&uv->master_lock, NULL);
|
||||
|
||||
@@ -1178,6 +1186,9 @@ int main(int argc, char *argv[])
|
||||
case OPT_CAPTURE_FILTER:
|
||||
requested_capture_filter = optarg;
|
||||
break;
|
||||
case OPT_ENCRYPTION:
|
||||
uv->requested_encryption = optarg;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
@@ -1225,6 +1236,10 @@ int main(int argc, char *argv[])
|
||||
audio_rx_port = uv->recv_port_number + 2;
|
||||
}
|
||||
|
||||
if(control_init(CONTROL_DEFAULT_PORT, &control, &root_mod) != 0) {
|
||||
fprintf(stderr, "Warning: Unable to initialize remote control!\n:");
|
||||
}
|
||||
|
||||
if(should_export) {
|
||||
if(!enable_export(export_opts)) {
|
||||
fprintf(stderr, "Export initialization failed.\n");
|
||||
@@ -1281,7 +1296,8 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
uv->audio = audio_cfg_init (&root_mod, audio_host, audio_rx_port,
|
||||
audio_tx_port, audio_send, audio_recv,
|
||||
jack_cfg, requested_audio_fec, audio_channel_map,
|
||||
jack_cfg, requested_audio_fec, uv->requested_encryption,
|
||||
audio_channel_map,
|
||||
audio_scale, echo_cancellation, use_ipv6, mcast_if,
|
||||
audio_codec, compressed_audio_sample_rate);
|
||||
free(requested_audio_fec);
|
||||
@@ -1445,8 +1461,10 @@ int main(int argc, char *argv[])
|
||||
packet_rate = 0;
|
||||
}
|
||||
|
||||
if ((uv->tx = initialize_transmit(&root_mod,
|
||||
uv->requested_mtu, requested_video_fec)) == NULL) {
|
||||
if ((uv->tx = tx_init(&root_mod,
|
||||
uv->requested_mtu, TX_MEDIA_VIDEO,
|
||||
requested_video_fec,
|
||||
uv->requested_encryption)) == NULL) {
|
||||
printf("Unable to initialize transmitter.\n");
|
||||
exit_uv(EXIT_FAIL_TRANSMIT);
|
||||
goto cleanup_wait_display;
|
||||
@@ -1469,7 +1487,8 @@ int main(int argc, char *argv[])
|
||||
/* following block only shows help (otherwise initialized in receiver thread */
|
||||
if((uv->postprocess && strstr(uv->postprocess, "help") != NULL) ||
|
||||
(uv->decoder_mode && strstr(uv->decoder_mode, "help") != NULL)) {
|
||||
struct state_decoder *dec = decoder_init(uv->decoder_mode, uv->postprocess, NULL);
|
||||
struct state_decoder *dec = decoder_init(uv->decoder_mode, uv->postprocess, NULL,
|
||||
uv->requested_encryption);
|
||||
decoder_destroy(dec);
|
||||
exit_uv(EXIT_SUCCESS);
|
||||
goto cleanup_wait_display;
|
||||
@@ -1518,10 +1537,6 @@ int main(int argc, char *argv[])
|
||||
|
||||
pthread_mutex_lock(&uv->master_lock);
|
||||
|
||||
if(control_init(CONTROL_DEFAULT_PORT, &control, &root_mod) != 0) {
|
||||
fprintf(stderr, "Warning: Unable to initialize remote control!\n:");
|
||||
}
|
||||
|
||||
if(audio_get_display_flags(uv->audio)) {
|
||||
audio_register_put_callback(uv->audio, (void (*)(void *, struct audio_frame *)) display_put_audio_frame, uv->display_device);
|
||||
audio_register_reconfigure_callback(uv->audio, (int (*)(void *, int, int,
|
||||
@@ -1595,6 +1610,8 @@ cleanup:
|
||||
|
||||
control_done(control);
|
||||
|
||||
module_done(&root_mod);
|
||||
|
||||
printf("Exit\n");
|
||||
|
||||
return exit_status;
|
||||
|
||||
@@ -10,56 +10,10 @@
|
||||
#include "utils/list.h"
|
||||
#include "utils/lock_guard.h"
|
||||
|
||||
static struct module *find_child(struct module *node, const char *node_name, int index)
|
||||
{
|
||||
for(void *it = simple_linked_list_it_init(node->childs); it != NULL; ) {
|
||||
struct module *child = (struct module *) simple_linked_list_it_next(&it);
|
||||
if(strcasecmp(module_class_name(child->cls), node_name) == 0) {
|
||||
if(index-- == 0) {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void get_receiver_index(char *node_str, int *index) {
|
||||
*index = 0;
|
||||
if(strchr(node_str, '[')) {
|
||||
*index = atoi(strchr(node_str, '[') + 1);
|
||||
*strchr(node_str, '[') = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
struct response *send_message(struct module *root, const char *const_path, struct message *msg)
|
||||
{
|
||||
struct module *receiver = root;
|
||||
char *path, *tmp;
|
||||
char *item, *save_ptr;
|
||||
char buf[1024];
|
||||
|
||||
assert(root != NULL);
|
||||
|
||||
pthread_mutex_lock(&receiver->lock);
|
||||
|
||||
tmp = path = strdup(const_path);
|
||||
while ((item = strtok_r(path, ".", &save_ptr))) {
|
||||
struct module *old_receiver = receiver;
|
||||
int index;
|
||||
get_receiver_index(item, &index);
|
||||
receiver = find_child(receiver, item, index);
|
||||
if(!receiver) {
|
||||
pthread_mutex_unlock(&old_receiver->lock);
|
||||
break;
|
||||
}
|
||||
pthread_mutex_lock(&receiver->lock);
|
||||
pthread_mutex_unlock(&old_receiver->lock);
|
||||
|
||||
path = NULL;
|
||||
|
||||
}
|
||||
free(tmp);
|
||||
|
||||
struct module *receiver = get_module(root, const_path);
|
||||
/**
|
||||
* @invariant
|
||||
* either receiver is NULL or receiver->lock is locked (exactly once)
|
||||
|
||||
@@ -50,12 +50,14 @@ struct msg_change_fec_data {
|
||||
char fec[128];
|
||||
};
|
||||
|
||||
enum compress_change_type {
|
||||
CHANGE_COMPRESS,
|
||||
CHANGE_PARAMS
|
||||
};
|
||||
|
||||
struct msg_change_compress_data {
|
||||
struct message m;
|
||||
enum {
|
||||
CHANGE_COMPRESS,
|
||||
CHANGE_PARAMS
|
||||
} what;
|
||||
enum compress_change_type what;
|
||||
char config_string[128];
|
||||
};
|
||||
|
||||
|
||||
68
src/module.c
68
src/module.c
@@ -124,6 +124,7 @@ const char *module_class_name_pairs[] = {
|
||||
[MODULE_CLASS_SENDER] = "sender",
|
||||
[MODULE_CLASS_TX] = "transmit",
|
||||
[MODULE_CLASS_AUDIO] = "audio",
|
||||
[MODULE_CLASS_CONTROL] = "control",
|
||||
};
|
||||
|
||||
const char *module_class_name(enum module_class cls)
|
||||
@@ -150,3 +151,70 @@ void append_message_path(char *buf, int buflen, enum module_class modules[])
|
||||
}
|
||||
}
|
||||
|
||||
struct module *get_root_module(struct module *node)
|
||||
{
|
||||
while(node->parent) {
|
||||
node = node->parent;
|
||||
}
|
||||
assert(node->cls == MODULE_CLASS_ROOT);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static struct module *find_child(struct module *node, const char *node_name, int index)
|
||||
{
|
||||
for(void *it = simple_linked_list_it_init(node->childs); it != NULL; ) {
|
||||
struct module *child = (struct module *) simple_linked_list_it_next(&it);
|
||||
if(strcasecmp(module_class_name(child->cls), node_name) == 0) {
|
||||
if(index-- == 0) {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void get_receiver_index(char *node_str, int *index) {
|
||||
*index = 0;
|
||||
if(strchr(node_str, '[')) {
|
||||
*index = atoi(strchr(node_str, '[') + 1);
|
||||
*strchr(node_str, '[') = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
struct module *get_module(struct module *root, const char *const_path)
|
||||
{
|
||||
struct module *receiver = root;
|
||||
char *path, *tmp;
|
||||
char *item, *save_ptr;
|
||||
|
||||
assert(root != NULL);
|
||||
|
||||
pthread_mutex_lock(&receiver->lock);
|
||||
|
||||
tmp = path = strdup(const_path);
|
||||
while ((item = strtok_r(path, ".", &save_ptr))) {
|
||||
struct module *old_receiver = receiver;
|
||||
int index;
|
||||
get_receiver_index(item, &index);
|
||||
receiver = find_child(receiver, item, index);
|
||||
if(!receiver) {
|
||||
pthread_mutex_unlock(&old_receiver->lock);
|
||||
break;
|
||||
}
|
||||
pthread_mutex_lock(&receiver->lock);
|
||||
pthread_mutex_unlock(&old_receiver->lock);
|
||||
|
||||
path = NULL;
|
||||
|
||||
}
|
||||
free(tmp);
|
||||
|
||||
return receiver;
|
||||
}
|
||||
|
||||
void unlock_module(struct module *module)
|
||||
{
|
||||
pthread_mutex_unlock(&module->lock);
|
||||
}
|
||||
|
||||
|
||||
26
src/module.h
26
src/module.h
@@ -70,6 +70,7 @@ enum module_class {
|
||||
MODULE_CLASS_SENDER,
|
||||
MODULE_CLASS_TX,
|
||||
MODULE_CLASS_AUDIO,
|
||||
MODULE_CLASS_CONTROL,
|
||||
};
|
||||
|
||||
struct module;
|
||||
@@ -77,6 +78,11 @@ struct simple_linked_list;
|
||||
|
||||
typedef void (*module_deleter_t)(struct module *);
|
||||
|
||||
/**
|
||||
* @struct module
|
||||
* Only members cls, deleter, priv_data and msg_queue may be directly touched
|
||||
* by user. The others should be considered private.
|
||||
*/
|
||||
struct module {
|
||||
uint32_t magic;
|
||||
pthread_mutex_t lock;
|
||||
@@ -86,6 +92,7 @@ struct module {
|
||||
module_deleter_t deleter;
|
||||
|
||||
/**
|
||||
* @var msg_callback
|
||||
* Module may implement a push method that will respond synchronously to events.
|
||||
* If not, message will be enqueued to message queue.
|
||||
*/
|
||||
@@ -100,6 +107,25 @@ void module_register(struct module *module_data, struct module *parent);
|
||||
void module_done(struct module *module_data);
|
||||
const char *module_class_name(enum module_class cls);
|
||||
void append_message_path(char *buf, int buflen, enum module_class modules[]);
|
||||
/**
|
||||
* IMPORTANT: returned module will be locked on return and needs to be unlocked by caller
|
||||
* when it is done!
|
||||
*
|
||||
* @retval NULL if not found
|
||||
* @retval non-NULL pointer to the module
|
||||
*/
|
||||
struct module *get_module(struct module *root, const char *path);
|
||||
/**
|
||||
* @see get_module
|
||||
* Caller of get_module should call this when done with module
|
||||
*/
|
||||
void unlock_module(struct module *module);
|
||||
/**
|
||||
* Returns pointer to root module. It WON'T be locked.
|
||||
*
|
||||
* @retval root module
|
||||
*/
|
||||
struct module *get_root_module(struct module *node);
|
||||
|
||||
#define CAST_MODULE(x) ((struct module *) x)
|
||||
|
||||
|
||||
@@ -71,6 +71,8 @@
|
||||
#include "audio/codec.h"
|
||||
#include "audio/resampler.h"
|
||||
#include "audio/utils.h"
|
||||
#include "crypto/crc.h"
|
||||
#include "crypto/openssl_decrypt.h"
|
||||
|
||||
#include "utils/packet_counter.h"
|
||||
|
||||
@@ -115,6 +117,8 @@ struct state_audio_decoder {
|
||||
uint32_t saved_audio_tag;
|
||||
|
||||
int samples_decoded;
|
||||
|
||||
struct openssl_decrypt *decrypt;
|
||||
};
|
||||
|
||||
static int validate_mapping(struct channel_map *map);
|
||||
@@ -168,7 +172,7 @@ static void compute_scale(struct scale_data *scale_data, float vol_avg, int samp
|
||||
}
|
||||
}
|
||||
|
||||
void *audio_decoder_init(char *audio_channel_map, const char *audio_scale)
|
||||
void *audio_decoder_init(char *audio_channel_map, const char *audio_scale, const char *encryption)
|
||||
{
|
||||
struct state_audio_decoder *s;
|
||||
bool scale_auto = false;
|
||||
@@ -187,6 +191,19 @@ void *audio_decoder_init(char *audio_channel_map, const char *audio_scale)
|
||||
|
||||
s->resampler = resampler_init(48000);
|
||||
|
||||
if(encryption) {
|
||||
#ifdef HAVE_CRYPTO
|
||||
if(openssl_decrypt_init(&s->decrypt,
|
||||
encryption, MODE_AES128_CTR) != 0) {
|
||||
fprintf(stderr, "Unable to create decompress!\n");
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
fprintf(stderr, "This " PACKAGE_NAME " version was build "
|
||||
"without OpenSSL support!\n");
|
||||
return NULL;
|
||||
#endif // HAVE_CRYPTO
|
||||
}
|
||||
|
||||
if(audio_channel_map) {
|
||||
char *save_ptr = NULL;
|
||||
@@ -311,6 +328,8 @@ void audio_decoder_destroy(void *state)
|
||||
audio_codec_done(s->audio_decompress);
|
||||
resampler_done(s->resampler);
|
||||
|
||||
openssl_decrypt_destroy(s->decrypt);
|
||||
|
||||
free(s);
|
||||
}
|
||||
|
||||
@@ -333,12 +352,57 @@ int decode_audio_frame(struct coded_data *cdata, void *data)
|
||||
while (cdata != NULL) {
|
||||
char *data;
|
||||
// for definition see rtp_callbacks.h
|
||||
uint32_t *hdr = (uint32_t *)(void *) cdata->data->data;
|
||||
|
||||
uint32_t *audio_hdr = (uint32_t *)(void *) cdata->data->data;
|
||||
uint32_t *encryption_hdr;
|
||||
const int pt = cdata->data->pt;
|
||||
|
||||
if(pt == PT_ENCRYPT_AUDIO) {
|
||||
encryption_hdr = (uint32_t *)((void *) cdata->data->data +
|
||||
sizeof(audio_payload_hdr_t));
|
||||
if(!decoder->decrypt) {
|
||||
fprintf(stderr, "Receiving encrypted audio data but "
|
||||
"no decryption key entered!\n");
|
||||
ret = false; goto cleanup;
|
||||
}
|
||||
} else if(pt == PT_AUDIO) {
|
||||
if(decoder->decrypt) {
|
||||
fprintf(stderr, "Receiving unencrypted audio data "
|
||||
"while expecting encrypted.\n");
|
||||
ret = false; goto cleanup;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Unknown audio packet type: %d\n", pt);
|
||||
abort();
|
||||
}
|
||||
|
||||
unsigned int length;
|
||||
char plaintext[cdata->data->data_len]; // plaintext will be actually shorter
|
||||
if(pt == PT_AUDIO) {
|
||||
length = cdata->data->data_len - sizeof(audio_payload_hdr_t);
|
||||
data = cdata->data->data + sizeof(audio_payload_hdr_t);
|
||||
} else {
|
||||
assert(pt == PT_ENCRYPT_AUDIO);
|
||||
char *ciphertext = cdata->data->data + sizeof(crypto_payload_hdr_t) +
|
||||
sizeof(audio_payload_hdr_t);
|
||||
int ciphertext_len = cdata->data->data_len - sizeof(audio_payload_hdr_t) -
|
||||
sizeof(crypto_payload_hdr_t);
|
||||
|
||||
if((length = openssl_decrypt(decoder->decrypt,
|
||||
ciphertext, ciphertext_len,
|
||||
(char *) audio_hdr, sizeof(audio_payload_hdr_t),
|
||||
plaintext
|
||||
)) == 0) {
|
||||
fprintf(stderr, "Warning: Packet dropped AES - wrong CRC!\n");
|
||||
ret = false;
|
||||
goto cleanup;
|
||||
}
|
||||
data = plaintext;
|
||||
}
|
||||
|
||||
/* we receive last channel first (with m bit, last packet) */
|
||||
/* thus can be set only with m-bit packet */
|
||||
if(cdata->data->m) {
|
||||
input_channels = ((ntohl(hdr[0]) >> 22) & 0x3ff) + 1;
|
||||
input_channels = ((ntohl(audio_hdr[0]) >> 22) & 0x3ff) + 1;
|
||||
}
|
||||
|
||||
// we have:
|
||||
@@ -346,16 +410,19 @@ int decode_audio_frame(struct coded_data *cdata, void *data)
|
||||
// 2) not last, but the last one was processed at first
|
||||
assert(input_channels > 0);
|
||||
|
||||
channel = (ntohl(hdr[0]) >> 22) & 0x3ff;
|
||||
int bufnum = ntohl(hdr[0]) & 0x3fffff;
|
||||
sample_rate = ntohl(hdr[3]) & 0x3fffff;
|
||||
bps = (ntohl(hdr[3]) >> 26) / 8;
|
||||
uint32_t audio_tag = ntohl(hdr[4]);
|
||||
channel = (ntohl(audio_hdr[0]) >> 22) & 0x3ff;
|
||||
int bufnum = ntohl(audio_hdr[0]) & 0x3fffff;
|
||||
sample_rate = ntohl(audio_hdr[3]) & 0x3fffff;
|
||||
bps = (ntohl(audio_hdr[3]) >> 26) / 8;
|
||||
uint32_t audio_tag = ntohl(audio_hdr[4]);
|
||||
|
||||
output_channels = decoder->channel_remapping ? decoder->channel_map.max_output + 1: input_channels;
|
||||
output_channels = decoder->channel_remapping ?
|
||||
decoder->channel_map.max_output + 1: input_channels;
|
||||
|
||||
/**
|
||||
* TODO: obtain supported rates from device
|
||||
/*
|
||||
* Reconfiguration
|
||||
*
|
||||
* @todo obtain supported rates from device
|
||||
*/
|
||||
int device_sample_rate = 48000;
|
||||
int device_bps = 2;
|
||||
@@ -404,13 +471,9 @@ int decode_audio_frame(struct coded_data *cdata, void *data)
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
data = cdata->data->data + sizeof(audio_payload_hdr_t);
|
||||
|
||||
unsigned int length = cdata->data->data_len - sizeof(audio_payload_hdr_t);
|
||||
|
||||
unsigned int offset = ntohl(hdr[1]);
|
||||
unsigned int buffer_len = ntohl(hdr[2]);
|
||||
unsigned int offset = ntohl(audio_hdr[1]);
|
||||
unsigned int buffer_len = ntohl(audio_hdr[2]);
|
||||
//fprintf(stderr, "%d-%d-%d ", length, bufnum, channel);
|
||||
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
struct coded_data;
|
||||
|
||||
int decode_audio_frame(struct coded_data *cdata, void *data);
|
||||
void *audio_decoder_init(char *audio_channel_map, const char *audio_scale);
|
||||
void *audio_decoder_init(char *audio_channel_map, const char *audio_scale,
|
||||
const char *encryption);
|
||||
void audio_decoder_destroy(void *state);
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
#include "config_unix.h"
|
||||
#include "config_win32.h"
|
||||
#endif // HAVE_CONFIG_H
|
||||
#include "crypto/openssl_decrypt.h"
|
||||
#include "debug.h"
|
||||
#include "host.h"
|
||||
#include "perf.h"
|
||||
@@ -170,6 +171,8 @@ struct state_decoder {
|
||||
double set_fps; // "message" passed to our master
|
||||
codec_t codec;
|
||||
bool slow;
|
||||
|
||||
struct openssl_decrypt *decrypt;
|
||||
};
|
||||
|
||||
// message definitions
|
||||
@@ -202,7 +205,14 @@ static void wait_for_framebuffer_swap(struct state_decoder *decoder) {
|
||||
pthread_mutex_unlock(&decoder->lock);
|
||||
}
|
||||
|
||||
#define ENCRYPTED_ERR "Receiving encrypted video data but " \
|
||||
"no decryption key entered!\n"
|
||||
#define NOT_ENCRYPTED_ERR "Receiving unencrypted video data " \
|
||||
"while expecting encrypted.\n"
|
||||
#define SKIP_LDGM_FRAME ret = FALSE; goto cleanup;
|
||||
|
||||
static void *ldgm_thread(void *args) {
|
||||
uint32_t tmp_ui32;
|
||||
struct state_decoder *decoder = args;
|
||||
|
||||
struct fec fec_state;
|
||||
@@ -251,6 +261,7 @@ static void *ldgm_thread(void *args) {
|
||||
decompress_data->buffer_num = calloc(data->substream_count, sizeof(int));
|
||||
memcpy(decompress_data->buffer_num, data->buffer_num, data->substream_count * sizeof(int));
|
||||
memcpy(decompress_data->fec_buffers, data->recv_buffers, data->substream_count * sizeof(char *));
|
||||
|
||||
if (data->pt == PT_VIDEO_LDGM) {
|
||||
if(!fec_state.state || fec_state.k != data->k ||
|
||||
fec_state.m != data->m ||
|
||||
@@ -274,70 +285,118 @@ static void *ldgm_thread(void *args) {
|
||||
}
|
||||
|
||||
if (data->pt == PT_VIDEO_LDGM) {
|
||||
int x,y;
|
||||
for (x = 0; x < get_video_mode_tiles_x(decoder->video_mode) ; ++x) {
|
||||
for (y = 0; y < get_video_mode_tiles_y(decoder->video_mode); ++y) {
|
||||
int pos = x + get_video_mode_tiles_x(decoder->video_mode) * y;
|
||||
char *out_buffer = NULL;
|
||||
int out_len = 0;
|
||||
int pos;
|
||||
for (pos = 0; pos < get_video_mode_tiles_x(decoder->video_mode)
|
||||
* get_video_mode_tiles_y(decoder->video_mode); ++pos) {
|
||||
char *ldgm_out_buffer = NULL;
|
||||
int ldgm_out_len = 0;
|
||||
|
||||
ldgm_decoder_decode(fec_state.state, data->recv_buffers[pos],
|
||||
data->buffer_len[pos],
|
||||
&out_buffer, &out_len, data->pckt_list[pos]);
|
||||
ldgm_decoder_decode(fec_state.state, data->recv_buffers[pos],
|
||||
data->buffer_len[pos],
|
||||
&ldgm_out_buffer, &ldgm_out_len, data->pckt_list[pos]);
|
||||
|
||||
if(out_len == 0) {
|
||||
ret = FALSE;
|
||||
fprintf(stderr, "[decoder] LDGM: unable to reconstruct data.\n");
|
||||
goto cleanup;
|
||||
if(ldgm_out_len == 0) {
|
||||
ret = FALSE;
|
||||
fprintf(stderr, "[decoder] LDGM: unable to reconstruct data.\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
uint32_t ldgm_pt;
|
||||
char *ldgm_hdr = ldgm_out_buffer;
|
||||
memcpy(&ldgm_pt, ldgm_out_buffer, sizeof(ldgm_pt));
|
||||
ldgm_pt = htonl(ldgm_pt);
|
||||
assert(ldgm_pt == PT_VIDEO || ldgm_pt == PT_ENCRYPT_VIDEO);
|
||||
|
||||
video_payload_hdr_t video_hdr;
|
||||
memcpy(&video_hdr, ldgm_out_buffer + sizeof(uint32_t),
|
||||
sizeof(video_payload_hdr_t));
|
||||
ldgm_out_buffer += sizeof(video_payload_hdr_t) + sizeof(uint32_t);
|
||||
ldgm_out_len -= sizeof(video_payload_hdr_t) + sizeof(uint32_t);
|
||||
|
||||
if(ldgm_pt == PT_ENCRYPT_VIDEO) {
|
||||
if(!decoder->decrypt) {
|
||||
fprintf(stderr, ENCRYPTED_ERR);
|
||||
SKIP_LDGM_FRAME
|
||||
}
|
||||
check_for_mode_change(decoder, (uint32_t *)(void *) out_buffer,
|
||||
&frame);
|
||||
uint32_t *crypto_hdr = (uint32_t *)(void *) ldgm_out_buffer;
|
||||
tmp_ui32 = ntohl(crypto_hdr[0]);
|
||||
uint8_t crypto_type = tmp_ui32 >> 24;
|
||||
|
||||
if(!frame) {
|
||||
ret = FALSE;
|
||||
goto cleanup;
|
||||
if(crypto_type != CRYPTO_TYPE_AES128_CTR) {
|
||||
fprintf(stderr, "Unknown encryption!\n");
|
||||
}
|
||||
|
||||
out_buffer += sizeof(video_payload_hdr_t);
|
||||
out_len -= sizeof(video_payload_hdr_t);
|
||||
int ciphertext_len = ldgm_out_len -
|
||||
sizeof(crypto_payload_hdr_t);
|
||||
char *plaintext = malloc(ciphertext_len);
|
||||
char *ciphertext = (char *)
|
||||
ldgm_out_buffer + sizeof(crypto_payload_hdr_t);
|
||||
int plaintext_len;
|
||||
if((plaintext_len = openssl_decrypt(decoder->decrypt, ciphertext,
|
||||
ciphertext_len,
|
||||
ldgm_hdr, sizeof(video_payload_hdr_t) + sizeof(uint32_t),
|
||||
plaintext)) == 0) {
|
||||
fprintf(stderr, "Warning: Packet dropped AES - wrong CRC!\n");
|
||||
free(plaintext);
|
||||
ret = FALSE; goto cleanup;
|
||||
}
|
||||
|
||||
if(decoder->decoder_type == EXTERNAL_DECODER) {
|
||||
decompress_data->buffer_len[pos] = out_len;
|
||||
decompress_data->decompress_buffer[pos] = out_buffer;
|
||||
} else { // linedecoder
|
||||
wait_for_framebuffer_swap(decoder);
|
||||
free(data->recv_buffers[pos]);
|
||||
decompress_data->fec_buffers[pos] = data->recv_buffers[pos] =
|
||||
plaintext;
|
||||
|
||||
struct video_frame *out_frame;
|
||||
int divisor;
|
||||
ldgm_out_len = plaintext_len;
|
||||
ldgm_out_buffer = plaintext;
|
||||
} else {
|
||||
if(decoder->decrypt) {
|
||||
fprintf(stderr, NOT_ENCRYPTED_ERR);
|
||||
SKIP_LDGM_FRAME
|
||||
}
|
||||
}
|
||||
|
||||
if(!decoder->postprocess) {
|
||||
out_frame = frame;
|
||||
} else {
|
||||
out_frame = decoder->pp_frame;
|
||||
}
|
||||
check_for_mode_change(decoder, video_hdr,
|
||||
&frame);
|
||||
|
||||
if (!decoder->merged_fb) {
|
||||
divisor = decoder->max_substreams;
|
||||
} else {
|
||||
divisor = 1;
|
||||
}
|
||||
if(!frame) {
|
||||
SKIP_LDGM_FRAME
|
||||
}
|
||||
|
||||
tile = vf_get_tile(out_frame, pos % divisor);
|
||||
if(decoder->decoder_type == EXTERNAL_DECODER) {
|
||||
decompress_data->buffer_len[pos] = ldgm_out_len;
|
||||
decompress_data->decompress_buffer[pos] = ldgm_out_buffer;
|
||||
} else { // linedecoder
|
||||
wait_for_framebuffer_swap(decoder);
|
||||
|
||||
struct line_decoder *line_decoder =
|
||||
&decoder->line_decoder[pos];
|
||||
struct video_frame *out_frame;
|
||||
int divisor;
|
||||
|
||||
int data_pos = 0;
|
||||
char *src = out_buffer;
|
||||
char *dst = tile->data + line_decoder->base_offset;
|
||||
while(data_pos < (int) out_len) {
|
||||
line_decoder->decode_line((unsigned char*)dst, (unsigned char *) src, line_decoder->src_linesize,
|
||||
line_decoder->rshift, line_decoder->gshift,
|
||||
line_decoder->bshift);
|
||||
src += line_decoder->src_linesize;
|
||||
dst += vc_get_linesize(tile->width ,frame->color_spec);
|
||||
data_pos += line_decoder->src_linesize;
|
||||
}
|
||||
if(!decoder->postprocess) {
|
||||
out_frame = frame;
|
||||
} else {
|
||||
out_frame = decoder->pp_frame;
|
||||
}
|
||||
|
||||
if (!decoder->merged_fb) {
|
||||
divisor = decoder->max_substreams;
|
||||
} else {
|
||||
divisor = 1;
|
||||
}
|
||||
|
||||
tile = vf_get_tile(out_frame, pos % divisor);
|
||||
|
||||
struct line_decoder *line_decoder =
|
||||
&decoder->line_decoder[pos];
|
||||
|
||||
int data_pos = 0;
|
||||
char *src = ldgm_out_buffer;
|
||||
char *dst = tile->data + line_decoder->base_offset;
|
||||
while(data_pos < (int) ldgm_out_len) {
|
||||
line_decoder->decode_line((unsigned char*)dst, (unsigned char *) src, line_decoder->src_linesize,
|
||||
line_decoder->rshift, line_decoder->gshift,
|
||||
line_decoder->bshift);
|
||||
src += line_decoder->src_linesize;
|
||||
dst += vc_get_linesize(tile->width ,frame->color_spec);
|
||||
data_pos += line_decoder->src_linesize;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -553,7 +612,7 @@ static void decoder_set_video_mode(struct state_decoder *decoder, unsigned int v
|
||||
}
|
||||
|
||||
struct state_decoder *decoder_init(const char *requested_mode, const char *postprocess,
|
||||
struct display *display)
|
||||
struct display *display, const char *encryption)
|
||||
{
|
||||
struct state_decoder *s;
|
||||
|
||||
@@ -577,6 +636,20 @@ struct state_decoder *decoder_init(const char *requested_mode, const char *postp
|
||||
|
||||
int video_mode = VIDEO_NORMAL;
|
||||
|
||||
if(encryption) {
|
||||
#ifdef HAVE_CRYPTO
|
||||
if(openssl_decrypt_init(&s->decrypt,
|
||||
encryption, MODE_AES128_CTR) != 0) {
|
||||
fprintf(stderr, "Unable to create decompress!\n");
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
fprintf(stderr, "This " PACKAGE_NAME " version was build "
|
||||
"without OpenSSL support!\n");
|
||||
return NULL;
|
||||
#endif // HAVE_CRYPTO
|
||||
}
|
||||
|
||||
if(requested_mode) {
|
||||
/* these are data comming from newtork ! */
|
||||
if(strcasecmp(requested_mode, "help") == 0) {
|
||||
@@ -765,6 +838,8 @@ void decoder_destroy(struct state_decoder *decoder)
|
||||
if(!decoder)
|
||||
return;
|
||||
|
||||
openssl_decrypt_destroy(decoder->decrypt);
|
||||
|
||||
decoder_remove_display(decoder);
|
||||
|
||||
pthread_mutex_destroy(&decoder->lock);
|
||||
@@ -1292,6 +1367,8 @@ static int check_for_mode_change(struct state_decoder *decoder, uint32_t *hdr, s
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define SKIP_PACKET ret = FALSE; goto cleanup;
|
||||
|
||||
int decode_frame(struct coded_data *cdata, void *decode_data)
|
||||
{
|
||||
struct vcodec_state *pbuf_data = (struct vcodec_state *) decode_data;
|
||||
@@ -1348,13 +1425,14 @@ int decode_frame(struct coded_data *cdata, void *decode_data)
|
||||
}
|
||||
|
||||
int pt;
|
||||
int contained_pt; // if packed is encrypted it encapsulates other pt
|
||||
bool buffer_swapped = false;
|
||||
|
||||
while (cdata != NULL) {
|
||||
uint32_t *hdr;
|
||||
pckt = cdata->data;
|
||||
|
||||
pt = pckt->pt;
|
||||
contained_pt = pt = pckt->pt;
|
||||
hdr = (uint32_t *)(void *) pckt->data;
|
||||
data_pos = ntohl(hdr[1]);
|
||||
tmp = ntohl(hdr[0]);
|
||||
@@ -1366,6 +1444,10 @@ int decode_frame(struct coded_data *cdata, void *decode_data)
|
||||
if(pt == PT_VIDEO) {
|
||||
len = pckt->data_len - sizeof(video_payload_hdr_t);
|
||||
data = (char *) hdr + sizeof(video_payload_hdr_t);
|
||||
if(decoder->decrypt) {
|
||||
fprintf(stderr, NOT_ENCRYPTED_ERR);
|
||||
SKIP_PACKET
|
||||
}
|
||||
} else if (pt == PT_VIDEO_LDGM) {
|
||||
len = pckt->data_len - sizeof(ldgm_video_payload_hdr_t);
|
||||
data = (char *) hdr + sizeof(ldgm_video_payload_hdr_t);
|
||||
@@ -1375,6 +1457,16 @@ int decode_frame(struct coded_data *cdata, void *decode_data)
|
||||
m = 0x1fff & (tmp >> 6);
|
||||
c = 0x3f & tmp;
|
||||
seed = ntohl(hdr[4]);
|
||||
} else if (pt == PT_ENCRYPT_VIDEO) {
|
||||
len = pckt->data_len - sizeof(video_payload_hdr_t)
|
||||
- sizeof(crypto_payload_hdr_t);
|
||||
data = (char *) hdr + sizeof(video_payload_hdr_t)
|
||||
+ sizeof(crypto_payload_hdr_t);
|
||||
contained_pt = PT_VIDEO;
|
||||
if(!decoder->decrypt) {
|
||||
fprintf(stderr, ENCRYPTED_ERR);
|
||||
SKIP_PACKET
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "[decoder] Unknown packet type: %d.\n", pckt->pt);
|
||||
exit_uv(1);
|
||||
@@ -1411,23 +1503,38 @@ int decode_frame(struct coded_data *cdata, void *decode_data)
|
||||
|
||||
buffer_num[substream] = buffer_number;
|
||||
buffer_len[substream] = buffer_length;
|
||||
|
||||
ll_insert(pckt_list[substream], data_pos, len);
|
||||
|
||||
if (pt == PT_VIDEO) {
|
||||
/* Critical section
|
||||
* each thread *MUST* wait here if this condition is true
|
||||
*/
|
||||
check_for_mode_change(decoder, (uint32_t *)(void *)
|
||||
pckt->data, &frame);
|
||||
uint32_t *video_header = hdr;
|
||||
|
||||
char plaintext[len]; // will be actually shorter
|
||||
if(pt == PT_ENCRYPT_VIDEO) {
|
||||
int data_len;
|
||||
|
||||
if((data_len = openssl_decrypt(decoder->decrypt,
|
||||
data, len,
|
||||
(char *) video_header, sizeof(video_payload_hdr_t),
|
||||
plaintext)) == 0) {
|
||||
fprintf(stderr, "Warning: Packet dropped AES - wrong CRC!\n");
|
||||
goto next_packet;
|
||||
}
|
||||
data = (char *) plaintext;
|
||||
len = data_len;
|
||||
}
|
||||
|
||||
if(pt == PT_VIDEO && !frame) {
|
||||
if(contained_pt == PT_VIDEO) {
|
||||
/* Critical section
|
||||
* each thread *MUST* wait here if this condition is true
|
||||
*/
|
||||
check_for_mode_change(decoder, video_header, &frame);
|
||||
}
|
||||
if(contained_pt == PT_VIDEO && !frame) {
|
||||
ret = FALSE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (pt == PT_VIDEO && decoder->decoder_type == LINE_DECODER) {
|
||||
ll_insert(pckt_list[substream], data_pos, len);
|
||||
|
||||
if (contained_pt == PT_VIDEO && decoder->decoder_type == LINE_DECODER) {
|
||||
if(!buffer_swapped) {
|
||||
wait_for_framebuffer_swap(decoder);
|
||||
buffer_swapped = true;
|
||||
@@ -1528,6 +1635,7 @@ int decode_frame(struct coded_data *cdata, void *decode_data)
|
||||
len);
|
||||
}
|
||||
|
||||
next_packet:
|
||||
cdata = cdata->nxt;
|
||||
}
|
||||
|
||||
@@ -1549,7 +1657,7 @@ int decode_frame(struct coded_data *cdata, void *decode_data)
|
||||
ldgm_data->c = c;
|
||||
ldgm_data->seed = seed;
|
||||
ldgm_data->substream_count = decoder->max_substreams;
|
||||
ldgm_data->pt = pt;
|
||||
ldgm_data->pt = contained_pt;
|
||||
ldgm_data->poisoned = false;
|
||||
memcpy(ldgm_data->buffer_len, buffer_len, sizeof(buffer_len));
|
||||
memcpy(ldgm_data->buffer_num, buffer_num, sizeof(buffer_num));
|
||||
|
||||
@@ -56,7 +56,7 @@ struct tile;
|
||||
int decode_frame(struct coded_data *compressed_frame, void *decode_data);
|
||||
|
||||
struct state_decoder *decoder_init(const char *requested_mode, const char *postprocess,
|
||||
struct display *display);
|
||||
struct display *display, const char *encryption);
|
||||
void decoder_destroy(struct state_decoder *decoder);
|
||||
|
||||
bool decoder_register_video_display(struct state_decoder *decoder, struct display *display);
|
||||
|
||||
@@ -46,9 +46,11 @@
|
||||
* Packet formats:
|
||||
* http://www.sitola.cz/files/4K-packet-format.pdf
|
||||
*/
|
||||
#define PT_VIDEO 20
|
||||
#define PT_AUDIO 21
|
||||
#define PT_VIDEO_LDGM 22
|
||||
#define PT_VIDEO 20
|
||||
#define PT_AUDIO 21
|
||||
#define PT_VIDEO_LDGM 22
|
||||
#define PT_ENCRYPT_VIDEO 24
|
||||
#define PT_ENCRYPT_AUDIO 25
|
||||
|
||||
/*
|
||||
* Video payload
|
||||
@@ -101,6 +103,8 @@ typedef uint32_t video_payload_hdr_t[6];
|
||||
*/
|
||||
typedef uint32_t audio_payload_hdr_t[5];
|
||||
|
||||
typedef uint32_t ldgm_payload_hdr_t;
|
||||
|
||||
/*
|
||||
* LDGM video payload
|
||||
*
|
||||
@@ -124,8 +128,19 @@ typedef uint32_t audio_payload_hdr_t[5];
|
||||
*/
|
||||
typedef uint32_t ldgm_video_payload_hdr_t[5];
|
||||
|
||||
/*
|
||||
* Crypto video payload
|
||||
*
|
||||
* 1st word
|
||||
* bits 0 - 8 crypto type
|
||||
* bits 9 - 31 currently unused
|
||||
*/
|
||||
#define CRYPTO_TYPE_AES128_CTR 1u
|
||||
typedef uint32_t crypto_payload_hdr_t[1];
|
||||
|
||||
void rtp_recv_callback(struct rtp *session, rtp_event *e);
|
||||
int handle_with_buffer(struct rtp *session,rtp_event *e);
|
||||
int check_for_frame_completion(struct rtp *);
|
||||
void process_packet_for_display(char *);
|
||||
void call_display_frame(void);
|
||||
|
||||
|
||||
@@ -231,7 +231,6 @@ static void *sender_thread(void *arg) {
|
||||
struct video_frame *splitted_frames = NULL;
|
||||
int tile_y_count;
|
||||
struct video_desc saved_vid_desc;
|
||||
struct stats *stat_data_sent = stats_new_statistics("data");
|
||||
|
||||
tile_y_count = data->connections_count;
|
||||
memset(&saved_vid_desc, 0, sizeof(saved_vid_desc));
|
||||
@@ -250,6 +249,11 @@ static void *sender_thread(void *arg) {
|
||||
|
||||
pthread_mutex_unlock(&data->priv->lock);
|
||||
|
||||
struct module *control_mod = get_module(get_root_module(&data->priv->mod), "control");
|
||||
struct stats *stat_data_sent = stats_new_statistics((struct control_state *)
|
||||
control_mod, "data");
|
||||
unlock_module(control_mod);
|
||||
|
||||
while(1) {
|
||||
pthread_mutex_lock(&data->priv->lock);
|
||||
struct video_frame *tx_frame = NULL;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "control.h"
|
||||
#include "compat/platform_spin.h"
|
||||
#include "debug.h"
|
||||
#include "messaging.h"
|
||||
@@ -14,49 +15,42 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
static struct response *messaging_callback(struct received_message *msg, void *udata);
|
||||
|
||||
struct stats {
|
||||
public:
|
||||
stats(string name) {
|
||||
m_name = name;
|
||||
m_val = 0;
|
||||
stats(string name, struct control_state *control)
|
||||
: m_control(control), m_name(name), m_val(0) {
|
||||
platform_spin_init(&m_spin);
|
||||
control_add_stats(control, this);
|
||||
}
|
||||
|
||||
~stats() {
|
||||
control_remove_stats(m_control, this);
|
||||
platform_spin_destroy(&m_spin);
|
||||
}
|
||||
|
||||
void update_int(int64_t val) {
|
||||
platform_spin_lock(&m_spin);
|
||||
m_val = val;
|
||||
platform_spin_unlock(&m_spin);
|
||||
}
|
||||
|
||||
struct response *process_message(void *msg) {
|
||||
struct msg_stats *stats = (struct msg_stats *) msg;
|
||||
|
||||
if(string(stats->what).compare(m_name) == 0) {
|
||||
char buf[128];
|
||||
snprintf(buf, sizeof(buf), "%lu", m_val);
|
||||
return new_response(RESPONSE_OK, strdup(buf));
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
void get_stat(char *buffer, int buffer_len) {
|
||||
platform_spin_lock(&m_spin);
|
||||
snprintf(buffer, buffer_len, "%s %lu", m_name.c_str(), m_val);
|
||||
platform_spin_unlock(&m_spin);
|
||||
}
|
||||
|
||||
private:
|
||||
string m_name;
|
||||
int64_t m_val;
|
||||
void *m_messaging_subscribtion;
|
||||
struct control_state *m_control;
|
||||
platform_spin_t m_spin;
|
||||
};
|
||||
|
||||
static struct response *messaging_callback(void *msg, struct module *mod)
|
||||
struct stats *stats_new_statistics(struct control_state *control, char * name)
|
||||
{
|
||||
stats *s = (stats *) mod->priv_data;
|
||||
return s->process_message(msg);
|
||||
}
|
||||
|
||||
struct stats *stats_new_statistics(char * name)
|
||||
{
|
||||
return new stats(string(name));
|
||||
return new stats(string(name), control);
|
||||
}
|
||||
|
||||
void stats_update_int(struct stats *s, int64_t val)
|
||||
@@ -64,6 +58,11 @@ void stats_update_int(struct stats *s, int64_t val)
|
||||
return s->update_int(val);
|
||||
}
|
||||
|
||||
void stats_format(struct stats *s, char *buffer, int buffer_len)
|
||||
{
|
||||
s->get_stat(buffer, buffer_len);
|
||||
}
|
||||
|
||||
void stats_destroy(struct stats *s)
|
||||
{
|
||||
delete s;
|
||||
|
||||
@@ -11,8 +11,12 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct stats *stats_new_statistics(char * name);
|
||||
struct control_state;
|
||||
struct stats;
|
||||
|
||||
struct stats *stats_new_statistics(struct control_state *control, char * name);
|
||||
void stats_update_int(struct stats *, int64_t);
|
||||
void stats_format(struct stats *s, char *buffer, int buffer_len);
|
||||
void stats_destroy(struct stats *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
200
src/transmit.c
200
src/transmit.c
@@ -62,7 +62,7 @@
|
||||
#include "audio/audio.h"
|
||||
#include "audio/codec.h"
|
||||
#include "audio/utils.h"
|
||||
#include "messaging.h"
|
||||
#include "crypto/openssl_encrypt.h"
|
||||
#include "module.h"
|
||||
#include "rtp/ldgm.h"
|
||||
#include "rtp/rtp.h"
|
||||
@@ -72,7 +72,6 @@
|
||||
#include "host.h"
|
||||
#include "video_codec.h"
|
||||
#include "compat/platform_spin.h"
|
||||
#include "compat/platform_time.h"
|
||||
|
||||
#define TRANSMIT_MAGIC 0xe80ab15f
|
||||
|
||||
@@ -138,8 +137,9 @@ struct tx {
|
||||
|
||||
int last_fragment;
|
||||
|
||||
void *messaging_subscription;
|
||||
platform_spin_t spin;
|
||||
|
||||
struct openssl_encrypt *encryption;
|
||||
};
|
||||
|
||||
static bool fec_is_ldgm(struct tx *tx)
|
||||
@@ -180,11 +180,12 @@ static void tx_update(struct tx *tx, struct tile *tile)
|
||||
}
|
||||
}
|
||||
|
||||
struct tx *tx_init(struct module *parent, unsigned mtu, enum tx_media_type media_type, char *fec)
|
||||
struct tx *tx_init(struct module *parent, unsigned mtu, enum tx_media_type media_type,
|
||||
char *fec, const char *encryption)
|
||||
{
|
||||
struct tx *tx;
|
||||
|
||||
tx = (struct tx *)malloc(sizeof(struct tx));
|
||||
tx = (struct tx *) calloc(1, sizeof(struct tx));
|
||||
if (tx != NULL) {
|
||||
module_init_default(&tx->mod);
|
||||
tx->mod.cls = MODULE_CLASS_TX;
|
||||
@@ -208,6 +209,20 @@ struct tx *tx_init(struct module *parent, unsigned mtu, enum tx_media_type media
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if(encryption) {
|
||||
#ifdef HAVE_CRYPTO
|
||||
if(openssl_encrypt_init(&tx->encryption,
|
||||
encryption, MODE_AES128_CTR) != 0) {
|
||||
fprintf(stderr, "Unable to initialize encryption\n");
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
fprintf(stderr, "This " PACKAGE_NAME " version was build "
|
||||
"without OpenSSL support!\n");
|
||||
return NULL;
|
||||
#endif // HAVE_CRYPTO
|
||||
}
|
||||
|
||||
platform_spin_init(&tx->spin);
|
||||
|
||||
module_register(&tx->mod, parent);
|
||||
@@ -372,17 +387,42 @@ tx_send_tile(struct tx *tx, struct video_frame *frame, int pos, struct rtp *rtp_
|
||||
platform_spin_unlock(&tx->spin);
|
||||
}
|
||||
|
||||
static uint32_t format_interl_fps_hdr_row(enum interlacing_t interlacing, double input_fps)
|
||||
{
|
||||
unsigned int fpsd, fd, fps, fi;
|
||||
uint32_t tmp;
|
||||
|
||||
tmp = interlacing << 29;
|
||||
fps = round(input_fps);
|
||||
fpsd = 1;
|
||||
if(fabs(input_fps - round(input_fps) / 1.001) < 0.005)
|
||||
fd = 1;
|
||||
else
|
||||
fd = 0;
|
||||
fi = 0;
|
||||
|
||||
tmp |= fps << 19;
|
||||
tmp |= fpsd << 15;
|
||||
tmp |= fd << 14;
|
||||
tmp |= fi << 13;
|
||||
return htonl(tmp);
|
||||
}
|
||||
|
||||
static void
|
||||
tx_send_base(struct tx *tx, struct tile *tile, struct rtp *rtp_session,
|
||||
uint32_t ts, int send_m,
|
||||
codec_t color_spec, double input_fps,
|
||||
codec_t color_spec, double fps,
|
||||
enum interlacing_t interlacing, unsigned int substream,
|
||||
int fragment_offset)
|
||||
{
|
||||
int m, data_len;
|
||||
// see definition in rtp_callback.h
|
||||
video_payload_hdr_t video_hdr;
|
||||
ldgm_video_payload_hdr_t ldgm_hdr;
|
||||
|
||||
uint32_t hdr_data[100];
|
||||
uint32_t *ldgm_payload_hdr = hdr_data;
|
||||
uint32_t *video_hdr = ldgm_payload_hdr + 1;
|
||||
uint32_t *ldgm_hdr = video_hdr + sizeof(video_payload_hdr_t)/sizeof(uint32_t);
|
||||
uint32_t *encryption_hdr;
|
||||
int pt = PT_VIDEO; /* A value specified in our packet format */
|
||||
char *data;
|
||||
unsigned int pos;
|
||||
@@ -395,11 +435,10 @@ tx_send_base(struct tx *tx, struct tile *tile, struct rtp *rtp_session,
|
||||
#endif
|
||||
long delta;
|
||||
uint32_t tmp;
|
||||
unsigned int fps, fpsd, fd, fi;
|
||||
int mult_pos[FEC_MAX_MULT];
|
||||
int mult_index = 0;
|
||||
int mult_first_sent = 0;
|
||||
int hdrs_len = 40 + (sizeof(video_payload_hdr_t));
|
||||
int hdrs_len = 40 + (sizeof(video_payload_hdr_t)); // for computing max payload size
|
||||
char *data_to_send;
|
||||
int data_to_send_len;
|
||||
|
||||
@@ -423,6 +462,24 @@ tx_send_base(struct tx *tx, struct tile *tile, struct rtp *rtp_session,
|
||||
m = 0;
|
||||
pos = 0;
|
||||
|
||||
char *rtp_hdr;
|
||||
int rtp_hdr_len;
|
||||
|
||||
if(tx->encryption && !fec_is_ldgm(tx)) {
|
||||
/*
|
||||
* Important
|
||||
* Crypto and video header must be in specified order placed one right after
|
||||
* the another since both will be sent as a RTP header.
|
||||
*/
|
||||
encryption_hdr = video_hdr + sizeof(video_payload_hdr_t)/sizeof(uint32_t);
|
||||
|
||||
encryption_hdr[0] = htonl(CRYPTO_TYPE_AES128_CTR << 24);
|
||||
hdrs_len += sizeof(crypto_payload_hdr_t) + openssl_get_overhead(tx->encryption);
|
||||
rtp_hdr = (char *) video_hdr;
|
||||
rtp_hdr_len = sizeof(crypto_payload_hdr_t) + sizeof(video_payload_hdr_t);
|
||||
pt = PT_ENCRYPT_VIDEO;
|
||||
}
|
||||
|
||||
video_hdr[3] = htonl(tile->width << 16 | tile->height);
|
||||
video_hdr[4] = get_fourcc(color_spec);
|
||||
video_hdr[2] = htonl(data_to_send_len);
|
||||
@@ -431,28 +488,39 @@ tx_send_base(struct tx *tx, struct tile *tile, struct rtp *rtp_session,
|
||||
video_hdr[0] = htonl(tmp);
|
||||
|
||||
/* word 6 */
|
||||
tmp = interlacing << 29;
|
||||
fps = round(input_fps);
|
||||
fpsd = 1;
|
||||
if(fabs(input_fps - round(input_fps) / 1.001) < 0.005)
|
||||
fd = 1;
|
||||
else
|
||||
fd = 0;
|
||||
fi = 0;
|
||||
|
||||
tmp |= fps << 19;
|
||||
tmp |= fpsd << 15;
|
||||
tmp |= fd << 14;
|
||||
tmp |= fi << 13;
|
||||
video_hdr[5] = htonl(tmp);
|
||||
|
||||
char *hdr;
|
||||
int hdr_len;
|
||||
video_hdr[5] = format_interl_fps_hdr_row(interlacing, fps);
|
||||
|
||||
if(fec_is_ldgm(tx)) {
|
||||
hdrs_len = 40 + (sizeof(ldgm_video_payload_hdr_t));
|
||||
ldgm_encoder_encode(tx->fec_state, (char *) &video_hdr, sizeof(video_hdr),
|
||||
tile->data, tile->data_len, &data_to_send, &data_to_send_len);
|
||||
char *tmp_data = NULL;
|
||||
char *ldgm_input_data;
|
||||
int ldgm_input_len;
|
||||
int ldgm_payload_hdr_len = sizeof(ldgm_payload_hdr_t) + sizeof(video_payload_hdr_t);
|
||||
if(tx->encryption) {
|
||||
ldgm_input_len = tile->data_len + sizeof(crypto_payload_hdr_t) +
|
||||
MAX_CRYPTO_EXCEED;
|
||||
ldgm_input_data = tmp_data = malloc(ldgm_input_len);
|
||||
char *ciphertext = tmp_data + sizeof(crypto_payload_hdr_t);
|
||||
encryption_hdr = (uint32_t *)(void *) tmp_data;
|
||||
encryption_hdr[0] = htonl(CRYPTO_TYPE_AES128_CTR << 24);
|
||||
ldgm_payload_hdr[0] = ntohl(PT_ENCRYPT_VIDEO);
|
||||
#ifdef HAVE_CRYPTO
|
||||
int ret = openssl_encrypt(tx->encryption,
|
||||
tile->data, tile->data_len,
|
||||
(char *) ldgm_payload_hdr, ldgm_payload_hdr_len,
|
||||
ciphertext);
|
||||
#endif
|
||||
ldgm_input_len = sizeof(crypto_payload_hdr_t) + ret;
|
||||
|
||||
} else {
|
||||
ldgm_input_data = tile->data;
|
||||
ldgm_input_len = tile->data_len;
|
||||
ldgm_payload_hdr[0] = ntohl(PT_VIDEO);
|
||||
}
|
||||
ldgm_encoder_encode(tx->fec_state, (char *) ldgm_payload_hdr,
|
||||
ldgm_payload_hdr_len,
|
||||
ldgm_input_data, ldgm_input_len, &data_to_send, &data_to_send_len);
|
||||
free(tmp_data);
|
||||
tmp = substream << 22;
|
||||
tmp |= 0x3fffff & tx->buffer;
|
||||
// see definition in rtp_callback.h
|
||||
@@ -466,11 +534,19 @@ tx_send_base(struct tx *tx, struct tile *tile, struct rtp *rtp_session,
|
||||
|
||||
pt = PT_VIDEO_LDGM;
|
||||
|
||||
hdr = (char *) &ldgm_hdr;
|
||||
hdr_len = sizeof(ldgm_hdr);
|
||||
rtp_hdr = (char *) ldgm_hdr;
|
||||
rtp_hdr_len = sizeof(ldgm_video_payload_hdr_t);
|
||||
} else if(!tx->encryption) {
|
||||
rtp_hdr = (char *) video_hdr;
|
||||
rtp_hdr_len = sizeof(video_payload_hdr_t);
|
||||
}
|
||||
|
||||
uint32_t *hdr_offset; // data offset pointer - contains field that needs to be updated
|
||||
// every cycle
|
||||
if(fec_is_ldgm(tx)) {
|
||||
hdr_offset = ldgm_hdr + 1;
|
||||
} else {
|
||||
hdr = (char *) &video_hdr;
|
||||
hdr_len = sizeof(video_hdr);
|
||||
hdr_offset = video_hdr + 1;
|
||||
}
|
||||
|
||||
do {
|
||||
@@ -480,11 +556,7 @@ tx_send_base(struct tx *tx, struct tile *tile, struct rtp *rtp_session,
|
||||
|
||||
int offset = pos + fragment_offset;
|
||||
|
||||
video_hdr[1] = htonl(offset);
|
||||
if(fec_is_ldgm(tx)) {
|
||||
ldgm_hdr[1] = htonl(offset);
|
||||
}
|
||||
|
||||
*hdr_offset = htonl(offset);
|
||||
|
||||
data = data_to_send + pos;
|
||||
data_len = tx->mtu - hdrs_len;
|
||||
@@ -498,14 +570,24 @@ tx_send_base(struct tx *tx, struct tile *tile, struct rtp *rtp_session,
|
||||
pos += data_len;
|
||||
GET_STARTTIME;
|
||||
if(data_len) { /* check needed for FEC_MULT */
|
||||
char encrypted_data[data_len + MAX_CRYPTO_EXCEED];
|
||||
|
||||
if(tx->encryption && tx->fec_scheme != FEC_LDGM) {
|
||||
data_len = openssl_encrypt(tx->encryption,
|
||||
data, data_len,
|
||||
(char *) video_hdr, sizeof(video_payload_hdr_t),
|
||||
encrypted_data);
|
||||
data = encrypted_data;
|
||||
}
|
||||
|
||||
rtp_send_data_hdr(rtp_session, ts, pt, m, 0, 0,
|
||||
hdr, hdr_len,
|
||||
rtp_hdr, rtp_hdr_len,
|
||||
data, data_len, 0, 0, 0);
|
||||
if(m && tx->fec_scheme != FEC_NONE) {
|
||||
int i;
|
||||
for(i = 0; i < 5; ++i) {
|
||||
rtp_send_data_hdr(rtp_session, ts, pt, m, 0, 0,
|
||||
hdr, hdr_len,
|
||||
rtp_hdr, rtp_hdr_len,
|
||||
data, data_len, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
@@ -543,7 +625,7 @@ tx_send_base(struct tx *tx, struct tile *tile, struct rtp *rtp_session,
|
||||
*/
|
||||
void audio_tx_send(struct tx* tx, struct rtp *rtp_session, audio_frame2 * buffer)
|
||||
{
|
||||
const int pt = PT_AUDIO; /* PT set for audio in our packet format */
|
||||
int pt; /* PT set for audio in our packet format */
|
||||
unsigned int pos = 0u,
|
||||
m = 0u;
|
||||
int channel;
|
||||
@@ -551,7 +633,9 @@ void audio_tx_send(struct tx* tx, struct rtp *rtp_session, audio_frame2 * buffer
|
||||
int data_len;
|
||||
char *data;
|
||||
// see definition in rtp_callback.h
|
||||
audio_payload_hdr_t payload_hdr;
|
||||
uint32_t hdr_data[100];
|
||||
uint32_t *audio_hdr = hdr_data;
|
||||
uint32_t *crypto_hdr = audio_hdr + sizeof(audio_payload_hdr_t) / sizeof(uint32_t);
|
||||
uint32_t timestamp;
|
||||
#ifdef HAVE_LINUX
|
||||
struct timespec start, stop;
|
||||
@@ -564,12 +648,21 @@ void audio_tx_send(struct tx* tx, struct rtp *rtp_session, audio_frame2 * buffer
|
||||
int mult_pos[FEC_MAX_MULT];
|
||||
int mult_index = 0;
|
||||
int mult_first_sent = 0;
|
||||
int rtp_hdr_len;
|
||||
|
||||
platform_spin_lock(&tx->spin);
|
||||
|
||||
timestamp = get_local_mediatime();
|
||||
perf_record(UVP_SEND, timestamp);
|
||||
|
||||
if(tx->encryption) {
|
||||
rtp_hdr_len = sizeof(crypto_payload_hdr_t) + sizeof(audio_payload_hdr_t);
|
||||
pt = PT_ENCRYPT_AUDIO;
|
||||
} else {
|
||||
rtp_hdr_len = sizeof(audio_payload_hdr_t);
|
||||
pt = PT_AUDIO; /* PT set for audio in our packet format */
|
||||
}
|
||||
|
||||
for(channel = 0; channel < buffer->ch_count; ++channel)
|
||||
{
|
||||
chan_data = buffer->data[channel];
|
||||
@@ -586,17 +679,17 @@ void audio_tx_send(struct tx* tx, struct rtp *rtp_session, audio_frame2 * buffer
|
||||
uint32_t tmp;
|
||||
tmp = channel << 22; /* bits 0-9 */
|
||||
tmp |= tx->buffer; /* bits 10-31 */
|
||||
payload_hdr[0] = htonl(tmp);
|
||||
audio_hdr[0] = htonl(tmp);
|
||||
|
||||
payload_hdr[2] = htonl(buffer->data_len[channel]);
|
||||
audio_hdr[2] = htonl(buffer->data_len[channel]);
|
||||
|
||||
/* fourth word */
|
||||
tmp = (buffer->bps * 8) << 26;
|
||||
tmp |= buffer->sample_rate;
|
||||
payload_hdr[3] = htonl(tmp);
|
||||
audio_hdr[3] = htonl(tmp);
|
||||
|
||||
/* fifth word */
|
||||
payload_hdr[4] = htonl(get_audio_tag(buffer->codec));
|
||||
audio_hdr[4] = htonl(get_audio_tag(buffer->codec));
|
||||
|
||||
do {
|
||||
if(tx->fec_scheme == FEC_MULT) {
|
||||
@@ -610,15 +703,25 @@ void audio_tx_send(struct tx* tx, struct rtp *rtp_session, audio_frame2 * buffer
|
||||
if(channel == buffer->ch_count - 1)
|
||||
m = 1;
|
||||
}
|
||||
payload_hdr[1] = htonl(pos);
|
||||
audio_hdr[1] = htonl(pos);
|
||||
pos += data_len;
|
||||
|
||||
GET_STARTTIME;
|
||||
|
||||
if(data_len) { /* check needed for FEC_MULT */
|
||||
char encrypted_data[data_len + MAX_CRYPTO_EXCEED];
|
||||
if(tx->encryption) {
|
||||
crypto_hdr[0] = htonl(CRYPTO_TYPE_AES128_CTR << 24);
|
||||
data_len = openssl_encrypt(tx->encryption,
|
||||
data, data_len,
|
||||
(char *) audio_hdr, sizeof(audio_payload_hdr_t),
|
||||
encrypted_data);
|
||||
data = encrypted_data;
|
||||
}
|
||||
|
||||
rtp_send_data_hdr(rtp_session, timestamp, pt, m, 0, /* contributing sources */
|
||||
0, /* contributing sources length */
|
||||
(char *) &payload_hdr, sizeof(payload_hdr),
|
||||
(char *) audio_hdr, rtp_hdr_len,
|
||||
data, data_len,
|
||||
0, 0, 0);
|
||||
}
|
||||
@@ -650,3 +753,4 @@ void audio_tx_send(struct tx* tx, struct rtp *rtp_session, audio_frame2 * buffer
|
||||
|
||||
platform_spin_unlock(&tx->spin);
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,8 @@ enum tx_media_type {
|
||||
TX_MEDIA_VIDEO
|
||||
};
|
||||
|
||||
struct tx *tx_init(struct module *parent, unsigned mtu, enum tx_media_type media_type, char *fec);
|
||||
struct tx *tx_init(struct module *parent, unsigned mtu, enum tx_media_type media_type,
|
||||
char *fec, const char *encryption);
|
||||
void tx_send_tile(struct tx *tx_session, struct video_frame *frame, int pos, struct rtp *rtp_session);
|
||||
void tx_send(struct tx *tx_session, struct video_frame *frame, struct rtp *rtp_session);
|
||||
void audio_tx_send(struct tx *tx_session, struct rtp *rtp_session, audio_frame2 *buffer);
|
||||
|
||||
@@ -59,7 +59,6 @@
|
||||
#include "video_compress/jpeg.h"
|
||||
#include "libgpujpeg/gpujpeg_encoder.h"
|
||||
#include "libgpujpeg/gpujpeg_common.h"
|
||||
#include "messaging.h"
|
||||
#include "video_codec.h"
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
@@ -80,7 +79,6 @@ struct compress_jpeg_state {
|
||||
struct video_desc saved_desc;
|
||||
|
||||
int restart_interval;
|
||||
void *messaging_subscription;
|
||||
platform_spin_t spin;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user