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

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);
293  if (flow->requested_server_test_port &&
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);
305  if (flow->requested_server_test_port &&
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 }
const char * fg_nameinfo(const struct sockaddr *sa, socklen_t salen)
Definition: fg_socket.c:374
int requested_send_buffer_size
Request sender buffer in bytes (option -B).
Definition: common.h:196
void logging(int priority, const char *fmt,...)
Definition: fg_log.c:69
int set_flow_tcp_options(struct flow *flow)
Definition: daemon.c:1420
char connect_called
Definition: daemon.h:111
void fg_pcap_go(struct flow *flow)
Start a tcpdump to capture traffic of the provided flow.
Definition: fg_pcap.c:314
struct flow_settings settings
Definition: daemon.h:83
#define DEBUG_MSG(LVL, MSG,...)
Print debug message to standard error.
Definition: debug.h:49
Definition: daemon.h:60
int requested_read_buffer_size
Request receiver buffer, advertised window in bytes (option -W).
Definition: common.h:198
int listenfd_data
Definition: daemon.h:81
unsigned real_listen_receive_buffer_size
Definition: daemon.h:109
unsigned short requested_server_test_port
Definition: daemon.h:106
unsigned real_listen_send_buffer_size
Definition: daemon.h:108
enum flow_state_t state
Definition: daemon.h:77
int fd
Definition: daemon.h:80
int set_window_size_directed(int fd, int window, int direction)
Definition: fg_socket.c:78
void flow_error(struct flow *flow, const char *fmt,...)
Definition: daemon.c:115
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;
180  flow->write_block = calloc(1, flow->settings.maximum_block_size );
181  flow->read_block = calloc(1, flow->settings.maximum_block_size );
182  /* Controller flow ID is set in the daemon */
183  flow->id=flow->settings.flow_id;
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 =
204  flow->settings.bind_address[0]
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;
243  request->flow_id = flow->id;
244 
245  fg_list_push_back(&flows, flow);
246 
247  return;
248 }
int maximum_block_size
Application buffer size in bytes (option -U).
Definition: common.h:201
int requested_send_buffer_size
Request sender buffer in bytes (option -B).
Definition: common.h:196
void logging(int priority, const char *fmt,...)
Definition: fg_log.c:69
#define MAX_FLOWS_DAEMON
Maximal number of parallel flows supported by one daemon instance.
Definition: common.h:65
void init_flow(struct flow *flow, int is_source)
To initialize all flows to the default value.
Definition: daemon.c:892
struct flow_settings settings
Definition: daemon.h:83
#define DEBUG_MSG(LVL, MSG,...)
Print debug message to standard error.
Definition: debug.h:49
char * read_block
Definition: daemon.h:97
char * write_block
Definition: daemon.h:98
char * error
Definition: daemon.h:170
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
int requested_read_buffer_size
Request receiver buffer, advertised window in bytes (option -W).
Definition: common.h:198
int listenfd_data
Definition: daemon.h:81
unsigned real_listen_receive_buffer_size
Definition: daemon.h:109
unsigned real_listen_send_buffer_size
Definition: daemon.h:108
static int create_listen_socket(struct flow *flow, char *bind_addr, unsigned short *listen_port)
Definition: destination.c:78
int flow_id
Flow ID maintained by controller.
Definition: common.h:186
int set_window_size_directed(int fd, int window, int direction)
Definition: fg_socket.c:78
int byte_counting
Enumerate bytes in payload instead of sending zeros (option -E).
Definition: common.h:229
void request_error(struct request *request, const char *fmt,...)
Definition: daemon.c:128
void uninit_flow(struct flow *flow)
Definition: daemon.c:161
char bind_address[1000]
The interface address for the flow (used by daemon).
Definition: common.h:183
Definition: daemon.h:73
struct flow_settings settings
Definition: daemon.h:197
size_t fg_list_size(struct linked_list *const list)
Returns the number of elements in the list.
Definition: fg_list.c:211
int id
Definition: daemon.h:75
struct linked_list flows
Definition: daemon.c:99
void flow_error(struct flow *flow, const char *fmt,...)
Definition: daemon.c:115
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 }
int mtcp
Set TCP_MTCP (15) on test socket (option -O).
Definition: common.h:242
void logging(int priority, const char *fmt,...)
Definition: fg_log.c:69
int set_tcp_mtcp(int fd)
Definition: fg_socket.c:347
static unsigned port
Definition: flowgrindd.c:95
struct flow_settings settings
Definition: daemon.h:83
int get_port(int fd)
Definition: fg_socket.c:441
#define DEBUG_MSG(LVL, MSG,...)
Print debug message to standard error.
Definition: debug.h:49
char cc_alg[TCP_CA_NAME_MAX]
Set congestion control algorithm ALG on test socket (option -O).
Definition: common.h:236
int set_congestion_control(int fd, const char *cc_alg)
Definition: fg_socket.c:265
int fd
Definition: daemon.h:80
int set_non_blocking(int fd)
Definition: fg_socket.c:172
void flow_error(struct flow *flow, const char *fmt,...)
Definition: daemon.c:115
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.

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 892 of file daemon.c.

