send_packets.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. /* $Id: send_packets.c 1556 2006-07-31 06:12:01Z aturner $ */
  2. /*
  3. * Copyright (c) 2001-2004 Aaron Turner.
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. *
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * 2. Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. * 3. Neither the names of the copyright owners nor the names of its
  16. * contributors may be used to endorse or promote products derived from
  17. * this software without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
  20. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  21. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  22. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  23. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  24. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  25. * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  26. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
  27. * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  28. * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  29. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. */
  31. #include "config.h"
  32. #include "defines.h"
  33. #include "common.h"
  34. #include <sys/time.h>
  35. #include <sys/types.h>
  36. #include <signal.h>
  37. #include <string.h>
  38. #include <netinet/in.h>
  39. #include <errno.h>
  40. #include <stdlib.h>
  41. #include <unistd.h>
  42. #include "tcpreplay.h"
  43. #ifdef TCPREPLAY
  44. #include "tcpreplay_opts.h"
  45. #endif
  46. #include "send_packets.h"
  47. extern tcpreplay_opt_t options;
  48. extern struct timeval begin, end;
  49. extern COUNTER bytes_sent, failed, pkts_sent;
  50. extern volatile int didsig;
  51. #ifdef HAVE_TCPDUMP
  52. extern tcpdump_t tcpdump;
  53. #endif
  54. #ifdef DEBUG
  55. extern int debug;
  56. #endif
  57. static void do_sleep(struct timeval *time, struct timeval *last, int len, int accurate, sendpacket_t *sp);
  58. static u_int32_t sleep_loop(struct timeval time);
  59. /*
  60. * the main loop function. This is where we figure out
  61. * what to do with each packet
  62. */
  63. void
  64. send_packets(pcap_t *pcap)
  65. {
  66. struct timeval last = { 0, 0 };
  67. COUNTER packetnum = 0;
  68. struct pcap_pkthdr pkthdr;
  69. const u_char *pktdata = NULL;
  70. sendpacket_t *sp = options.intf1;
  71. u_int32_t pktlen;
  72. /* register signals */
  73. didsig = 0;
  74. if (!options.speed.mode == SPEED_ONEATATIME) {
  75. (void)signal(SIGINT, catcher);
  76. }
  77. else {
  78. (void)signal(SIGINT, break_now);
  79. }
  80. /* MAIN LOOP
  81. * Keep sending while we have packets or until
  82. * we've sent enough packets
  83. */
  84. while ((pktdata = pcap_next(pcap, &pkthdr)) != NULL) {
  85. /* die? */
  86. if (didsig)
  87. break_now(0);
  88. packetnum++;
  89. #ifdef TCPREPLAY
  90. /* do we use the snaplen (caplen) or the "actual" packet len? */
  91. pktlen = HAVE_OPT(PKTLEN) ? pkthdr.len : pkthdr.caplen;
  92. #elif TCPBRIDGE
  93. pktlen = pkthdr.caplen;
  94. #else
  95. #error WTF??? We should not be here!
  96. #endif
  97. dbgx(2, "packet " COUNTER_SPEC " caplen %d", packetnum, pktlen);
  98. /* Dual nic processing */
  99. if (options.intf2 != NULL) {
  100. sp = (sendpacket_t *) cache_mode(options.cachedata, packetnum);
  101. /* sometimes we should not send the packet */
  102. if (sp == CACHE_NOSEND)
  103. continue;
  104. }
  105. /* do we need to print the packet via tcpdump? */
  106. #ifdef HAVE_TCPDUMP
  107. if (options.verbose)
  108. tcpdump_print(&tcpdump, &pkthdr, pktdata);
  109. #endif
  110. /*
  111. * we have to cast the ts, since OpenBSD sucks
  112. * had to be special and use bpf_timeval
  113. */
  114. do_sleep((struct timeval *)&pkthdr.ts, &last, pktlen, options.accurate, sp);
  115. /* write packet out on network */
  116. if (sendpacket(sp, pktdata, pktlen) < (int)pktlen)
  117. errx(1, "Unable to send packet: %s", sendpacket_geterr(sp));
  118. /*
  119. * track the time of the "last packet sent". Again, because of OpenBSD
  120. * we have to do a mempcy rather then assignment
  121. */
  122. memcpy(&last, &pkthdr.ts, sizeof(struct timeval));
  123. } /* while */
  124. }
  125. /*
  126. * determines based upon the cachedata which interface the given packet
  127. * should go out. Also rewrites any layer 2 data we might need to adjust.
  128. * Returns a void cased pointer to the options.intfX of the corresponding
  129. * interface.
  130. */
  131. void *
  132. cache_mode(char *cachedata, COUNTER packet_num)
  133. {
  134. void *sp = NULL;
  135. int result;
  136. if (packet_num > options.cache_packets)
  137. err(1, "Exceeded number of packets in cache file.");
  138. result = check_cache(cachedata, packet_num);
  139. if (result == CACHE_NOSEND) {
  140. dbgx(2, "Cache: Not sending packet " COUNTER_SPEC ".", packet_num);
  141. return CACHE_NOSEND;
  142. }
  143. else if (result == CACHE_PRIMARY) {
  144. dbgx(2, "Cache: Sending packet " COUNTER_SPEC " out primary interface.", packet_num);
  145. sp = options.intf1;
  146. }
  147. else if (result == CACHE_SECONDARY) {
  148. dbgx(2, "Cache: Sending packet " COUNTER_SPEC " out secondary interface.", packet_num);
  149. sp = options.intf2;
  150. }
  151. else {
  152. err(1, "check_cache() returned an error. Aborting...");
  153. }
  154. return sp;
  155. }
  156. /*
  157. * Given the timestamp on the current packet and the last packet sent,
  158. * calculate the appropriate amount of time to sleep and do so.
  159. */
  160. static void
  161. do_sleep(struct timeval *time, struct timeval *last, int len, int accurate, sendpacket_t *sp)
  162. {
  163. static struct timeval didsleep = { 0, 0 };
  164. static struct timeval start = { 0, 0 };
  165. struct timeval nap, now, delta;
  166. struct timespec ignore, sleep;
  167. float n;
  168. struct pollfd poller[1]; /* use poll to read from the keyboard */
  169. char input[EBUF_SIZE];
  170. static u_int32_t send = 0; /* remember # of packets to send btw calls */
  171. u_int32_t loop;
  172. /* just return if topspeed */
  173. if (options.speed.mode == SPEED_TOPSPEED)
  174. return;
  175. dbgx(3, "Last time: " TIMEVAL_FORMAT, last->tv_sec, last->tv_usec);
  176. if (gettimeofday(&now, NULL) < 0) {
  177. errx(1, "Error gettimeofday: %s", strerror(errno));
  178. }
  179. dbgx(3, "Now time: " TIMEVAL_FORMAT, now.tv_sec, now.tv_usec);
  180. /* First time through for this file */
  181. if (!timerisset(last)) {
  182. start = now;
  183. timerclear(&delta);
  184. timerclear(&didsleep);
  185. }
  186. else {
  187. timersub(&now, &start, &delta);
  188. }
  189. switch(options.speed.mode) {
  190. case SPEED_MULTIPLIER:
  191. /*
  192. * Replay packets a factor of the time they were originally sent.
  193. */
  194. if (timerisset(last) && timercmp(time, last, >)) {
  195. timersub(time, last, &nap);
  196. timerdiv(&nap, options.speed.speed);
  197. }
  198. else {
  199. /*
  200. * Don't sleep if this is our first packet, or if the
  201. * this packet appears to have been sent before the
  202. * last packet.
  203. */
  204. timerclear(&nap);
  205. }
  206. break;
  207. case SPEED_MBPSRATE:
  208. /*
  209. * Ignore the time supplied by the capture file and send data at
  210. * a constant 'rate' (bytes per second).
  211. */
  212. if (timerisset(last)) {
  213. n = (float)len / (options.speed.speed * 1024 * 1024 / 8); /* convert Mbps to bps */
  214. nap.tv_sec = n;
  215. nap.tv_usec = (n - nap.tv_sec) * 1000000;
  216. dbgx(3, "packet size %d\t\tequals %f bps\t\tnap " TIMEVAL_FORMAT, len, n,
  217. nap.tv_sec, nap.tv_usec);
  218. }
  219. else {
  220. timerclear(&nap);
  221. }
  222. break;
  223. case SPEED_PACKETRATE:
  224. /* run in packets/sec */
  225. n = 1 / options.speed.speed;
  226. nap.tv_sec = n;
  227. n -= nap.tv_sec;
  228. nap.tv_usec = n * 1000000;
  229. break;
  230. case SPEED_ONEATATIME:
  231. /* do we skip prompting for a key press? */
  232. if (send == 0) {
  233. printf("**** How many packets do you wish to send? (next packet out %s): ",
  234. sp == options.intf1 ? options.intf1_name : options.intf2_name);
  235. fflush(NULL);
  236. poller[0].fd = STDIN_FILENO;
  237. poller[0].events = POLLIN;
  238. poller[0].revents = 0;
  239. /* wait for the input */
  240. if (poll(poller, 1, -1) < 0)
  241. errx(1, "Error reading from stdin: %s", strerror(errno));
  242. /*
  243. * read to the end of the line or EBUF_SIZE,
  244. * Note, if people are stupid, and type in more text then EBUF_SIZE
  245. * then the next fgets() will pull in that data, which will have poor
  246. * results. fuck them.
  247. */
  248. fgets(input, sizeof(input), stdin);
  249. if (strlen(input) > 1) {
  250. send = strtoul(input, NULL, 0);
  251. }
  252. /* how many packets should we send? */
  253. if (send == 0) {
  254. dbg(1, "Input was less then 1 or non-numeric, assuming 1");
  255. /* assume send only one packet */
  256. send = 1;
  257. }
  258. }
  259. /* decrement our send counter */
  260. printf("Sending packet out: %s\n",
  261. sp == options.intf1 ? options.intf1_name : options.intf2_name);
  262. send --;
  263. /* leave do_sleep() */
  264. return;
  265. break;
  266. default:
  267. errx(1, "Unknown/supported speed mode: %d", options.speed.mode);
  268. break;
  269. }
  270. if (!accurate) {
  271. timeradd(&didsleep, &nap, &didsleep);
  272. dbgx(4, "I will sleep " TIMEVAL_FORMAT, nap.tv_sec, nap.tv_usec);
  273. if (timercmp(&didsleep, &delta, >)) {
  274. timersub(&didsleep, &delta, &nap);
  275. sleep.tv_sec = nap.tv_sec;
  276. sleep.tv_nsec = nap.tv_usec * 1000; /* convert ms to ns */
  277. if (nanosleep(&sleep, &ignore) == -1) {
  278. warnx("nanosleep error: %s", strerror(errno));
  279. }
  280. }
  281. } else {
  282. timeradd(&now, &nap, &delta);
  283. loop = sleep_loop(delta);
  284. dbgx(3, "sleep_loop looped %u times", loop);
  285. }
  286. }
  287. /*
  288. * this function will keep calling gettimeofday() until it returns
  289. * >= time. This should be a lot more accurate then using nanosleep(),
  290. * but at the cost of being more CPU intensive.
  291. */
  292. static u_int32_t
  293. sleep_loop(struct timeval time)
  294. {
  295. struct timeval now;
  296. u_int32_t loop = 0;
  297. do {
  298. gettimeofday(&now, NULL);
  299. loop ++;
  300. } while (now.tv_sec < time.tv_sec || now.tv_usec < time.tv_usec);
  301. return loop;
  302. }
  303. /*
  304. Local Variables:
  305. mode:c
  306. indent-tabs-mode:nil
  307. c-basic-offset:4
  308. End:
  309. */