Flowgrind
Advanced TCP traffic generator
destination.c File Reference

Routines used to setup a Flowgrind destination for a test. 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 "common.h"
#include "debug.h"
#include "fg_socket.h"
#include "fg_time.h"
#include "fg_math.h"
#include "fg_log.h"
#include "daemon.h"
#include "fg_pcap.h"

Go to the source code of this file.

Functions

int accept_data (struct flow *flow)
 
void add_flow_destination (struct request_add_flow_destination *request)
 To set daemon flow as destination endpoint. More...
 
static int create_listen_socket (struct flow *flow, char *bind_addr, unsigned short *listen_port)
 
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...
 
void remove_flow (unsigned i)
 
void uninit_flow (struct flow *flow)
 

Detailed Description

Routines used to setup a Flowgrind destination for a test.

Definition in file destination.c.

Function Documentation

◆ accept_data()

int accept_data ( struct flow flow)
Bug:
: currently we use portable select() API, which is limited by the number of bits in an fd_set

Definition at line 250 of file destination.c.

251 {
252  struct sockaddr_storage caddr;
253  socklen_t addrlen = sizeof(caddr);
254  unsigned real_send_buffer_size;
255  unsigned real_receive_buffer_size;
256 
257  flow->fd = accept(flow->listenfd_data, (struct sockaddr *)&caddr,
258  &addrlen);
259  if (flow->fd == -1) {
260  /* try again later .... */
261  if (errno == EINTR || errno == EAGAIN)
262  return 0;
263  logging(LOG_ALERT, "accept() failed: %s", strerror(errno));
264  return -1;
265  }
266 
267  /* FIXME: currently we use portable select() API, which
268  * is limited by the number of bits in an fd_set */
269  if (flow->fd >= FD_SETSIZE) {
270  logging(LOG_ALERT, "too many file descriptors are "
271  "already in use by this daemon (FD number=%u)", flow->fd);
272  flow_error(flow, "failed to add test connection: too many"
273  "file descriptors in use by this daemon");
274  close(flow->fd);
275  return -1;
276  }
277 
278  if (close(flow->listenfd_data) == -1)
279  logging(LOG_WARNING, "close() failed");
280  flow->listenfd_data = -1;
281 
282  logging(LOG_NOTICE, "client %s connected for testing (fd=%u)",
283  fg_nameinfo((struct sockaddr *)&caddr, addrlen), flow->fd);
284 
285 #ifdef HAVE_LIBPCAP
286  fg_pcap_go(flow);
287 #endif /* HAVE_LIBPCAP */
288 
289  real_send_buffer_size =
292  SO_SNDBUF);
294  flow->real_listen_send_buffer_size != real_send_buffer_size) {
295  logging(LOG_WARNING, "failed to set send buffer size of test "
296  "socket to send buffer size size of listen socket "
297  "(listen = %u, test = %u)",
298  flow->real_listen_send_buffer_size, real_send_buffer_size);
299  return -1;
300  }
301  real_receive_buffer_size =
304  SO_RCVBUF);
306  flow->real_listen_receive_buffer_size != real_receive_buffer_size) {
307  logging(LOG_WARNING, "failed to set receive buffer size "
308  "(advertised window) of test socket to receive "
309  "buffer size of listen socket (listen = %u, "
310  "test = %u)", flow->real_listen_receive_buffer_size,
311  real_receive_buffer_size);
312  return -1;
313  }
314  if (set_flow_tcp_options(flow) == -1)
315  return -1;
316  DEBUG_MSG(LOG_NOTICE, "data socket accepted");
317  flow->state = GRIND;
318  flow->connect_called = 1;
319 
320  return 0;
321 }

◆ add_flow_destination()

void add_flow_destination ( struct request_add_flow_destination request)

To set daemon flow as destination endpoint.

To set the flow options and settings as destination endpoint. Listening port created and send back to the controller in the same request structure

Parameters
[in,out]requestcontain the test option and parameter for destination source endpoint
Bug:
: currently we use portable select() API, which is limited by the number of bits in an fd_set

Definition at line 158 of file destination.c.

159 {
160  struct flow *flow;
161  unsigned short server_data_port;
162 
164  logging(LOG_WARNING, "can not accept another flow, already "
165  "handling %zu flows", fg_list_size(&flows));
166  request_error(&request->r, "Can not accept another flow, "
167  "already handling %zu flows.", fg_list_size(&flows));
168  return;
169  }
170 
171  flow = malloc(sizeof(struct flow));
172  if (!flow) {
173  logging(LOG_ALERT, "could not allocate memory for flow");
174  return;
175  }
176 
177  init_flow(flow, 0);
178 
179  flow->settings = request->settings;
182  /* Controller flow ID is set in the daemon */
184  if (flow->write_block == NULL || flow->read_block == NULL) {
185  logging(LOG_ALERT, "could not allocate memory for read/write "
186  "blocks");
187  request_error(&request->r, "could not allocate memory "
188  "for read/write blocks");
189  uninit_flow(flow);
190  return;
191  }
192 
193  if (flow->settings.byte_counting) {
194  int byte_idx;
195  for (byte_idx = 0; byte_idx < flow->settings.maximum_block_size;
196  byte_idx++)
197  *(flow->write_block + byte_idx) =
198  (unsigned char)(byte_idx & 0xff);
199  }
200 
201  /* Create listen socket for data connection */
202  if ((flow->listenfd_data =
205  ? flow->settings.bind_address : 0,
206  &server_data_port)) == -1) {
207  logging(LOG_ALERT, "could not create listen socket for "
208  "data connection: %s", flow->error);
209  request_error(&request->r, "could not create listen socket "
210  "for data connection: %s", flow->error);
211  uninit_flow(flow);
212  return;
213  } else {
214  /* FIXME: currently we use portable select() API, which
215  * is limited by the number of bits in an fd_set */
216  if (flow->listenfd_data >= FD_SETSIZE) {
217  logging(LOG_ALERT, "failed to add listen socket: "
218  "fd number too high (fd=%u)", flow->listenfd_data);
219  flow_error(flow, "failed to add listen socket: too many"
220  "file descriptors in use by this daemon");
221  uninit_flow(flow);
222  return;
223  }
224  DEBUG_MSG(LOG_WARNING, "listening on %s port %u for data "
225  "connection (fd=%u)", flow->settings.bind_address,
226  server_data_port, flow->listenfd_data);
227  }
228 
232  SO_SNDBUF);
236  SO_RCVBUF);
237 
238  request->listen_data_port = (int)server_data_port;
239  request->real_listen_send_buffer_size =
241  request->real_listen_read_buffer_size =
243  request->flow_id = flow->id;
244 
246 
247  return;
248 }

