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