Tools for multicast testing (msend and mreceive) https://github.com/troglobit/mtools
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

msend.c 8.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. /*
  2. * msend.c -- Sends UDP packets to a multicast group
  3. *
  4. * (c) Jianping Wang, Yvan Pointurier, Jorg Liebeherr, 2002
  5. * Multimedia Networks Group, University of Virginia
  6. *
  7. * SOURCE CODE RELEASED TO THE PUBLIC DOMAIN
  8. *
  9. * version 2.0 - 5/20/2002
  10. * version 2.1 - 12/4/2002
  11. * By default, msend does not join multicast group. If -join option is
  12. * given, msend joins the multicast group.
  13. * version 2.2 - 05/17/2003
  14. * Most commandline parameters are assigned default values. The
  15. * usage information is changed according to README_msend.txt
  16. *
  17. *
  18. * Based on this public domain program:
  19. * u_mctest.c (c) Bob Quinn 2/4/97
  20. *
  21. */
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <sys/types.h>
  26. #include <sys/socket.h>
  27. #include <netinet/in.h>
  28. #include <arpa/inet.h>
  29. #include <signal.h>
  30. #include <sys/time.h>
  31. #define TRUE 1
  32. #define FALSE 0
  33. #ifndef INVALID_SOCKET
  34. #define INVALID_SOCKET -1
  35. #endif
  36. #ifndef SOCKET_ERROR
  37. #define SOCKET_ERROR -1
  38. #endif
  39. #define LOOPMAX 20
  40. #define BUFSIZE 1024
  41. char *TEST_ADDR = "224.1.1.1";
  42. int TEST_PORT = 4444;
  43. int TTL_VALUE = 1;
  44. int SLEEP_TIME = 1000;
  45. unsigned long IP = INADDR_ANY;
  46. int NUM = 0;
  47. int join_flag = 0; /* not join */
  48. typedef struct timerhandler_s {
  49. int s;
  50. char *achOut;
  51. int len;
  52. int n;
  53. struct sockaddr *stTo;
  54. int addr_size;
  55. } timerhandler_t;
  56. timerhandler_t handler_par;
  57. void timerhandler();
  58. void printHelp(void)
  59. {
  60. printf("msend version %s\n\
  61. Usage: msend [-g GROUP] [-p PORT] [-join] [-i ADDRESS] [-t TTL] [-P PERIOD]\n\
  62. [-text \"text\"|-n]\n\
  63. msend [-v | -h]\n\
  64. \n\
  65. -g GROUP IP multicast group address to send to. Default: 224.1.1.1\n\
  66. -p PORT UDP port number used in the multicast packets. Default: 4444\n\
  67. -i ADDRESS IP address of the interface to use to send the packets.\n\
  68. The default is to use the system default interface.\n\
  69. -join Multicast sender will join the multicast group.\n\
  70. By default a sender never joins the group.\n\
  71. -P PERIOD Interval in milliseconds between packets. Default 1000 msec\n\
  72. -t TTL The TTL value (1-255) used in the packets. You must set\n\
  73. this higher if you want to route the traffic, otherwise\n\
  74. the first router will drop the packets! Default: 1\n\
  75. -text \"text\" Specify a string to use as payload in the packets, also\n\
  76. displayed by the mreceive command. Default: empty\n\
  77. -n Encode -text argument as a number instead of a string.\n\
  78. -v Print version information.\n\
  79. -h Print the command usage.\n\n", VERSION);
  80. }
  81. int main(int argc, char *argv[])
  82. {
  83. struct sockaddr_in stLocal, stTo;
  84. char achOut[BUFSIZE] = "";
  85. int s, i;
  86. struct ip_mreq stMreq;
  87. int iTmp, iRet;
  88. int ii = 1;
  89. int addr_size = sizeof(struct sockaddr_in);
  90. struct itimerval times;
  91. sigset_t sigset;
  92. struct sigaction act;
  93. if ((argc == 2) && (strcmp(argv[ii], "-v") == 0)) {
  94. printf("msend version 2.2\n");
  95. return 0;
  96. }
  97. if ((argc == 2) && (strcmp(argv[ii], "-h") == 0)) {
  98. printHelp();
  99. return 0;
  100. }
  101. while (ii < argc) {
  102. if (strcmp(argv[ii], "-g") == 0) {
  103. ii++;
  104. if ((ii < argc) && !(strchr(argv[ii], '-'))) {
  105. TEST_ADDR = argv[ii];
  106. ii++;
  107. }
  108. } else if (strcmp(argv[ii], "-p") == 0) {
  109. ii++;
  110. if ((ii < argc) && !(strchr(argv[ii], '-'))) {
  111. TEST_PORT = atoi(argv[ii]);
  112. ii++;
  113. }
  114. } else if (strcmp(argv[ii], "-join") == 0) {
  115. join_flag++;;
  116. ii++;
  117. } else if (strcmp(argv[ii], "-i") == 0) {
  118. ii++;
  119. if ((ii < argc) && !(strchr(argv[ii], '-'))) {
  120. IP = inet_addr(argv[ii]);
  121. ii++;
  122. }
  123. } else if (strcmp(argv[ii], "-t") == 0) {
  124. ii++;
  125. if ((ii < argc) && !(strchr(argv[ii], '-'))) {
  126. TTL_VALUE = atoi(argv[ii]);
  127. ii++;
  128. }
  129. } else if (strcmp(argv[ii], "-P") == 0) {
  130. ii++;
  131. if ((ii < argc) && !(strchr(argv[ii], '-'))) {
  132. SLEEP_TIME = atoi(argv[ii]);
  133. ii++;
  134. }
  135. } else if (strcmp(argv[ii], "-n") == 0) {
  136. ii++;
  137. NUM = 1;
  138. ii++;
  139. } else if (strcmp(argv[ii], "-text") == 0) {
  140. ii++;
  141. if ((ii < argc) && !(strchr(argv[ii], '-'))) {
  142. strcpy(achOut, argv[ii]);
  143. ii++;
  144. }
  145. } else {
  146. printf("wrong parameters!\n\n");
  147. printHelp();
  148. return 1;
  149. }
  150. }
  151. /* get a datagram socket */
  152. s = socket(AF_INET, SOCK_DGRAM, 0);
  153. if (s == INVALID_SOCKET) {
  154. printf("socket() failed.\n");
  155. exit(1);
  156. }
  157. /* avoid EADDRINUSE error on bind() */
  158. iTmp = TRUE;
  159. iRet = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&iTmp, sizeof(iTmp));
  160. if (iRet == SOCKET_ERROR) {
  161. printf("setsockopt() SO_REUSEADDR failed.\n");
  162. exit(1);
  163. }
  164. /* name the socket */
  165. stLocal.sin_family = AF_INET;
  166. stLocal.sin_addr.s_addr = IP;
  167. stLocal.sin_port = htons(TEST_PORT);
  168. iRet = bind(s, (struct sockaddr *)&stLocal, sizeof(stLocal));
  169. if (iRet == SOCKET_ERROR) {
  170. printf("bind() failed.\n");
  171. exit(1);
  172. }
  173. /* join the multicast group. */
  174. stMreq.imr_multiaddr.s_addr = inet_addr(TEST_ADDR);
  175. stMreq.imr_interface.s_addr = IP;
  176. if (join_flag == 1) {
  177. iRet = setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&stMreq, sizeof(stMreq));
  178. if (iRet == SOCKET_ERROR) {
  179. printf("setsockopt() IP_ADD_MEMBERSHIP failed.\n");
  180. exit(1);
  181. }
  182. }
  183. /* set TTL to traverse up to multiple routers */
  184. iTmp = TTL_VALUE;
  185. iRet = setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, (char *)&iTmp, sizeof(iTmp));
  186. if (iRet == SOCKET_ERROR) {
  187. printf("setsockopt() IP_MULTICAST_TTL failed.\n");
  188. exit(1);
  189. }
  190. /* enable loopback */
  191. iTmp = TRUE;
  192. iRet = setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&iTmp, sizeof(iTmp));
  193. if (iRet == SOCKET_ERROR) {
  194. printf("setsockopt() IP_MULTICAST_LOOP failed.\n");
  195. exit(1);
  196. }
  197. /* assign our destination address */
  198. stTo.sin_family = AF_INET;
  199. stTo.sin_addr.s_addr = inet_addr(TEST_ADDR);
  200. stTo.sin_port = htons(TEST_PORT);
  201. printf("Now sending to multicast group: %s\n", TEST_ADDR);
  202. SLEEP_TIME *= 1000; /* convert to microsecond */
  203. if (SLEEP_TIME > 0) {
  204. /* block SIGALRM */
  205. sigemptyset(&sigset);
  206. sigaddset(&sigset, SIGALRM);
  207. sigprocmask(SIG_BLOCK, &sigset, NULL);
  208. /* set up handler for SIGALRM */
  209. act.sa_handler = &timerhandler;
  210. sigemptyset(&act.sa_mask);
  211. act.sa_flags = SA_SIGINFO;
  212. sigaction(SIGALRM, &act, NULL);
  213. /*
  214. * set up interval timer
  215. */
  216. times.it_value.tv_sec = 0; /* wait a bit for system to "stabilize" */
  217. times.it_value.tv_usec = 1; /* tv_sec or tv_usec cannot be both zero */
  218. times.it_interval.tv_sec = (time_t)(SLEEP_TIME / 1000000);
  219. times.it_interval.tv_usec = (long)(SLEEP_TIME % 1000000);
  220. setitimer(ITIMER_REAL, &times, NULL);
  221. handler_par.s = s;
  222. handler_par.achOut = achOut;
  223. handler_par.len = strlen(achOut) + 1;
  224. handler_par.n = 0;
  225. handler_par.stTo = (struct sockaddr *)&stTo;
  226. handler_par.addr_size = addr_size;
  227. /* now wait for the alarms */
  228. sigemptyset(&sigset);
  229. for (;;) {
  230. sigsuspend(&sigset);
  231. }
  232. return 0;
  233. } else {
  234. for (i = 0; i < 10; i++) {
  235. int addr_size = sizeof(struct sockaddr_in);
  236. if (NUM) {
  237. achOut[3] = (unsigned char)(i >> 24);
  238. achOut[2] = (unsigned char)(i >> 16);
  239. achOut[1] = (unsigned char)(i >> 8);
  240. achOut[0] = (unsigned char)(i);
  241. printf("Send out msg %d to %s:%d\n", i, TEST_ADDR, TEST_PORT);
  242. } else {
  243. printf("Send out msg %d to %s:%d: %s\n", i, TEST_ADDR, TEST_PORT, achOut);
  244. }
  245. iRet = sendto(s, achOut, (NUM ? 4 : strlen(achOut) + 1), 0, (struct sockaddr *)&stTo, addr_size);
  246. if (iRet < 0) {
  247. printf("sendto() failed.\n");
  248. exit(1);
  249. }
  250. } /* end for(;;) */
  251. }
  252. return 0;
  253. } /* end main() */
  254. void timerhandler(void)
  255. {
  256. int iRet;
  257. static int iCounter = 1;
  258. if (NUM) {
  259. handler_par.achOut = (char *)(&iCounter);
  260. handler_par.len = sizeof(iCounter);
  261. printf("Sending msg %d, TTL %d, to %s:%d\n", iCounter, TTL_VALUE, TEST_ADDR, TEST_PORT);
  262. } else {
  263. printf("Sending msg %d, TTL %d, to %s:%d: %s\n", iCounter, TTL_VALUE, TEST_ADDR, TEST_PORT, handler_par.achOut);
  264. }
  265. iRet = sendto(handler_par.s, handler_par.achOut, handler_par.len, handler_par.n, handler_par.stTo, handler_par.addr_size);
  266. if (iRet < 0) {
  267. printf("sendto() failed.\n");
  268. exit(1);
  269. }
  270. iCounter++;
  271. return;
  272. }
  273. /**
  274. * Local Variables:
  275. * version-control: t
  276. * indent-tabs-mode: t
  277. * c-file-style: "linux"
  278. * End:
  279. */