◆ create_listen_socket()

static int create_listen_socket ( struct flow flow,
char *  bind_addr,
unsigned short *  listen_port 
)
static

Definition at line 78 of file destination.c.

80 {
81  int port;
82  int rc;
83  int fd;
84  struct addrinfo hints, *res, *ressave;
85 
86  bzero(&hints, sizeof(struct addrinfo));
87  hints.ai_flags = bind_addr ? 0 : AI_PASSIVE;
88  hints.ai_family = AF_UNSPEC;
89  hints.ai_socktype = SOCK_STREAM;
90 
91  /* Any port will be fine */
92  if ((rc = getaddrinfo(bind_addr, "0", &hints, &res)) != 0) {
93  logging(LOG_ALERT, "getaddrinfo() failed: %s",
94  gai_strerror(rc));
95  flow_error(flow, "getaddrinfo() failed: %s",
96  gai_strerror(rc));
97  return -1;
98  }
99 
100  ressave = res;
101 
102  do {
103  fd = socket(res->ai_family, res->ai_socktype,
104  res->ai_protocol);
105  if (fd < 0)
106  continue;
107  if (bind(fd, res->ai_addr, res->ai_addrlen) == 0)
108  break;
109  close(fd);
110  } while ((res = res->ai_next) != NULL);
111 
112  if (res == NULL) {
113  logging(LOG_ALERT, "failed to create listen socket: %s",
114  strerror(errno));
115  flow_error(flow, "failed to create listen socket: %s",
116  strerror(errno));
117  freeaddrinfo(ressave);
118  return -1;
119  }
120 
121  freeaddrinfo(ressave);
122 
123  /* we need to set sockopt mtcp before we start listen() */
124  if (flow->settings.mtcp)
125  set_tcp_mtcp(fd);
126 
127  if (flow->settings.cc_alg)
129 
130  if (listen(fd, 0) < 0) {
131  logging(LOG_ALERT, "listen failed: %s", strerror(errno));
132  flow_error(flow, "listen failed: %s", strerror(errno));
133  return -1;
134  }
135 
136  set_non_blocking(fd);
137 
138  port = get_port(fd);
139  if (port < 0) {
140  flow_error(flow, "Could not get port: %s", strerror(errno));
141  close(fd);
142  return -1;
143  }
144  DEBUG_MSG(LOG_DEBUG, "listening on port %d", port);
145  *listen_port = (unsigned short)port;
146 
147  return fd;
148 }

◆ 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 }

◆ 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
flow_settings::requested_read_buffer_size
int requested_read_buffer_size
Request receiver buffer, advertised window in bytes (option -W).
Definition: common.h:198
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
set_non_blocking
int set_non_blocking(int fd)
Definition: fg_socket.c:172
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
GRIND
@ GRIND
Definition: daemon.h:60
flow_settings::byte_counting
int byte_counting
Enumerate bytes in payload instead of sending zeros (option -E).
Definition: common.h:229
flow_settings::cc_alg
char cc_alg[TCP_CA_NAME_MAX]
Set congestion control algorithm ALG on test socket (option -O).
Definition: common.h:236
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
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
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
flow::endpoint
enum endpoint_t endpoint
Definition: daemon.h:78
MIN_BLOCK_SIZE
#define MIN_BLOCK_SIZE
Minium block (message) size we can send.
Definition: common.h:79
get_port
int get_port(int fd)
Definition: fg_socket.c:441
flow::listenfd_data
int listenfd_data
Definition: daemon.h:81
flow::real_listen_receive_buffer_size
unsigned real_listen_receive_buffer_size
Definition: daemon.h:109
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::fd
int fd
Definition: daemon.h:80
flow::real_listen_send_buffer_size
unsigned real_listen_send_buffer_size
Definition: daemon.h:108
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::requested_server_test_port
unsigned short requested_server_test_port
Definition: daemon.h:106
flow::id
int id
Definition: daemon.h:75
fg_nameinfo
const char * fg_nameinfo(const struct sockaddr *sa, socklen_t salen)
Definition: fg_socket.c:374
flows
struct linked_list flows
Definition: daemon.c:103
uninit_flow
void uninit_flow(struct flow *flow)
Definition: daemon.c:165
flow_settings::mtcp
int mtcp
Set TCP_MTCP (15) on test socket (option -O).
Definition: common.h:242
set_congestion_control
int set_congestion_control(int fd, const char *cc_alg)
Definition: fg_socket.c:265
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::bind_address
char bind_address[1000]
The interface address for the flow (used by daemon).
Definition: common.h:183
create_listen_socket
static int create_listen_socket(struct flow *flow, char *bind_addr, unsigned short *listen_port)
Definition: destination.c:78
set_tcp_mtcp
int set_tcp_mtcp(int fd)
Definition: fg_socket.c:347
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]