Flowgrind
Advanced TCP traffic generator
source.c File Reference

Routines used by Flowgrind to setup the source for a test flow. More...

#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <strings.h>
#include <signal.h>
#include <string.h>
#include <fcntl.h>
#include <math.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/wait.h>
#include <errno.h>
#include <time.h>
#include <syslog.h>
#include <sys/time.h>
#include <netdb.h>
#include <pthread.h>
#include <float.h>
#include "debug.h"
#include "fg_error.h"
#include "fg_math.h"
#include "fg_socket.h"
#include "fg_time.h"
#include "fg_log.h"
#include "fg_pcap.h"

Go to the source code of this file.

Functions

int add_flow_source (struct request_add_flow_source *request)
 To set daemon flow as source endpoint. More...
 
int do_connect (struct flow *flow)
 Establishes a connection of a flow. More...
 
int get_tcp_info (struct flow *flow, struct tcp_info *info)
 
void init_flow (struct flow *flow, int is_source)
 To initialize all flows to the default value. More...
 
static int name2socket (struct flow *flow, char *server_name, unsigned port, struct sockaddr **saptr, socklen_t *lenp, const int read_buffer_size_req, int *read_buffer_size, const int send_buffer_size_req, int *send_buffer_size)
 
void remove_flow (unsigned i)
 
void uninit_flow (struct flow *flow)
 

Detailed Description

Routines used by Flowgrind to setup the source for a test flow.

Definition in file source.c.

Function Documentation

◆ add_flow_source()

int add_flow_source ( struct request_add_flow_source request)

To set daemon flow as source endpoint.

To set the flow options and settings as source endpoint. Depending upon the late connection option the data connection is established to connect the destination daemon listening port address with source daemon.

Parameters
[in,out]requestContain the test option and parameter for daemon source endpoint

Definition at line 177 of file source.c.

178 {
179 #ifdef HAVE_SO_TCP_CONGESTION
180  socklen_t opt_len = 0;
181 #endif /* HAVE_SO_TCP_CONGESTION */
182  struct flow *flow;
183 
185  logging(LOG_WARNING, "can not accept another flow, already "
186  "handling %zu flows", fg_list_size(&flows));
188  "Can not accept another flow, already "
189  "handling %zu flows.", fg_list_size(&flows));
190  return -1;
191  }
192 
193  flow = malloc(sizeof(struct flow));
194  if (!flow) {
195  logging(LOG_ALERT, "could not allocate memory for flow");
196  return -1;
197  }
198 
199  init_flow(flow, 1);
200 
201  flow->settings = request->settings;
202  flow->source_settings = request->source_settings;
203  /* be greedy with buffer sizes */
206  /* Controller flow ID is set in the daemon */
208  if (flow->write_block == NULL || flow->read_block == NULL) {
209  logging(LOG_ALERT, "could not allocate memory for read/write "
210  "blocks");
211  request_error(&request->r, "could not allocate memory for read/write blocks");
212  uninit_flow(flow);
213  return -1;
214  }
215  if (flow->settings.byte_counting) {
216  int byte_idx;
217  for (byte_idx = 0; byte_idx < flow->settings.maximum_block_size; byte_idx++)
218  *(flow->write_block + byte_idx) = (unsigned char)(byte_idx & 0xff);
219  }
220 
224  &flow->addr, &flow->addr_len,
225  flow->settings.requested_read_buffer_size, &request->real_read_buffer_size,
226  flow->settings.requested_send_buffer_size, &request->real_send_buffer_size);
227  if (flow->fd == -1) {
228  logging(LOG_ALERT, "could not create data socket: %s",
229  flow->error);
230  request_error(&request->r, "Could not create data socket: %s", flow->error);
231  uninit_flow(flow);
232  return -1;
233  }
234 
235  if (set_flow_tcp_options(flow) == -1) {
236  request->r.error = flow->error;
237  flow->error = NULL;
238  uninit_flow(flow);
239  return -1;
240  }
241 
242 #ifdef HAVE_SO_TCP_CONGESTION
243  opt_len = sizeof(request->cc_alg);
244  if (getsockopt(flow->fd, IPPROTO_TCP, TCP_CONGESTION,
245  request->cc_alg, &opt_len) == -1) {
246  request_error(&request->r, "failed to determine actual congestion control algorithm: %s",
247  strerror(errno));
248  uninit_flow(flow);
249  return -1;
250  }
251 #endif /* HAVE_SO_TCP_CONGESTION */
252 
253 #ifdef HAVE_LIBPCAP
254  fg_pcap_go(flow);
255 #endif /* HAVE_LIBPCAP */
257  DEBUG_MSG(4, "(early) connecting test socket (fd=%u)", flow->fd);
258  if (do_connect(flow) == -1) {
259  request->r.error = flow->error;
260  flow->error = NULL;
261  uninit_flow(flow);
262  return -1;
263  }
264  }
265 
266  request->flow_id = flow->id;
267 
269 
270  return 0;
271 }

