Flowgrind
Advanced TCP traffic generator
destination.c
Go to the documentation of this file.
1 
6 /*
7  * Copyright (C) 2010-2013 Christian Samsel <christian.samsel@rwth-aachen.de>
8  * Copyright (C) 2009 Tim Kosse <tim.kosse@gmx.de>
9  * Copyright (C) 2007-2008 Daniel Schaffrath <daniel.schaffrath@mac.com>
10  *
11  * This file is part of Flowgrind.
12  *
13  * Flowgrind is free software: you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation, either version 3 of the License, or
16  * (at your option) any later version.
17  *
18  * Flowgrind is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with Flowgrind. If not, see <http://www.gnu.org/licenses/>.
25  *
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif /* HAVE_CONFIG_H */
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <stdarg.h>
35 #include <strings.h>
36 #include <signal.h>
37 #include <string.h>
38 #include <fcntl.h>
39 #include <math.h>
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <sys/param.h>
43 #include <sys/select.h>
44 #include <netinet/in.h>
45 #include <arpa/inet.h>
46 #include <unistd.h>
47 #include <sys/wait.h>
48 #include <errno.h>
49 #include <time.h>
50 #include <syslog.h>
51 #include <sys/time.h>
52 #include <netdb.h>
53 #include <pthread.h>
54 #include <float.h>
55 
56 #include "common.h"
57 #include "debug.h"
58 #include "fg_socket.h"
59 #include "fg_time.h"
60 #include "fg_math.h"
61 #include "fg_log.h"
62 #include "daemon.h"
63 
64 #ifdef HAVE_LIBPCAP
65 #include "fg_pcap.h"
66 #endif /* HAVE_LIBPCAP */
67 
68 void remove_flow(unsigned i);
69 
70 #ifdef HAVE_TCP_INFO
71 int get_tcp_info(struct flow *flow, struct tcp_info *info);
72 #endif /* HAVE_TCP_INFO */
73 
74 void init_flow(struct flow* flow, int is_source);
75 void uninit_flow(struct flow *flow);
76 
77 /* listen_port will receive the port of the created socket */
78 static int create_listen_socket(struct flow *flow, char *bind_addr,
79  unsigned short *listen_port)
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 }
149 
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 }
249 
250 int accept_data(struct flow *flow)
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 }
get_tcp_info
int get_tcp_info(struct flow *flow, struct tcp_info *info)
DEBUG_MSG
#define DEBUG_MSG(LVL, MSG,...)
Print debug message to standard error.
Definition: debug.h:49
fg_pcap.h
Packet capture support for the Flowgrind daemon.
fg_log.h
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
accept_data
int accept_data(struct flow *flow)
Definition: destination.c:250
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
set_non_blocking
int set_non_blocking(int fd)
Definition: fg_socket.c:172
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::settings
struct flow_settings settings
Definition: daemon.h:83
remove_flow
void remove_flow(unsigned i)
flow::read_block
char * read_block
Definition: daemon.h:97
request_add_flow_destination
Definition: daemon.h:193
init_flow
void init_flow(struct flow *flow, int is_source)
To initialize all flows to the default value.
Definition: daemon.c:896
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_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
fg_socket.h
Routines used to manipulate socket parameters for Flowgrind.
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
fg_time.h
Timing related routines used by Flowgrind.
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_error
void flow_error(struct flow *flow, const char *fmt,...)
Definition: daemon.c:119
flow::write_block
char * write_block
Definition: daemon.h:98
common.h
Data structures used by the Flowgrind daemon and controller.
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::requested_server_test_port
unsigned short requested_server_test_port
Definition: daemon.h:106
add_flow_destination
void add_flow_destination(struct request_add_flow_destination *request)
To set daemon flow as destination endpoint.
Definition: destination.c:158
config.h
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
fg_math.h
Routines for statistics and advanced traffic generation.
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
debug.h
Debugging routines for Flowgrind controller and daemon.
daemon.h
Routines used by the Flowgrind daemon.
flow_settings::requested_send_buffer_size
int requested_send_buffer_size
Request sender buffer in bytes (option -B).
Definition: common.h:196