| #include <net/if.h> |
| #include <net/ethernet.h> |
| #include <netinet/in.h> |
| #include <unistd.h> |
| #include <stdint.h> |
| #include <netdb.h> |
| #include <sys/ioctl.h> |
| #include <sys/time.h> |
| #include <stdio.h> |
| #include <assert.h> |
| #include <packetizer.h> |
| #include <stdexcept> |
| #include <fstream> |
| |
| #ifdef DEBUG_MODE |
| # define debug(...) (__VA_ARGS__) |
| #else |
| # define debug(...) do { } while(0) |
| #endif |
| |
| static __inline uint64_t |
| read_tsc(void) |
| { |
| uint64_t tsc; |
| __asm __volatile("rdtsc" : "=A" (tsc)); |
| return tsc; |
| } |
| |
| packetizer::packetizer(const char *target_mac, const char *eth_device, |
| const char *filename) |
| { |
| seqno = 0; |
| memcpy(this->target_mac, target_mac, 6); |
| strcpy(this->eth_device, eth_device); |
| strcpy(this->filename, filename); |
| memset(&myaddr, 0, sizeof(myaddr)); |
| |
| // setuid root to open a raw socket. if we fail, too bad |
| seteuid(0); |
| sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); |
| seteuid(getuid()); |
| if(sock < 0) |
| throw std::runtime_error("socket() failed! Maybe try running as root..."); |
| |
| myaddr.sll_ifindex = if_nametoindex(eth_device); |
| myaddr.sll_family = AF_PACKET; |
| |
| int ret = bind(sock, (struct sockaddr *)&myaddr, sizeof(myaddr)); |
| if (ret < 0) |
| throw std::runtime_error("bind() failed!"); |
| |
| struct timeval tv; |
| tv.tv_sec = 1; |
| tv.tv_usec = 0; |
| if(setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,&tv,sizeof(struct timeval)) < 0) |
| throw std::runtime_error("setsockopt() failed!"); |
| |
| // get MAC address of local ethernet device |
| struct ifreq ifr; |
| strcpy(ifr.ifr_name, eth_device); |
| ret = ioctl(sock, SIOCGIFHWADDR, (char *)&ifr); |
| if (ret < 0) |
| throw std::runtime_error("ioctl() failed!"); |
| memcpy(&host_mac, &ifr.ifr_ifru.ifru_hwaddr.sa_data, 6); |
| } |
| |
| int packetizer::start() |
| { |
| std::ifstream file(filename, std::ios::in | std::ios::binary); |
| packet p(target_mac, host_mac, seqno, MAX_PAYLOAD_SIZE, NULL); |
| |
| int ret; |
| printf("Starting to packetize the file: %s\n", filename); |
| file.read(p.payload, MAX_PAYLOAD_SIZE); |
| while(file) { |
| //printf("Sending chunk %d\n", seqno); |
| ret = ::sendto(sock, (char*)&p, p.size(), 0, |
| (sockaddr*)&myaddr,sizeof(myaddr)); |
| |
| volatile uint64_t tsc = read_tsc(); |
| while((read_tsc() - tsc) < 34800); |
| if (ret < 0) |
| throw std::runtime_error("sending packet failed!"); |
| p.header.seqno = htons(next_seqno()); |
| file.read(p.payload, MAX_PAYLOAD_SIZE); |
| } |
| if(file.gcount()) { |
| p.header.payload_size = ntohl(file.gcount()); |
| p.packet_size = sizeof(p.header)+file.gcount(); |
| |
| ret = ::sendto(sock, (char*)&p, p.size(), 0, |
| (sockaddr*)&myaddr,sizeof(myaddr)); |
| if (ret < 0) |
| throw std::runtime_error("sending packet failed!"); |
| //printf("Sending chunk %d\n", seqno); |
| } |
| printf("Last chunk had %u bytes...\n", file.gcount()); |
| } |
| |
| int main(int argc, char** argv) |
| { |
| char target_mac[6]; |
| char eth_device[256]; |
| char filename[256]; |
| if(argc == 1) { |
| target_mac[0] = 0x00; |
| target_mac[1] = 0x24; |
| target_mac[2] = 0x1d; |
| target_mac[3] = 0x10; |
| target_mac[4] = 0xa2; |
| target_mac[5] = 0xb5; |
| strcpy(eth_device, "eth0"); |
| strcpy(filename, "../../fs/i686/tests/e.y4m"); |
| } |
| if(argc > 1) { |
| assert(argc == 4); |
| assert(strlen(argv[1]) == 17); |
| sscanf(argv[1], "%2x:%2x:%2x:%2x:%2x:%2x", (unsigned int *)&target_mac[0], |
| (unsigned int *)&target_mac[1], |
| (unsigned int *)&target_mac[2], |
| (unsigned int *)&target_mac[3], |
| (unsigned int *)&target_mac[4], |
| (unsigned int *)&target_mac[5]); |
| strcpy(eth_device, argv[2]); |
| strcpy(filename, argv[3]); |
| |
| } |
| packetizer p(target_mac, eth_device, filename); |
| p.start(); |
| return 0; |
| } |
| |