◆ do_connect()

int do_connect ( struct flow flow)

Establishes a connection of a flow.

Establishes a connection to the destination daemon listening port, and marks the flow as connected.

Parameters
[in,out]flowFlow to connect.

Definition at line 153 of file source.c.

153  {
154  int rc;
155 
156  rc = connect(flow->fd, flow->addr, flow->addr_len);
157  if (rc == -1 && errno != EINPROGRESS) {
158  flow_error(flow, "connect() failed: %s",
159  strerror(errno));
160  err("failed to connect flow %u", flow->id);
161  return rc;
162  }
163  flow->connect_called = 1;
164  flow->pmtu = get_pmtu(flow->fd);
165  return 0;
166 }

◆ get_tcp_info()

int get_tcp_info ( struct flow flow,
struct tcp_info *  info 
)

◆ init_flow()

void init_flow ( struct flow flow,
int  is_source 
)

To initialize all flows to the default value.

The daemon maintain all its data in its flow statistics data structure. These data are initialize to the default value or zero value according to their metrics details.

Parameters
[in,out]flowflow structure maintained by a daemon
[in]is_sourceto determine flow endpoint i.e. source or destination

Definition at line 896 of file daemon.c.

897 {
898  memset(flow, 0, sizeof(struct flow));
899 
900  /* flow id is given by controller */
901  flow->id = -1;
902  flow->endpoint = is_source ? SOURCE : DESTINATION;
904  flow->fd = -1;
905  flow->listenfd_data = -1;
906 
909 
910  flow->finished[READ] = flow->finished[WRITE] = 0;
911 
912  flow->addr = 0;
913 
914  foreach(int *i, INTERVAL, FINAL) {
915  flow->statistics[*i].bytes_read = 0;
916  flow->statistics[*i].bytes_written = 0;
917 
922 
923  flow->statistics[*i].rtt_min = FLT_MAX;
924  flow->statistics[*i].rtt_max = FLT_MIN;
925  flow->statistics[*i].rtt_sum = 0.0F;
926  flow->statistics[*i].iat_min = FLT_MAX;
927  flow->statistics[*i].iat_max = FLT_MIN;
928  flow->statistics[*i].iat_sum = 0.0F;
929  flow->statistics[*i].delay_min = FLT_MAX;
930  flow->statistics[*i].delay_max = FLT_MIN;
931  flow->statistics[*i].delay_sum = 0.0F;
932  }
933 
934  DEBUG_MSG(LOG_NOTICE, "called init flow %d", flow->id);
935 }

◆ name2socket()

static int name2socket ( struct flow flow,
char *  server_name,
unsigned  port,
struct sockaddr **  saptr,
socklen_t *  lenp,
const int  read_buffer_size_req,
int *  read_buffer_size,
const int  send_buffer_size_req,
int *  send_buffer_size 
)
static
Bug:
: currently we use portable select() API, which is limited by the number of bits in an fd_set

Definition at line 76 of file source.c.

80 {
81  int fd, n;
82  struct addrinfo hints, *res, *ressave;
83  char service[7];
84 
85  bzero(&hints, sizeof(struct addrinfo));
86  hints.ai_family = AF_UNSPEC;
87  hints.ai_socktype = SOCK_STREAM;
88 
89  snprintf(service, sizeof(service), "%u", port);
90 
91  if ((n = getaddrinfo(server_name, service, &hints, &res)) != 0) {
92  flow_error(flow, "getaddrinfo() failed: %s",
93  gai_strerror(n));
94  return -1;
95  }
96  ressave = res;
97 
98  do {
99 
100  fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
101 
102  if (fd < 0)
103  continue;
104  /* FIXME: currently we use portable select() API, which
105  * is limited by the number of bits in an fd_set */
106  if (fd >= FD_SETSIZE) {
107  logging(LOG_ALERT, "too many file descriptors are"
108  "already in use by this daemon");
109  flow_error(flow, "failed to create listen socket: too many"
110  "file descriptors in use by this daemon");
111  close(fd);
112  freeaddrinfo(ressave);
113  return -1;
114  }
115 
116  if (send_buffer_size)
117  *send_buffer_size = set_window_size_directed(fd, send_buffer_size_req, SO_SNDBUF);
118  if (read_buffer_size)
119  *read_buffer_size = set_window_size_directed(fd, read_buffer_size_req, SO_RCVBUF);
120 
121  break;
122 
123  } while ((res = res->ai_next) != NULL);
124 
125  if (res == NULL) {
126  flow_error(flow, "Could not create socket for "
127  "\"%s:%d\": %s", server_name, port, strerror(errno));
128  freeaddrinfo(ressave);
129  return -1;
130  }
131 
132  if (saptr && lenp) {
133  *saptr = malloc(res->ai_addrlen);
134  if (*saptr == NULL)
135  crit("malloc(): failed");
136  memcpy(*saptr, res->ai_addr, res->ai_addrlen);
137  *lenp = res->ai_addrlen;
138  }
139 
140  freeaddrinfo(ressave);
141 
142  return fd;
143 }