893 {
894  memset(flow, 0, sizeof(struct flow));
895 
896  /* flow id is given by controller */
897  flow->id = -1;
898  flow->endpoint = is_source ? SOURCE : DESTINATION;
899  flow->state = is_source ? GRIND_WAIT_CONNECT : GRIND_WAIT_ACCEPT;
900  flow->fd = -1;
901  flow->listenfd_data = -1;
902 
905 
906  flow->finished[READ] = flow->finished[WRITE] = 0;
907 
908  flow->addr = 0;
909 
910  foreach(int *i, INTERVAL, FINAL) {
911  flow->statistics[*i].bytes_read = 0;
912  flow->statistics[*i].bytes_written = 0;
913 
914  flow->statistics[*i].request_blocks_read = 0;
915  flow->statistics[*i].request_blocks_written = 0;
916  flow->statistics[*i].response_blocks_read = 0;
917  flow->statistics[*i].response_blocks_written = 0;
918 
919  flow->statistics[*i].rtt_min = FLT_MAX;
920  flow->statistics[*i].rtt_max = FLT_MIN;
921  flow->statistics[*i].rtt_sum = 0.0F;
922  flow->statistics[*i].iat_min = FLT_MAX;
923  flow->statistics[*i].iat_max = FLT_MIN;
924  flow->statistics[*i].iat_sum = 0.0F;
925  flow->statistics[*i].delay_min = FLT_MAX;
926  flow->statistics[*i].delay_max = FLT_MIN;
927  flow->statistics[*i].delay_sum = 0.0F;
928  }
929 
930  DEBUG_MSG(LOG_NOTICE, "called init flow %d", flow->id);
931 }
double delay_sum
Accumulated one-way delay.
Definition: daemon.h:148
unsigned request_blocks_read
Definition: daemon.h:130
unsigned current_read_block_size
Definition: daemon.h:101
unsigned request_blocks_written
Definition: daemon.h:131
enum endpoint_t endpoint
Definition: daemon.h:78
#define DEBUG_MSG(LVL, MSG,...)
Print debug message to standard error.
Definition: debug.h:49
Endpoint that accepts the connection.
Definition: common.h:100
double iat_min
Minimum interarrival time.
Definition: daemon.h:138
#define MIN_BLOCK_SIZE
Minium block (message) size we can send.
Definition: common.h:79
unsigned current_write_block_size
Definition: daemon.h:100
double iat_sum
Accumulated interarrival time.
Definition: daemon.h:142
Endpoint that opens the connection.
Definition: common.h:98
double rtt_min
Minimum round-trip time.
Definition: daemon.h:150
unsigned response_blocks_read
Definition: daemon.h:132
int listenfd_data
Definition: daemon.h:81
struct sockaddr * addr
Definition: daemon.h:119
double delay_max
Maximum one-way delay.
Definition: daemon.h:146
unsigned response_blocks_written
Definition: daemon.h:133
unsigned long long bytes_written
Definition: daemon.h:125
double iat_max
Maximum interarrival time.
Definition: daemon.h:140
Final report.
Definition: common.h:116
enum flow_state_t state
Definition: daemon.h:77
int fd
Definition: daemon.h:80
Read operation.
Definition: common.h:108
char finished[2]
Definition: daemon.h:112
Write operation.
Definition: common.h:106
double rtt_sum
Accumulated round-trip time.
Definition: daemon.h:154
double delay_min
Minimum one-way delay.
Definition: daemon.h:144
struct flow::statistics statistics[2]
int id
Definition: daemon.h:75
double rtt_max
Maximum round-trip time.
Definition: daemon.h:152
unsigned long long bytes_read
Definition: daemon.h:124
Intermediated interval report.
Definition: common.h:114
void remove_flow ( unsigned  i)
void uninit_flow ( struct flow flow)

Definition at line 161 of file daemon.c.

162 {
163  DEBUG_MSG(LOG_DEBUG,"uninit_flow() called for flow %d",flow->id);
164  if (flow->fd != -1)
165  close(flow->fd);
166  if (flow->listenfd_data != -1)
167  close(flow->listenfd_data);
168 #ifdef HAVE_LIBPCAP
169  int rc;
170  if (flow->settings.traffic_dump && flow->pcap_thread) {
171  rc = pthread_cancel(flow->pcap_thread);
172  if (rc)
173  logging(LOG_WARNING, "failed to cancel dump thread: %s",
174  strerror(rc));
175 
176  /* wait for the dump thread to react to the cancellation request */
177  rc = pthread_join(flow->pcap_thread, NULL);
178  if (rc)
179  logging(LOG_WARNING, "failed to join dump thread: %s",
180  strerror(rc));
181  }
182 #endif /* HAVE_LIBPCAP */
183  free_all(flow->read_block, flow->write_block, flow->addr, flow->error);
184  free_math_functions(flow);
185 }
void logging(int priority, const char *fmt,...)
Definition: fg_log.c:69
struct flow_settings settings
Definition: daemon.h:83
#define DEBUG_MSG(LVL, MSG,...)
Print debug message to standard error.
Definition: debug.h:49
char * read_block
Definition: daemon.h:97
char * write_block
Definition: daemon.h:98
char * error
Definition: daemon.h:170
#define free_all(...)
To free() an arbitrary number of variables.
int listenfd_data
Definition: daemon.h:81
struct sockaddr * addr
Definition: daemon.h:119
int fd
Definition: daemon.h:80
int traffic_dump
Dump traffic using libpcap (option -M).
Definition: common.h:204
pthread_t pcap_thread
Definition: daemon.h:161
void free_math_functions(struct flow *flow)
Definition: fg_math.c:97
int id
Definition: daemon.h:75