mirror of https://github.com/LeOS-GSI/LeOS-Genesis
672 lines
19 KiB
C
672 lines
19 KiB
C
/**
|
|
* @file flooder.c
|
|
* @author Ambroz Bizjak <ambrop7@gmail.com>
|
|
*
|
|
* @section LICENSE
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are 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. Neither the name of the author 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
* ANY EXPRESS 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 AUTHOR 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.
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
|
|
#include <protocol/addr.h>
|
|
#include <protocol/scproto.h>
|
|
#include <misc/loglevel.h>
|
|
#include <misc/version.h>
|
|
#include <misc/nsskey.h>
|
|
#include <misc/byteorder.h>
|
|
#include <misc/loggers_string.h>
|
|
#include <misc/open_standard_streams.h>
|
|
#include <base/BLog.h>
|
|
#include <system/BReactor.h>
|
|
#include <system/BSignal.h>
|
|
#include <system/BNetwork.h>
|
|
#include <flow/SinglePacketBuffer.h>
|
|
#include <flow/PacketProtoEncoder.h>
|
|
#include <nspr_support/BSSLConnection.h>
|
|
#include <server_connection/ServerConnection.h>
|
|
|
|
#ifndef BADVPN_USE_WINAPI
|
|
#include <base/BLog_syslog.h>
|
|
#endif
|
|
|
|
#include <flooder/flooder.h>
|
|
|
|
#include <generated/blog_channel_flooder.h>
|
|
|
|
#define LOGGER_STDOUT 1
|
|
#define LOGGER_SYSLOG 2
|
|
|
|
// command-line options
|
|
struct {
|
|
int help;
|
|
int version;
|
|
int logger;
|
|
#ifndef BADVPN_USE_WINAPI
|
|
char *logger_syslog_facility;
|
|
char *logger_syslog_ident;
|
|
#endif
|
|
int loglevel;
|
|
int loglevels[BLOG_NUM_CHANNELS];
|
|
int ssl;
|
|
char *nssdb;
|
|
char *client_cert_name;
|
|
char *server_name;
|
|
char *server_addr;
|
|
peerid_t floods[MAX_FLOODS];
|
|
int num_floods;
|
|
} options;
|
|
|
|
// server address we connect to
|
|
BAddr server_addr;
|
|
|
|
// server name to use for SSL
|
|
char server_name[256];
|
|
|
|
// reactor
|
|
BReactor ss;
|
|
|
|
// client certificate if using SSL
|
|
CERTCertificate *client_cert;
|
|
|
|
// client private key if using SSL
|
|
SECKEYPrivateKey *client_key;
|
|
|
|
// server connection
|
|
ServerConnection server;
|
|
|
|
// whether server is ready
|
|
int server_ready;
|
|
|
|
// my ID, defined only after server_ready
|
|
peerid_t my_id;
|
|
|
|
// flooding output
|
|
PacketRecvInterface flood_source;
|
|
PacketProtoEncoder flood_encoder;
|
|
SinglePacketBuffer flood_buffer;
|
|
|
|
// whether we were asked for a packet and blocked
|
|
int flood_blocking;
|
|
|
|
// index of next peer to send packet too
|
|
int flood_next;
|
|
|
|
/**
|
|
* Cleans up everything that can be cleaned up from inside the event loop.
|
|
*/
|
|
static void terminate (void);
|
|
|
|
/**
|
|
* Prints command line help.
|
|
*/
|
|
static void print_help (const char *name);
|
|
|
|
/**
|
|
* Prints program name, version and copyright notice.
|
|
*/
|
|
static void print_version (void);
|
|
|
|
/**
|
|
* Parses command line options into the options strucute.
|
|
*
|
|
* @return 1 on success, 0 on failure
|
|
*/
|
|
static int parse_arguments (int argc, char *argv[]);
|
|
|
|
/**
|
|
* Processes command line options.
|
|
*
|
|
* @return 1 on success, 0 on failure
|
|
*/
|
|
static int resolve_arguments (void);
|
|
|
|
/**
|
|
* Handler invoked when program termination is requested.
|
|
*/
|
|
static void signal_handler (void *unused);
|
|
|
|
static void server_handler_error (void *user);
|
|
static void server_handler_ready (void *user, peerid_t param_my_id, uint32_t ext_ip);
|
|
static void server_handler_newclient (void *user, peerid_t peer_id, int flags, const uint8_t *cert, int cert_len);
|
|
static void server_handler_endclient (void *user, peerid_t peer_id);
|
|
static void server_handler_message (void *user, peerid_t peer_id, uint8_t *data, int data_len);
|
|
|
|
static void flood_source_handler_recv (void *user, uint8_t *data);
|
|
|
|
int main (int argc, char *argv[])
|
|
{
|
|
if (argc <= 0) {
|
|
return 1;
|
|
}
|
|
|
|
// open standard streams
|
|
open_standard_streams();
|
|
|
|
// parse command-line arguments
|
|
if (!parse_arguments(argc, argv)) {
|
|
fprintf(stderr, "Failed to parse arguments\n");
|
|
print_help(argv[0]);
|
|
goto fail0;
|
|
}
|
|
|
|
// handle --help and --version
|
|
if (options.help) {
|
|
print_version();
|
|
print_help(argv[0]);
|
|
return 0;
|
|
}
|
|
if (options.version) {
|
|
print_version();
|
|
return 0;
|
|
}
|
|
|
|
// initialize logger
|
|
switch (options.logger) {
|
|
case LOGGER_STDOUT:
|
|
BLog_InitStdout();
|
|
break;
|
|
#ifndef BADVPN_USE_WINAPI
|
|
case LOGGER_SYSLOG:
|
|
if (!BLog_InitSyslog(options.logger_syslog_ident, options.logger_syslog_facility)) {
|
|
fprintf(stderr, "Failed to initialize syslog logger\n");
|
|
goto fail0;
|
|
}
|
|
break;
|
|
#endif
|
|
default:
|
|
ASSERT(0);
|
|
}
|
|
|
|
// configure logger channels
|
|
for (int i = 0; i < BLOG_NUM_CHANNELS; i++) {
|
|
if (options.loglevels[i] >= 0) {
|
|
BLog_SetChannelLoglevel(i, options.loglevels[i]);
|
|
}
|
|
else if (options.loglevel >= 0) {
|
|
BLog_SetChannelLoglevel(i, options.loglevel);
|
|
}
|
|
}
|
|
|
|
BLog(BLOG_NOTICE, "initializing "GLOBAL_PRODUCT_NAME" "PROGRAM_NAME" "GLOBAL_VERSION);
|
|
|
|
// initialize network
|
|
if (!BNetwork_GlobalInit()) {
|
|
BLog(BLOG_ERROR, "BNetwork_GlobalInit failed");
|
|
goto fail1;
|
|
}
|
|
|
|
// init time
|
|
BTime_Init();
|
|
|
|
// resolve addresses
|
|
if (!resolve_arguments()) {
|
|
BLog(BLOG_ERROR, "Failed to resolve arguments");
|
|
goto fail1;
|
|
}
|
|
|
|
// init reactor
|
|
if (!BReactor_Init(&ss)) {
|
|
BLog(BLOG_ERROR, "BReactor_Init failed");
|
|
goto fail1;
|
|
}
|
|
|
|
// setup signal handler
|
|
if (!BSignal_Init(&ss, signal_handler, NULL)) {
|
|
BLog(BLOG_ERROR, "BSignal_Init failed");
|
|
goto fail1a;
|
|
}
|
|
|
|
if (options.ssl) {
|
|
// init NSPR
|
|
PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
|
|
|
|
// register local NSPR file types
|
|
if (!BSSLConnection_GlobalInit()) {
|
|
BLog(BLOG_ERROR, "BSSLConnection_GlobalInit failed");
|
|
goto fail3;
|
|
}
|
|
|
|
// init NSS
|
|
if (NSS_Init(options.nssdb) != SECSuccess) {
|
|
BLog(BLOG_ERROR, "NSS_Init failed (%d)", (int)PR_GetError());
|
|
goto fail2;
|
|
}
|
|
|
|
// set cipher policy
|
|
if (NSS_SetDomesticPolicy() != SECSuccess) {
|
|
BLog(BLOG_ERROR, "NSS_SetDomesticPolicy failed (%d)", (int)PR_GetError());
|
|
goto fail3;
|
|
}
|
|
|
|
// init server cache
|
|
if (SSL_ConfigServerSessionIDCache(0, 0, 0, NULL) != SECSuccess) {
|
|
BLog(BLOG_ERROR, "SSL_ConfigServerSessionIDCache failed (%d)", (int)PR_GetError());
|
|
goto fail3;
|
|
}
|
|
|
|
// open server certificate and private key
|
|
if (!open_nss_cert_and_key(options.client_cert_name, &client_cert, &client_key)) {
|
|
BLog(BLOG_ERROR, "Cannot open certificate and key");
|
|
goto fail4;
|
|
}
|
|
}
|
|
|
|
// start connecting to server
|
|
if (!ServerConnection_Init(
|
|
&server, &ss, NULL, server_addr, SC_KEEPALIVE_INTERVAL, SERVER_BUFFER_MIN_PACKETS, options.ssl, 0, client_cert, client_key, server_name, NULL,
|
|
server_handler_error, server_handler_ready, server_handler_newclient, server_handler_endclient, server_handler_message
|
|
)) {
|
|
BLog(BLOG_ERROR, "ServerConnection_Init failed");
|
|
goto fail5;
|
|
}
|
|
|
|
// set server not ready
|
|
server_ready = 0;
|
|
|
|
// enter event loop
|
|
BLog(BLOG_NOTICE, "entering event loop");
|
|
BReactor_Exec(&ss);
|
|
|
|
if (server_ready) {
|
|
ServerConnection_ReleaseBuffers(&server);
|
|
SinglePacketBuffer_Free(&flood_buffer);
|
|
PacketProtoEncoder_Free(&flood_encoder);
|
|
PacketRecvInterface_Free(&flood_source);
|
|
}
|
|
|
|
ServerConnection_Free(&server);
|
|
fail5:
|
|
if (options.ssl) {
|
|
CERT_DestroyCertificate(client_cert);
|
|
SECKEY_DestroyPrivateKey(client_key);
|
|
fail4:
|
|
ASSERT_FORCE(SSL_ShutdownServerSessionIDCache() == SECSuccess)
|
|
fail3:
|
|
SSL_ClearSessionCache();
|
|
ASSERT_FORCE(NSS_Shutdown() == SECSuccess)
|
|
fail2:
|
|
ASSERT_FORCE(PR_Cleanup() == PR_SUCCESS)
|
|
PL_ArenaFinish();
|
|
}
|
|
|
|
BSignal_Finish();
|
|
fail1a:
|
|
BReactor_Free(&ss);
|
|
fail1:
|
|
BLog(BLOG_NOTICE, "exiting");
|
|
BLog_Free();
|
|
fail0:
|
|
DebugObjectGlobal_Finish();
|
|
|
|
return 1;
|
|
}
|
|
|
|
void terminate (void)
|
|
{
|
|
BLog(BLOG_NOTICE, "tearing down");
|
|
|
|
// exit event loop
|
|
BReactor_Quit(&ss, 0);
|
|
}
|
|
|
|
void print_help (const char *name)
|
|
{
|
|
printf(
|
|
"Usage:\n"
|
|
" %s\n"
|
|
" [--help]\n"
|
|
" [--version]\n"
|
|
" [--logger <"LOGGERS_STRING">]\n"
|
|
#ifndef BADVPN_USE_WINAPI
|
|
" (logger=syslog?\n"
|
|
" [--syslog-facility <string>]\n"
|
|
" [--syslog-ident <string>]\n"
|
|
" )\n"
|
|
#endif
|
|
" [--loglevel <0-5/none/error/warning/notice/info/debug>]\n"
|
|
" [--channel-loglevel <channel-name> <0-5/none/error/warning/notice/info/debug>] ...\n"
|
|
" [--ssl --nssdb <string> --client-cert-name <string>]\n"
|
|
" [--server-name <string>]\n"
|
|
" --server-addr <addr>\n"
|
|
" [--flood-id <id>] ...\n"
|
|
"Address format is a.b.c.d:port (IPv4) or [addr]:port (IPv6).\n",
|
|
name
|
|
);
|
|
}
|
|
|
|
void print_version (void)
|
|
{
|
|
printf(GLOBAL_PRODUCT_NAME" "PROGRAM_NAME" "GLOBAL_VERSION"\n"GLOBAL_COPYRIGHT_NOTICE"\n");
|
|
}
|
|
|
|
int parse_arguments (int argc, char *argv[])
|
|
{
|
|
if (argc <= 0) {
|
|
return 0;
|
|
}
|
|
|
|
options.help = 0;
|
|
options.version = 0;
|
|
options.logger = LOGGER_STDOUT;
|
|
#ifndef BADVPN_USE_WINAPI
|
|
options.logger_syslog_facility = "daemon";
|
|
options.logger_syslog_ident = argv[0];
|
|
#endif
|
|
options.loglevel = -1;
|
|
for (int i = 0; i < BLOG_NUM_CHANNELS; i++) {
|
|
options.loglevels[i] = -1;
|
|
}
|
|
options.ssl = 0;
|
|
options.nssdb = NULL;
|
|
options.client_cert_name = NULL;
|
|
options.server_name = NULL;
|
|
options.server_addr = NULL;
|
|
options.num_floods = 0;
|
|
|
|
int i;
|
|
for (i = 1; i < argc; i++) {
|
|
char *arg = argv[i];
|
|
if (!strcmp(arg, "--help")) {
|
|
options.help = 1;
|
|
}
|
|
else if (!strcmp(arg, "--version")) {
|
|
options.version = 1;
|
|
}
|
|
else if (!strcmp(arg, "--logger")) {
|
|
if (1 >= argc - i) {
|
|
fprintf(stderr, "%s: requires an argument\n", arg);
|
|
return 0;
|
|
}
|
|
char *arg2 = argv[i + 1];
|
|
if (!strcmp(arg2, "stdout")) {
|
|
options.logger = LOGGER_STDOUT;
|
|
}
|
|
#ifndef BADVPN_USE_WINAPI
|
|
else if (!strcmp(arg2, "syslog")) {
|
|
options.logger = LOGGER_SYSLOG;
|
|
}
|
|
#endif
|
|
else {
|
|
fprintf(stderr, "%s: wrong argument\n", arg);
|
|
return 0;
|
|
}
|
|
i++;
|
|
}
|
|
#ifndef BADVPN_USE_WINAPI
|
|
else if (!strcmp(arg, "--syslog-facility")) {
|
|
if (1 >= argc - i) {
|
|
fprintf(stderr, "%s: requires an argument\n", arg);
|
|
return 0;
|
|
}
|
|
options.logger_syslog_facility = argv[i + 1];
|
|
i++;
|
|
}
|
|
else if (!strcmp(arg, "--syslog-ident")) {
|
|
if (1 >= argc - i) {
|
|
fprintf(stderr, "%s: requires an argument\n", arg);
|
|
return 0;
|
|
}
|
|
options.logger_syslog_ident = argv[i + 1];
|
|
i++;
|
|
}
|
|
#endif
|
|
else if (!strcmp(arg, "--loglevel")) {
|
|
if (1 >= argc - i) {
|
|
fprintf(stderr, "%s: requires an argument\n", arg);
|
|
return 0;
|
|
}
|
|
if ((options.loglevel = parse_loglevel(argv[i + 1])) < 0) {
|
|
fprintf(stderr, "%s: wrong argument\n", arg);
|
|
return 0;
|
|
}
|
|
i++;
|
|
}
|
|
else if (!strcmp(arg, "--channel-loglevel")) {
|
|
if (2 >= argc - i) {
|
|
fprintf(stderr, "%s: requires two arguments\n", arg);
|
|
return 0;
|
|
}
|
|
int channel = BLogGlobal_GetChannelByName(argv[i + 1]);
|
|
if (channel < 0) {
|
|
fprintf(stderr, "%s: wrong channel argument\n", arg);
|
|
return 0;
|
|
}
|
|
int loglevel = parse_loglevel(argv[i + 2]);
|
|
if (loglevel < 0) {
|
|
fprintf(stderr, "%s: wrong loglevel argument\n", arg);
|
|
return 0;
|
|
}
|
|
options.loglevels[channel] = loglevel;
|
|
i += 2;
|
|
}
|
|
else if (!strcmp(arg, "--ssl")) {
|
|
options.ssl = 1;
|
|
}
|
|
else if (!strcmp(arg, "--nssdb")) {
|
|
if (1 >= argc - i) {
|
|
fprintf(stderr, "%s: requires an argument\n", arg);
|
|
return 0;
|
|
}
|
|
options.nssdb = argv[i + 1];
|
|
i++;
|
|
}
|
|
else if (!strcmp(arg, "--client-cert-name")) {
|
|
if (1 >= argc - i) {
|
|
fprintf(stderr, "%s: requires an argument\n", arg);
|
|
return 0;
|
|
}
|
|
options.client_cert_name = argv[i + 1];
|
|
i++;
|
|
}
|
|
else if (!strcmp(arg, "--server-name")) {
|
|
if (1 >= argc - i) {
|
|
fprintf(stderr, "%s: requires an argument\n", arg);
|
|
return 0;
|
|
}
|
|
options.server_name = argv[i + 1];
|
|
i++;
|
|
}
|
|
else if (!strcmp(arg, "--server-addr")) {
|
|
if (1 >= argc - i) {
|
|
fprintf(stderr, "%s: requires an argument\n", arg);
|
|
return 0;
|
|
}
|
|
options.server_addr = argv[i + 1];
|
|
i++;
|
|
}
|
|
else if (!strcmp(arg, "--flood-id")) {
|
|
if (1 >= argc - i) {
|
|
fprintf(stderr, "%s: requires an argument\n", arg);
|
|
return 0;
|
|
}
|
|
if (options.num_floods == MAX_FLOODS) {
|
|
fprintf(stderr, "%s: too many\n", arg);
|
|
return 0;
|
|
}
|
|
options.floods[options.num_floods] = atoi(argv[i + 1]);
|
|
options.num_floods++;
|
|
i++;
|
|
}
|
|
else {
|
|
fprintf(stderr, "unknown option: %s\n", arg);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (options.help || options.version) {
|
|
return 1;
|
|
}
|
|
|
|
if (options.ssl != !!options.nssdb) {
|
|
fprintf(stderr, "False: --ssl <=> --nssdb\n");
|
|
return 0;
|
|
}
|
|
|
|
if (options.ssl != !!options.client_cert_name) {
|
|
fprintf(stderr, "False: --ssl <=> --client-cert-name\n");
|
|
return 0;
|
|
}
|
|
|
|
if (!options.server_addr) {
|
|
fprintf(stderr, "False: --server-addr\n");
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int resolve_arguments (void)
|
|
{
|
|
// resolve server address
|
|
ASSERT(options.server_addr)
|
|
if (!BAddr_Parse(&server_addr, options.server_addr, server_name, sizeof(server_name))) {
|
|
BLog(BLOG_ERROR, "server addr: BAddr_Parse failed");
|
|
return 0;
|
|
}
|
|
if (!addr_supported(server_addr)) {
|
|
BLog(BLOG_ERROR, "server addr: not supported");
|
|
return 0;
|
|
}
|
|
|
|
// override server name if requested
|
|
if (options.server_name) {
|
|
if (strlen(options.server_name) >= sizeof(server_name)) {
|
|
BLog(BLOG_ERROR, "server name: too long");
|
|
return 0;
|
|
}
|
|
strcpy(server_name, options.server_name);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
void signal_handler (void *unused)
|
|
{
|
|
BLog(BLOG_NOTICE, "termination requested");
|
|
|
|
terminate();
|
|
}
|
|
|
|
void server_handler_error (void *user)
|
|
{
|
|
BLog(BLOG_ERROR, "server connection failed, exiting");
|
|
|
|
terminate();
|
|
}
|
|
|
|
void server_handler_ready (void *user, peerid_t param_my_id, uint32_t ext_ip)
|
|
{
|
|
ASSERT(!server_ready)
|
|
|
|
// remember our ID
|
|
my_id = param_my_id;
|
|
|
|
// init flooding
|
|
|
|
// init source
|
|
PacketRecvInterface_Init(&flood_source, SC_MAX_ENC, flood_source_handler_recv, NULL, BReactor_PendingGroup(&ss));
|
|
|
|
// init encoder
|
|
PacketProtoEncoder_Init(&flood_encoder, &flood_source, BReactor_PendingGroup(&ss));
|
|
|
|
// init buffer
|
|
if (!SinglePacketBuffer_Init(&flood_buffer, PacketProtoEncoder_GetOutput(&flood_encoder), ServerConnection_GetSendInterface(&server), BReactor_PendingGroup(&ss))) {
|
|
BLog(BLOG_ERROR, "SinglePacketBuffer_Init failed, exiting");
|
|
goto fail1;
|
|
}
|
|
|
|
// set not blocking
|
|
flood_blocking = 0;
|
|
|
|
// set server ready
|
|
server_ready = 1;
|
|
|
|
BLog(BLOG_INFO, "server: ready, my ID is %d", (int)my_id);
|
|
|
|
return;
|
|
|
|
fail1:
|
|
PacketProtoEncoder_Free(&flood_encoder);
|
|
PacketRecvInterface_Free(&flood_source);
|
|
terminate();
|
|
}
|
|
|
|
void server_handler_newclient (void *user, peerid_t peer_id, int flags, const uint8_t *cert, int cert_len)
|
|
{
|
|
ASSERT(server_ready)
|
|
|
|
BLog(BLOG_INFO, "newclient %d", (int)peer_id);
|
|
}
|
|
|
|
void server_handler_endclient (void *user, peerid_t peer_id)
|
|
{
|
|
ASSERT(server_ready)
|
|
|
|
BLog(BLOG_INFO, "endclient %d", (int)peer_id);
|
|
}
|
|
|
|
void server_handler_message (void *user, peerid_t peer_id, uint8_t *data, int data_len)
|
|
{
|
|
ASSERT(server_ready)
|
|
ASSERT(data_len >= 0)
|
|
ASSERT(data_len <= SC_MAX_MSGLEN)
|
|
|
|
BLog(BLOG_INFO, "message from %d", (int)peer_id);
|
|
}
|
|
|
|
void flood_source_handler_recv (void *user, uint8_t *data)
|
|
{
|
|
ASSERT(server_ready)
|
|
ASSERT(!flood_blocking)
|
|
if (options.num_floods > 0) {
|
|
ASSERT(flood_next >= 0)
|
|
ASSERT(flood_next < options.num_floods)
|
|
}
|
|
|
|
if (options.num_floods == 0) {
|
|
flood_blocking = 1;
|
|
return;
|
|
}
|
|
|
|
peerid_t peer_id = options.floods[flood_next];
|
|
flood_next = (flood_next + 1) % options.num_floods;
|
|
|
|
BLog(BLOG_INFO, "message to %d", (int)peer_id);
|
|
|
|
struct sc_header header;
|
|
header.type = SCID_OUTMSG;
|
|
memcpy(data, &header, sizeof(header));
|
|
|
|
struct sc_client_outmsg omsg;
|
|
omsg.clientid = htol16(peer_id);
|
|
memcpy(data + sizeof(header), &omsg, sizeof(omsg));
|
|
|
|
memset(data + sizeof(struct sc_header) + sizeof(struct sc_client_outmsg), 0, SC_MAX_MSGLEN);
|
|
|
|
PacketRecvInterface_Done(&flood_source, sizeof(struct sc_header) + sizeof(struct sc_client_outmsg) + SC_MAX_MSGLEN);
|
|
}
|