◆ remove_flow()

void remove_flow ( unsigned  i)

◆ uninit_flow()

void uninit_flow ( struct flow flow)

Definition at line 165 of file daemon.c.

166 {
167  DEBUG_MSG(LOG_DEBUG,"uninit_flow() called for flow %d",flow->id);
168  if (flow->fd != -1)
169  close(flow->fd);
170  if (flow->listenfd_data != -1)
171  close(flow->listenfd_data);
172 #ifdef HAVE_LIBPCAP
173  int rc;
175  rc = pthread_cancel(flow->pcap_thread);
176  if (rc)
177  logging(LOG_WARNING, "failed to cancel dump thread: %s",
178  strerror(rc));
179 
180  /* wait for the dump thread to react to the cancellation request */
181  rc = pthread_join(flow->pcap_thread, NULL);
182  if (rc)
183  logging(LOG_WARNING, "failed to join dump thread: %s",
184  strerror(rc));
185  }
186 #endif /* HAVE_LIBPCAP */
189 }
DEBUG_MSG
#define DEBUG_MSG(LVL, MSG,...)
Print debug message to standard error.
Definition: debug.h:49
flow::statistics::response_blocks_read
unsigned response_blocks_read
Definition: daemon.h:132
FINAL
@ FINAL
Final report.
Definition: common.h:116
INTERVAL
@ INTERVAL
Intermediated interval report.
Definition: common.h:114
WRITE
@ WRITE
Write operation.
Definition: common.h:106
flow::statistics::delay_sum
double delay_sum
Accumulated one-way delay.
Definition: daemon.h:148
flow::current_read_block_size
unsigned current_read_block_size
Definition: daemon.h:101
flow::statistics::iat_min
double iat_min
Minimum interarrival time.
Definition: daemon.h:138
fg_list_size
size_t fg_list_size(struct linked_list *const list)
Returns the number of elements in the list.
Definition: fg_list.c:211
flow::connect_called
char connect_called
Definition: daemon.h:111
flow
Definition: daemon.h:73
request_error
void request_error(struct request *request, const char *fmt,...)
Definition: daemon.c:132
crit
#define crit(...)
To report an critical error w/ the corresponding system error message.
Definition: fg_error.h:36
flow_settings::requested_read_buffer_size
int requested_read_buffer_size
Request receiver buffer, advertised window in bytes (option -W).
Definition: common.h:198
flow_source_settings::destination_host
char destination_host[256]
Definition: daemon.h:65
name2socket
static int name2socket(struct flow *flow, char *server_name, unsigned port, struct sockaddr **saptr, socklen_t *lenp, const int read_buffer_size_req, int *read_buffer_size, const int send_buffer_size_req, int *send_buffer_size)
Definition: source.c:76
port
static unsigned port
Definition: flowgrindd.c:95
set_flow_tcp_options
int set_flow_tcp_options(struct flow *flow)
Definition: daemon.c:1424
logging
void logging(int priority, const char *fmt,...)
Definition: fg_log.c:69
flow::statistics::rtt_sum
double rtt_sum
Accumulated round-trip time.
Definition: daemon.h:154
READ
@ READ
Read operation.
Definition: common.h:108
DESTINATION
@ DESTINATION
Endpoint that accepts the connection.
Definition: common.h:100
flow::statistics::delay_max
double delay_max
Maximum one-way delay.
Definition: daemon.h:146
MAX_FLOWS_DAEMON
#define MAX_FLOWS_DAEMON
Maximal number of parallel flows supported by one daemon instance.
Definition: common.h:65
flow::source_settings
struct flow_source_settings source_settings
Definition: daemon.h:84
flow::pmtu
int pmtu
Definition: daemon.h:114
flow_settings::byte_counting
int byte_counting
Enumerate bytes in payload instead of sending zeros (option -E).
Definition: common.h:229
flow::statistics::delay_min
double delay_min
Minimum one-way delay.
Definition: daemon.h:144
flow::settings
struct flow_settings settings
Definition: daemon.h:83
flow::read_block
char * read_block
Definition: daemon.h:97
init_flow
void init_flow(struct flow *flow, int is_source)
To initialize all flows to the default value.
Definition: daemon.c:896
flow::statistics::bytes_written
unsigned long long bytes_written
Definition: daemon.h:125
err
#define err(...)
To report an error w/ the corresponding system error message.
Definition: fg_error.h:43
flow::statistics::rtt_max
double rtt_max
Maximum round-trip time.
Definition: daemon.h:152
flow_settings::traffic_dump
int traffic_dump
Dump traffic using libpcap (option -M).
Definition: common.h:204
flow_settings::maximum_block_size
int maximum_block_size
Application buffer size in bytes (option -U).
Definition: common.h:201
flow_source_settings::late_connect
int late_connect
Definition: daemon.h:68
fg_pcap_go
void fg_pcap_go(struct flow *flow)
Start a tcpdump to capture traffic of the provided flow.
Definition: fg_pcap.c:314
flow::statistics::response_blocks_written
unsigned response_blocks_written
Definition: daemon.h:133
flow_settings::flow_id
int flow_id
Flow ID maintained by controller.
Definition: common.h:186
request
Definition: daemon.h:179
flow::error
char * error
Definition: daemon.h:170
flow::current_write_block_size
unsigned current_write_block_size
Definition: daemon.h:100
GRIND_WAIT_CONNECT
@ GRIND_WAIT_CONNECT
Definition: daemon.h:56
GRIND_WAIT_ACCEPT
@ GRIND_WAIT_ACCEPT
Definition: daemon.h:58
get_pmtu
int get_pmtu(int fd)
Definition: fg_socket.c:193
flow::endpoint
enum endpoint_t endpoint
Definition: daemon.h:78
request::error
char * error
Definition: daemon.h:187
MIN_BLOCK_SIZE
#define MIN_BLOCK_SIZE
Minium block (message) size we can send.
Definition: common.h:79
flow::listenfd_data
int listenfd_data
Definition: daemon.h:81
SOURCE
@ SOURCE
Endpoint that opens the connection.
Definition: common.h:98
flow::statistics::request_blocks_read
unsigned request_blocks_read
Definition: daemon.h:130
flow::addr_len
socklen_t addr_len
Definition: daemon.h:120
flow::fd
int fd
Definition: daemon.h:80
flow::finished
char finished[2]
Definition: daemon.h:112
flow_error
void flow_error(struct flow *flow, const char *fmt,...)
Definition: daemon.c:119
free_all
#define free_all(...)
To free() an arbitrary number of variables.
Definition: fg_definitions.h:59
flow::addr
struct sockaddr * addr
Definition: daemon.h:119
flow::write_block
char * write_block
Definition: daemon.h:98
free_math_functions
void free_math_functions(struct flow *flow)
Definition: fg_math.c:97
fg_list_push_back
int fg_list_push_back(struct linked_list *const list, void *const data)
Inserts a new element at the end of the list.
Definition: fg_list.c:167
flow::state
enum flow_state_t state
Definition: daemon.h:77
set_window_size_directed
int set_window_size_directed(int fd, int window, int direction)
Definition: fg_socket.c:78
flow::statistics::bytes_read
unsigned long long bytes_read
Definition: daemon.h:124
flow::statistics::request_blocks_written
unsigned request_blocks_written
Definition: daemon.h:131
flow::statistics::iat_max
double iat_max
Maximum interarrival time.
Definition: daemon.h:140
flow::statistics::rtt_min
double rtt_min
Minimum round-trip time.
Definition: daemon.h:150
flow::id
int id
Definition: daemon.h:75
do_connect
int do_connect(struct flow *flow)
Establishes a connection of a flow.
Definition: source.c:153
flows
struct linked_list flows
Definition: daemon.c:103
flow_source_settings::destination_port
int destination_port
Definition: daemon.h:66
uninit_flow
void uninit_flow(struct flow *flow)
Definition: daemon.c:165
flow::statistics::iat_sum
double iat_sum
Accumulated interarrival time.
Definition: daemon.h:142
flow::pcap_thread
pthread_t pcap_thread
Definition: daemon.h:161
flow_settings::requested_send_buffer_size
int requested_send_buffer_size
Request sender buffer in bytes (option -B).
Definition: common.h:196
flow::statistics
struct flow::statistics statistics[2]