xref: /haiku/src/tests/kits/net/link_echo.cpp (revision e81a954787e50e56a7f06f72705b7859b6ab06d1)
1 /*
2  * Copyright 2006-2010, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Oliver Tappe, zooey@hirschkaefer.de
7  *		Axel Dörfler, axeld@pinc-software.de
8  */
9 
10 
11 #include <ctype.h>
12 #include <errno.h>
13 #include <net/if_dl.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <sys/socket.h>
18 
19 #include <NetworkInterface.h>
20 
21 
22 extern const char* __progname;
23 
24 
25 static const size_t kBufferSize = 1500;
26 static const uint32 kFrameType = 0x8998;
27 
28 static const char* kProgramName = __progname;
29 
30 
31 static void
32 parse_mac_address(const char* string, uint8* mac)
33 {
34 	if (sscanf(string, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", &mac[0],
35 			&mac[1], &mac[2], &mac[3], &mac[4], &mac[5]) < 6) {
36 		fprintf(stderr, "%s: Invalid MAC address.\n", kProgramName);
37 		exit(EXIT_FAILURE);
38 	}
39 }
40 
41 
42 static void
43 link_client(int fd, const BNetworkAddress& server)
44 {
45 	char buffer[kBufferSize];
46 
47 	while (fgets(buffer, kBufferSize, stdin) != NULL) {
48 		size_t length = strlen(buffer);
49 		if (length > 0)
50 			length--;
51 
52 		if (sendto(fd, buffer, length, 0, server, server.Length()) < 0) {
53 			fprintf(stderr, "%s: sendto(): %s\n", kProgramName,
54 				strerror(errno));
55 			exit(EXIT_FAILURE);
56 		}
57 		printf("sent %" B_PRIuSIZE " bytes...\n", length);
58 
59 		ssize_t bytesRead = recvfrom(fd, buffer, kBufferSize - 1, 0, NULL,
60 			NULL);
61 		if (bytesRead < 0) {
62 			fprintf(stderr, "%s: recvfrom(): %s\n", kProgramName,
63 				strerror(errno));
64 			exit(EXIT_FAILURE);
65 		}
66 		buffer[bytesRead] = 0;
67 		printf("-> %s\n", buffer);
68 	}
69 }
70 
71 
72 static void
73 link_server(int fd)
74 {
75 	while (true) {
76 		BNetworkAddress client;
77 		socklen_t length = sizeof(client);
78 
79 		char buffer[kBufferSize];
80 		ssize_t bytesRead = recvfrom(fd, buffer, kBufferSize - 1, 0, client,
81 			&length);
82 		if (bytesRead < 0) {
83 			fprintf(stderr, "%s: recvfrom(): %s\n", kProgramName,
84 				strerror(errno));
85 			exit(EXIT_FAILURE);
86 		}
87 		buffer[bytesRead] = '\0';
88 
89 		printf("got <%s> from client %s\n", buffer, client.ToString().String());
90 
91 		for (int i = 0; i < bytesRead; i++) {
92 			if (islower(buffer[i]))
93 				buffer[i] = toupper(buffer[i]);
94 			else if (isupper(buffer[i]))
95 				buffer[i] = tolower(buffer[i]);
96 		}
97 		printf("replying <%s>\n", buffer);
98 
99 		if (sendto(fd, buffer, bytesRead, 0, client, client.Length()) < 0) {
100 			fprintf(stderr, "%s: sendto(): %s\n", kProgramName,
101 				strerror(errno));
102 			exit(EXIT_FAILURE);
103 		}
104 	}
105 }
106 
107 
108 int
109 main(int argc, char** argv)
110 {
111 	enum {
112 		CLIENT_MODE,
113 		SERVER_MODE,
114 		BROADCAST_MODE,
115 	} mode = CLIENT_MODE;
116 
117 	if (argc < 3) {
118 		fprintf(stderr, "usage: %s <device> client <server-mac-address>\n"
119 			"or     %s <device> broadcast\n"
120 			"or     %s <device> server\n", kProgramName, kProgramName,
121 			kProgramName);
122 		exit(EXIT_FAILURE);
123 	}
124 
125 	BNetworkInterface interface(argv[1]);
126 	BNetworkAddress link;
127 	if (interface.GetHardwareAddress(link) != B_OK)
128 		perror("get hardware address");
129 
130 	BNetworkAddress server;
131 
132 	if (!strcmp(argv[2], "client")) {
133 		mode = CLIENT_MODE;
134 		if (argc < 4) {
135 			fprintf(stderr, "usage: %s client <server-mac-address>\n",
136 				kProgramName);
137 			exit(EXIT_FAILURE);
138 		}
139 
140 		uint8 macAddress[6];
141 		parse_mac_address(argv[3], macAddress);
142 		server.SetToLinkLevel(macAddress, sizeof(macAddress));
143 	} else if (!strcmp(argv[2], "broadcast")) {
144 		mode = BROADCAST_MODE;
145 
146 		uint8 broadcastAddress[6];
147 		for (size_t i = 0; i < sizeof(broadcastAddress); i++)
148 			broadcastAddress[i] = 0xff;
149 		server.SetToLinkLevel(broadcastAddress, sizeof(broadcastAddress));
150 	} else if (!strcmp(argv[2], "server"))
151 		mode = SERVER_MODE;
152 
153 	int fd = socket(AF_LINK, SOCK_DGRAM, 0);
154 	if (fd < 0)
155 		perror("socket");
156 
157 	// bind to protocol
158 	link.SetLinkLevelFrameType(kFrameType);
159 	server.SetLinkLevelFrameType(kFrameType);
160 
161 	if (bind(fd, link, link.Length()) != 0)
162 		perror("bind");
163 
164 	socklen_t length = sizeof(link);
165 	if (getsockname(fd, link, &length) != 0)
166 		perror("getsockname");
167 
168 	printf("bound to %s\n", link.ToString().String());
169 
170 	if (mode == BROADCAST_MODE) {
171 		int option = 1;
172 		setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &option, sizeof(option));
173 	}
174 
175 	switch (mode) {
176 		case CLIENT_MODE:
177 		case BROADCAST_MODE:
178 			link_client(fd, server);
179 			break;
180 		case SERVER_MODE:
181 			link_server(fd);
182 			break;
183 	}
184 
185 	return 0;
186 }
187