int main(int argc, char **argv) { int raw_mode = 0; struct GlobalHeader ghead; // parameter check if(argc == 1) { raw_mode = 0; } else if(argc == 2) { if(0 != strcmp(argv[1], "-r")) { usage(); return 0; } raw_mode = 1; } else { usage(); return 0; } // read global header if(!raw_mode) { // XXX Should check link type and record snapshot length. fread(&ghead, sizeof(unsigned char), sizeof(struct GlobalHeader), stdin); if(ghead.magic != MAGIC_NUMBER) { printf("invalid file format\n"); return 0; } printf("PCAP format v%d.%d, ", ghead.majorver, ghead.minorver); if(ghead.linklayertype != 1) { printf("unsupported link layer type\n"); return 0; } printf("link layer type: Ethernet.\n"); } // read each packet while (1) { int i; struct PacketHeader phead; struct EthernetHeader ehead; printf("\n"); // packet header if (!raw_mode) { // XXX Should use length information in decoding below. if(sizeof(struct PacketHeader) != fread(&phead, sizeof(unsigned char), sizeof(struct PacketHeader), stdin)) break; if(phead.packetsize > ghead.snapshotlength) { printf("wrong packet at 0x%08x\n", (int)ftell(stdin)); return 0; } printf("<<<PCAP packet\n"); printf(" packet size: %d\n", phead.packetsize); printf(" payload size: %d\n", phead.payloadsize); } // data captured from wire get_ether(&ehead); print_ether(&ehead); if (ehead.length_type <= 1500) { // old style packet printf("Old style packet, length = %d\n", ehead.length_type); printf("We don't support this packet now\n"); if (!raw_mode) { dump(phead.packetsize-sizeof(ehead), 1); } } else if (ehead.length_type == 0x0800) { // ASSIGNMENT: MODIFY THIS TO PRINT INFORMATION ABOUT ENCAPSULATED PAYLOAD. struct IPv4Header ipv4head; get_ipv4(&ipv4head); print_ipv4(&ipv4head); if(ipv4head.protocol == 4) { printf("IP packet\n"); printf("Wedon't support this packet now\n"); dump(ipv4head.datalen-sizeof(ipv4head), 1); } else if(ipv4head.protocol == 6) { struct TCPHeader tcphead; get_tcp(&tcphead); print_tcp(&tcphead); // get payload in TCP packet //dump(ipv4head.datalen-sizeof(ipv4head)-sizeof(tcphead), 2); if(phead.packetsize >= sizeof(ehead)+ipv4head.datalen) { dump(ipv4head.datalen-sizeof(ipv4head)-sizeof(tcphead), 0); } else { dump((ipv4head.datalen-sizeof(ipv4head)-sizeof(tcphead))-(sizeof(ehead)+ipv4head.datalen-phead.packetsize), 0); } } else if(ipv4head.protocol == 17) { struct UDPHeader udphead; get_udp(&udphead); assert(udphead.size == ipv4head.datalen-sizeof(ipv4head)); print_udp(&udphead); // get payload in UDP packet if(phead.packetsize >= sizeof(ehead)+ipv4head.datalen) { dump(udphead.size-sizeof(udphead), 0); } else { dump((udphead.size-sizeof(udphead))-(sizeof(ehead)+ipv4head.datalen-phead.packetsize), 0); } } else { printf("Unexpected IP packet\n"); dump(ipv4head.datalen-sizeof(ipv4head), 1); } if(!raw_mode) { if(phead.packetsize > sizeof(ehead)+ipv4head.datalen) { printf("pad:\n"); dump(phead.packetsize-sizeof(ehead)-ipv4head.datalen, 1); } } } else if(ehead.length_type == 0x0806) { printf("ARP packet\n"); printf("We don't support this packet now\n"); if (!raw_mode) { dump(phead.packetsize-sizeof(ehead), 1); } } else if(ehead.length_type == 0x86DD) { printf("IPv6 packet\n"); printf("We don't support this packet now\n"); if (!raw_mode) { dump(phead.packetsize-sizeof(ehead), 1); } } else { printf("Unexpected Ethernet packet\n"); if (!raw_mode) { dump(phead.packetsize-sizeof(ehead), 1); } } } return 0; }
// gets a datagram from the master with or without blocking. updates // master_position if successful. if the master has exited, returns 1. // returns -1 on error. // otherwise, returns 0. static int get_udp(int blocking, float *master_position) { char mesg[100]; int chars_received = -1; int n; static int sockfd = -1; if (sockfd == -1) { struct timeval tv = { .tv_sec = 30 }; struct sockaddr_in servaddr = { 0 }; sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd == -1) return -1; servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(udp_port); bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); } set_blocking(sockfd, blocking); while (-1 != (n = recvfrom(sockfd, mesg, sizeof(mesg)-1, 0, NULL, NULL))) { // flush out any further messages so we don't get behind if (chars_received == -1) set_blocking(sockfd, 0); chars_received = n; mesg[chars_received] = 0; if (strcmp(mesg, "bye") == 0) return 1; sscanf(mesg, "%f", master_position); } return 0; } void send_udp(const char *send_to_ip, int port, char *mesg) { static int sockfd = -1; static struct sockaddr_in socketinfo; if (sockfd == -1) { static const int one = 1; int ip_valid = 0; sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd == -1) exit_player(EXIT_ERROR); // Enable broadcast setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one)); #if HAVE_WINSOCK2_H socketinfo.sin_addr.s_addr = inet_addr(send_to_ip); ip_valid = socketinfo.sin_addr.s_addr != INADDR_NONE; #else ip_valid = inet_aton(send_to_ip, &socketinfo.sin_addr); #endif if (!ip_valid) { mp_msg(MSGT_CPLAYER, MSGL_FATAL, MSGTR_InvalidIP); exit_player(EXIT_ERROR); } socketinfo.sin_family = AF_INET; socketinfo.sin_port = htons(port); } sendto(sockfd, mesg, strlen(mesg), 0, (struct sockaddr *) &socketinfo, sizeof(socketinfo)); } // this function makes sure we stay as close as possible to the master's // position. returns 1 if the master tells us to exit, 0 otherwise. int udp_slave_sync(MPContext *mpctx) { // grab any waiting datagrams without blocking int master_exited = get_udp(0, &udp_master_position); while (!master_exited) { float my_position = mpctx->sh_video->pts; // if we're way off, seek to catch up if (FFABS(my_position - udp_master_position) > udp_seek_threshold) { abs_seek_pos = SEEK_ABSOLUTE; rel_seek_secs = udp_master_position; break; } // normally we expect that the master will have just played the // frame we're ready to play. break out and play it, and we'll be // right in sync. // or, the master might be up to a few seconds ahead of us, in // which case we also want to play the current frame immediately, // without waiting. // UDP_TIMING_TOLERANCE is a small value that lets us consider // the master equal to us even if it's very slightly ahead. if (udp_master_position + UDP_TIMING_TOLERANCE > my_position) break; // the remaining case is that we're slightly ahead of the master. // usually, it just means we called get_udp() before the datagram // arrived. call get_udp again, but this time block until we receive // a datagram. master_exited = get_udp(1, &udp_master_position); } return master_exited; }