📄 common.c
字号:
/* Westell 6100 multicast data collection utility. * Shared code for wstart and wstop. * * Copyright: Josh Carroll (josh.carroll@gmail.com) * 10/13/2004 * * common.c is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA **/#include "common.h"wmodel_t models[MAX_MODEL_NUMBER+1] = { { /* Westell 610010 */ "610010", {4, 4}, {8, 2}, {10, 2}, {12, 2}, {14, 2}, {16, 2}, {18, 2}, {20, 2}, {22, 2}, {24, 2}, {28, 4}, {32, 4}, {36, 4}, {40, 4}, {44, 4}, {48, 4}, {52, 4}, /* skipped data, not sure what resides there */ {98, 4}, {102, 4}, {106, 4}, /* server port */ 1875, /* udp packet size */ 120, /* multicast group to join */ "224.73.193.62" }, { /* Westell 610030 */ "610030", {4, 4}, {8, 2}, {10, 2}, {12, 2}, {14, 2}, {16, 2}, {18, 2}, {20, 2}, {22, 2}, {24, 2}, {28, 4}, {32, 4}, {36, 4}, {40, 4}, {44, 4}, {48, 4}, {52, 4}, /* skipped data, not sure what resides there */ {98, 4}, {102, 4}, {106, 4}, /* server port */ 1875, /* udp packet size */ 120, /* multicast group to join */ "224.73.193.62" }, { /* Westell 36R516 */ "36R516", {4, 4}, {8, 2}, {10, 2}, {12, 2}, {14, 2}, {16, 2}, {18, 2}, {20, 2}, {22, 2}, {24, 2}, {28, 4}, {32, 4}, {36, 4}, {40, 4}, {44, 4}, {48, 4}, {52, 0}, /* skipped data, not sure what resides there */ {98, 4}, {102, 4}, {106, 4}, /* server port */ 1875, /* udp packet size */ 120, /* multicast group to join */ "224.73.193.62" }, { /* Westell 2200 */ "2200", {4, 4}, {8, 2}, {10, 2}, {12, 2}, {14, 2}, {16, 2}, {18, 2}, {20, 2}, {22, 2}, {24, 2}, {28, 4}, {32, 4}, {36, 4}, {40, 4}, {44, 4}, {48, 4}, {52, 4}, /* skipped data, not sure what resides there */ {98, 4}, {102, 4}, {106, 4}, /* server port */ 1875, /* udp packet size */ 120, /* multicast group to join */ "224.73.193.62" }, { /* Westell 7400 series */ "7400", {4, 4}, {8, 2}, {10, 2}, {12, 2}, {14, 2}, {16, 2}, {18, 2}, {20, 2}, {22, 2}, {24, 2}, {28, 4}, {32, 4}, {36, 4}, {40, 4}, {44, 4}, {48, 4}, {52, 4}, /* skipped data, not sure what resides there */ {98, 4}, {102, 4}, {106, 4}, /* server port */ 1875, /* udp packet size */ 120, /* multicast group to join */ "224.73.193.62" }};/* calc the checksum for the ip or igmp header */unsigned short chksum(unsigned short *hdr, int len) { long sum = 0; while(len > 1) { sum += *hdr++; len -= 2; } if(len > 0) { sum += *hdr; } while(sum >> 16) { sum = (sum >> 16) + (sum & 0xffff); } /* truncate to 16 bits */ sum = ~sum; return sum;}int send_packet(wpacket_t *pkt, char *bcast) { char errmsg[80]; struct in_addr broadcast; struct sockaddr_in server, thishost; int udp_socket,optval = 1; char *buffer; /* pkt->data holds the 8-bit decimal value of the * consecutive packets, so we should be able to * memcpy the appropriate number of bits to the * buffer character array, and pass that to the sento * function later */ buffer = malloc(sizeof(char) * pkt->packet_length); if(buffer == NULL) { perror("Could not allocate buffer memory for socket packet data"); exit(1); } memcpy(buffer, pkt->data, pkt->packet_length); /* create the socket */ if ((udp_socket = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { perror("Could not create socket"); /* clean up buffer */ wfree(buffer); exit(1); } if(setsockopt(udp_socket, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)) < 0) { perror("Setting socket options failed"); close(udp_socket); /* clean up buffer */ wfree(buffer); exit(1); } inet_aton(bcast, &broadcast); server.sin_family = AF_INET; server.sin_addr.s_addr = broadcast.s_addr; thishost.sin_family = AF_INET; thishost.sin_addr.s_addr = INADDR_ANY; thishost.sin_port = htons(pkt->src_port); server.sin_port = htons(pkt->dst_port); if(bind(udp_socket, (struct sockaddr *) &thishost, sizeof(thishost)) < 0) { sprintf(errmsg, "Could not bind to local port: %d", pkt->src_port); perror(errmsg); close(udp_socket); /* clean up buffer */ wfree(buffer); exit(1); } if(sendto(udp_socket, buffer, pkt->packet_length, 0, (struct sockaddr *) &server, sizeof(server)) < 0) { perror("Could not send data to socket"); close(udp_socket); /* clean up buffer */ wfree(buffer); exit(1); } /* close the socket now */ close(udp_socket); /* free up the memory from buffer */ wfree(buffer); return(0);}/* sends the multicast subscription packets */void multicast_subscribe(char dest[16], char group[16]) { int sock, retval, optval; struct ip *iphdr; struct igmp *igmphdr; struct sockaddr_in server; unsigned char *packet; /* allocate memory for the packet */ packet = malloc(IGMP_PKT_SIZE); /* create the server socket */ inet_aton(dest, &server.sin_addr); server.sin_family = AF_INET; /* initialize ip header */ iphdr = (struct ip *)packet; /* zero out the packet */ memset((char *)iphdr,'\0',sizeof(struct ip)); iphdr->ip_hl = 5; iphdr->ip_v = 4; iphdr->ip_len = IGMP_PKT_SIZE; iphdr->ip_id = htons(getpid()); iphdr->ip_ttl = 1; iphdr->ip_p = IPPROTO_IGMP; iphdr->ip_src.s_addr = INADDR_ANY; /* destination is the same as our socket */ iphdr->ip_dst = server.sin_addr; iphdr->ip_sum = (unsigned short)chksum((unsigned short *)iphdr, sizeof(struct ip)); /* now build the igmp header */ igmphdr = (struct igmp *)(packet + sizeof(struct ip)); igmphdr->igmp_type = IGMP_V2_MEMBERSHIP_REPORT; igmphdr->igmp_code = 0; igmphdr->igmp_cksum = (unsigned short)chksum((unsigned short *)igmphdr, sizeof(struct igmp)); inet_aton(group, &igmphdr->igmp_group); /* create the raw socket */ if((sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) { perror("Could not create raw socket"); /* cleanup before we exit */ wfree(packet); exit(1); } if((setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &optval, sizeof(optval))) < 0) { perror("Could not set socket options"); close(sock); /* cleanup before we exit */ wfree(packet); exit(1); } if((setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval))) < 0) { perror("Could not set additional socket options"); close(sock); /* cleanup before we exit */ wfree(packet); exit(1); } if((retval = sendto(sock, packet, IGMP_PKT_SIZE, 0, (struct sockaddr *) &server, sizeof(server))) < 0) { perror("Failed to send igmp membership packet"); close(sock); /* cleanup before we exit */ wfree(packet); exit(1); } close(sock); wfree(packet);}/* sends the multicast leave group packets */void multicast_leave(char dest[16], char group[16]) { int sock, retval, optval; struct ip *iphdr; struct igmp *igmphdr; struct sockaddr_in server; unsigned char *packet; /* allocate memory for the packet */ packet = malloc(IGMP_PKT_SIZE); /* create the server socket */ inet_aton(dest, &server.sin_addr); server.sin_family = AF_INET; /* initialize ip header */ iphdr = (struct ip *)packet; /* zero out the packet */ memset((char *)iphdr,'\0',sizeof(struct ip)); iphdr->ip_hl = 5; iphdr->ip_v = 4; iphdr->ip_len = IGMP_PKT_SIZE; iphdr->ip_id = htons(getpid()); iphdr->ip_ttl = 1; iphdr->ip_p = IPPROTO_IGMP; iphdr->ip_src.s_addr = INADDR_ANY; /* destination is the same as our socket */ iphdr->ip_dst = server.sin_addr; iphdr->ip_sum = (unsigned short)chksum((unsigned short *)iphdr, sizeof(struct ip)); /* now build the igmp header */ igmphdr = (struct igmp *)(packet + sizeof(struct ip)); igmphdr->igmp_type = IGMP_V2_LEAVE_GROUP; igmphdr->igmp_code = 0; igmphdr->igmp_cksum = (unsigned short)chksum((unsigned short *)igmphdr, sizeof(struct igmp)); inet_aton(group, &igmphdr->igmp_group); /* create the raw socket */ if((sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) { perror("Could not create raw socket"); /* clean up packet buffer */ wfree(packet); exit(1); } if((setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &optval, sizeof(optval))) < 0) { perror("Could not set socket options"); close(sock); /* clean up packet buffer */ wfree(packet); exit(1); } if((setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval))) < 0) { perror("Could not set additional socket options"); close(sock); /* clean up packet buffer */ wfree(packet); exit(1); } if((retval = sendto(sock, packet, IGMP_PKT_SIZE, 0, (struct sockaddr *) &server, sizeof(server))) < 0) { perror("Failed to send igmp membership packet"); close(sock); /* clean up packet buffer */ wfree(packet); exit(1); } close(sock); wfree(packet);}void usage(char *prog) { int i; printf("Usage: %s -m <model>\n", prog); printf("Valid models:\n"); for(i=0; i <= MAX_MODEL_NUMBER; i++) { printf("\t%d\t%s\n", i, models[i].model_number); } exit(1);}/* print the individual records */void print_info(const char *prefix, int32_t val, int divisor, int decimal_print) { if(val < 0) { printf("%s: %s\n", prefix, W_NO_DATA); } else { if(divisor == -1 || decimal_print != 1) { printf("%s: %u\n", prefix, val); } else { printf("%s: %.1f\n", prefix, val/(float)divisor); } }}/* takes the westell data struct and prints the fields out */void print_data(struct modemdata data, int decimal_print) { /* currently hard-coded. Remove what you want or modify to * product mrtg-friendly results here. For now it's just * dumping ALL the stats */ print_info("Uptime Counter", data.timectr, TIMECTR, decimal_print); print_info("Upstream SNR", data.snr_up, SNR_UP, decimal_print); print_info("Upstream Power", data.pwr_up, PWR_UP, decimal_print); print_info("Upstream Attenuation", data.attn_up, ATTN_UP, decimal_print); print_info("Upstream Sync Rate", data.syncrate_up, SYNCRATE_UP, decimal_print); print_info("Downstream SNR", data.snr_down, SNR_DOWN, decimal_print); print_info("Downstream Power", data.pwr_down, PWR_DOWN, decimal_print); print_info("Downstream Attenuation", data.attn_down, ATTN_DOWN, decimal_print); print_info("Downstream Sync Rate", data.syncrate_down, SYNCRATE_DOWN, decimal_print); print_info("FEC Errors", data.fec_errors, FEC_ERRORS, decimal_print); print_info("CRC Errors", data.crc_errors, CRC_ERRORS, decimal_print); print_info("HEC Errors", data.hec_errors, HEC_ERRORS, decimal_print); print_info("Signal Lost", data.signal_lost, SIGNAL_LOST, decimal_print); print_info("Frame Lost", data.frame_lost, FRAME_LOST, decimal_print); print_info("Tx Cell", data.tx_cells, TX_CELLS, decimal_print); print_info("Rx Cells", data.rx_cells, RX_CELLS, decimal_print); print_info("Dropped Cells", data.dropped_cells, DROPPED_CELLS, decimal_print); print_info("Rx Ethernet", data.ethernet_rx, ETHERNET_RX, decimal_print); print_info("Tx Ethernet", data.ethernet_tx, ETHERNET_TX, decimal_print); print_info("Discarded Ethernet", data.ethernet_discard, ETHERNET_DISCARD, decimal_print);}int32_t getfield(const unsigned char *packet, const field_t *pkt_field) { int32_t i32; int16_t i16; int8_t i8; switch(pkt_field->size) { case 1: memcpy(&i8, packet + pkt_field->offset, pkt_field->size); return i8; case 2: memcpy(&i16, packet + pkt_field->offset, pkt_field->size); return i16; case 4: memcpy(&i32, packet + pkt_field->offset, pkt_field->size); return i32; default: return -1; }}int listen_for_mcast(int model, unsigned char *packet, int packet_size, char *listen_addr) { char errmsg[80]; /* socket handle, and various flow control and * testing variables */ int socket_handle, retval; /* socket variables for establishing the multicast socket */ struct ip_mreq mreq; struct sockaddr_in client, server; struct in_addr mcast_addr; struct hostent *mcast_host; socklen_t client_len; int server_port; char mcast_group[16]; struct in_addr laddr; /* to hold the timeout value */ struct timeval read_timeout; /* for read/rhwrite/exception handling with timeout */ int select_val; fd_set read_fd, write_fd, exception_fd; /* read the values of the model's parameters */ strcpy(mcast_group,models[model].mcast_group); server_port = models[model].server_port; /* use the specified listen address if requested */ if(listen_addr == NULL) { laddr.s_addr = INADDR_ANY; } else { inet_aton(listen_addr, &laddr); } /* get mcast address to listen to */ mcast_host=gethostbyname(models[model].mcast_group); if(mcast_host==NULL) { sprintf(errmsg, "Unknown multicast group: %s\n", mcast_group); perror(errmsg); return 1; } memcpy(&mcast_addr, mcast_host->h_addr_list[0],mcast_host->h_length); /* check given address is multicast */ if(!IN_MULTICAST(ntohl(mcast_addr.s_addr))) { printf("Address is not multicast: %s\n", inet_ntoa(mcast_addr)); return 1; } /* create socket */ if( (socket_handle = socket(AF_INET,SOCK_DGRAM,0)) < 0) { perror("Cannot create socket"); return 1; } /* bind port */ server.sin_family=AF_INET; server.sin_addr.s_addr = INADDR_ANY; server.sin_port=htons(server_port); if(bind(socket_handle, (struct sockaddr *) &server, sizeof(server))<0) { sprintf(errmsg, "Unable to bind to port %d", server_port); perror(errmsg); return 1; } /* join multicast group */ mreq.imr_multiaddr.s_addr=mcast_addr.s_addr; mreq.imr_interface.s_addr=laddr.s_addr; /* continue only if we successfully joined the multicast group */ if((retval = setsockopt(socket_handle,IPPROTO_IP,IP_ADD_MEMBERSHIP, (void *) &mreq, sizeof(mreq))) == -1) { sprintf(errmsg, "Cannot join multicast group %s\n", inet_ntoa(mcast_addr)); perror(errmsg); return 1; } else { /* infinite server loop could go here */ client_len=sizeof(client); /* select setup */ FD_ZERO(&read_fd); FD_ZERO(&write_fd); FD_ZERO(&exception_fd); read_timeout.tv_sec = POLL_TIMEOUT; read_timeout.tv_usec = 0; FD_SET(socket_handle, &read_fd); FD_SET(socket_handle, &write_fd); FD_SET(socket_handle, &exception_fd); if((select_val = select(socket_handle+1, &read_fd, 0, 0, &read_timeout)) == -1) { perror("Select failed for socket"); /* free the memory in the packet buffer */ wfree(packet); return 1; } else { if(! FD_ISSET(socket_handle, &read_fd)) { printf("Could not find multicast stream. Please try again.\n"); /* free the memory in the packet buffer */ wfree(packet); return 1; } } /* read the data from the multicast packet of size packet_size */ if(recvfrom(socket_handle, packet, packet_size, 0, (struct sockaddr *) &client, &client_len) == -1) { perror("Could not receive on socket"); return 1; } /* successful recvfrom, return packet */ return 0; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -