Flowgrind
Advanced TCP traffic generator
source.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 "debug.h"
57 #include "fg_error.h"
58 #include "fg_math.h"
59 #include "fg_socket.h"
60 #include "fg_time.h"
61 #include "fg_log.h"
62 
63 #ifdef HAVE_LIBPCAP
64 #include "fg_pcap.h"
65 #endif /* HAVE_LIBPCAP */
66 
67 void remove_flow(unsigned i);
68 
69 #ifdef HAVE_TCP_INFO
70 int get_tcp_info(struct flow *flow, struct tcp_info *info);
71 #endif /* HAVE_TCP_INFO */
72 
73 void init_flow(struct flow* flow, int is_source);
74 void uninit_flow(struct flow *flow);
75 
76 static int name2socket(struct flow *flow, char *server_name, unsigned port, struct sockaddr **saptr,
77  socklen_t *lenp,
78  const int read_buffer_size_req, int *read_buffer_size,
79  const int send_buffer_size_req, int *send_buffer_size)
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 }
144 
153 int do_connect(struct flow *flow) {
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 }
167 
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));
187  request_error(&request->r,
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 */
204  flow->write_block = calloc(1, flow->settings.maximum_block_size);
205  flow->read_block = calloc(1, flow->settings.maximum_block_size);
206  /* Controller flow ID is set in the daemon */
207  flow->id = flow->settings.flow_id;
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 
221  flow->state = GRIND_WAIT_CONNECT;
222  flow->fd = name2socket(flow, flow->source_settings.destination_host,
224  &flow->addr, &flow->addr_len,
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 */
256  if (!flow->source_settings.late_connect) {
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 
268  fg_list_push_back(&flows, flow);
269 
270  return 0;
271 }
int maximum_block_size
Application buffer size in bytes (option -U).
Definition: common.h:201
int pmtu
Definition: daemon.h:114
#define err(...)
To report an error w/ the corresponding system error message.
Definition: fg_error.h:43
Debugging routines for Flowgrind controller and daemon.
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
Routines for statistics and advanced traffic generation.
int do_connect(struct flow *flow)
Establishes a connection of a flow.
Definition: source.c:153
struct flow_source_settings source_settings
Definition: daemon.h:84
char destination_host[256]
Definition: daemon.h:65
void fg_pcap_go(struct flow *flow)
Start a tcpdump to capture traffic of the provided flow.
Definition: fg_pcap.c:314
static unsigned port
Definition: flowgrindd.c:95
void uninit_flow(struct flow *flow)
Definition: daemon.c:161
struct flow_settings settings
Definition: daemon.h:210
#define MAX_FLOWS_DAEMON
Maximal number of parallel flows supported by one daemon instance.
Definition: common.h:65
Error-reporting routines used by Flowgrind.
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
void remove_flow(unsigned i)
#define DEBUG_MSG(LVL, MSG,...)
Print debug message to standard error.
Definition: debug.h:49
char * read_block
Definition: daemon.h:97
int get_pmtu(int fd)
Definition: fg_socket.c:193
char * error
Definition: daemon.h:187
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
struct request r
Definition: daemon.h:208
struct sockaddr * addr
Definition: daemon.h:119
struct flow_source_settings source_settings
Definition: daemon.h:211
#define crit(...)
To report an critical error w/ the corresponding system error message.
Definition: fg_error.h:36
enum flow_state_t state
Definition: daemon.h:77
socklen_t addr_len
Definition: daemon.h:120
int fd
Definition: daemon.h:80
char cc_alg[TCP_CA_NAME_MAX]
Definition: daemon.h:215
int add_flow_source(struct request_add_flow_source *request)
To set daemon flow as source endpoint.
Definition: source.c:177
Routines used to manipulate socket parameters for Flowgrind.
int get_tcp_info(struct flow *flow, struct tcp_info *info)
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
Packet capture support for the Flowgrind daemon.
Definition: daemon.h:73
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
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
struct linked_list flows
Definition: daemon.c:99
Timing related routines used by Flowgrind.
void flow_error(struct flow *flow, const char *fmt,...)
Definition: daemon.c:115