premier commit (version 105)
[ipphone-tools.git] / ipphone5-report.c
1 #include <sys/socket.h>
2 #include <netinet/in.h>
3 #include <arpa/inet.h> /* inet_aton,inet_ntoa */
4 #include <signal.h> /* signal,SIG* */
5 #include <errno.h> /* errno,E* */
6 #include <unistd.h> /* read,write,close */
7 #include <string.h> /* strcmp,memset */
8 #include <stdio.h> /* FILE,fprintf */
9
10 #define WAIT_TIME_MANY 3 // seconds
11 #define WAIT_TIME_ONLYONE 1 // seconds
12
13 #define UDP_DEBUG_SRC_PORT 1025
14
15 #define REPORT_REQUEST_STRING "Hello, world!"
16 #define REPORT_DST_IPADDR "224.1.2.5"
17 #define REPORT_SRC_PORT 61030
18
19 #define REPORT_IP_POS 0 // 0-3 IP
20 #define REPORT_MAC_POS 4 // 4-9 MAC
21 #define REPORT_VERSION_POS 10 // 10-39 Version
22 #define REPORT_NUMBER_POS 40 // 40-59 Phone Number
23 #define REPORT_TYPE_POS 60 // 60 ip type
24 #define REPORT_LOGON_POS 61 // 61 Logon status
25 #define REPORT_CALL_POS 62 // 62 Call status
26 #define REPORT_PROTOCOL_POS 63 // 63 Protocol
27 #define REPORT_TOTAL_LEN 64
28
29 static const char *report_type[] = {
30 "static", "dhcp", "pppoe", "modem"
31 };
32
33 static const char *report_protocol[] = {
34 "h323", "sip", "mgcp", "n2p", "iax2", "wp", "epn", "others"
35 };
36
37 void human_report(const unsigned char *buffer) {
38 const unsigned char *p;
39 fprintf(stdout, "================\n");
40 p = buffer + REPORT_IP_POS;
41 fprintf(stdout, "IPv4 address...: %d.%d.%d.%d\n", p[0],p[1],p[2],p[3]);
42 p = buffer + REPORT_MAC_POS;
43 fprintf(stdout, "MAC address....: %02x-%02x-%02x-%02x-%02x-%02x\n", p[0],p[1],p[2],p[3],p[4],p[5]);
44 p = buffer + REPORT_VERSION_POS;
45 fprintf(stdout, "Version........: %-30.30s\n", p);
46 p = buffer + REPORT_NUMBER_POS;
47 fprintf(stdout, "Phone Number...: %-20.20s\n", p);
48 p = buffer + REPORT_TYPE_POS;
49 fprintf(stdout, "IP Type........: %d (%s)\n", p[0], (p[0] < sizeof(report_type)/sizeof(char*)) ? report_type[p[0]] : "unknown");
50 p = buffer + REPORT_LOGON_POS;
51 fprintf(stdout, "Logged on......: %d (%s)\n", p[0], (p[0] == 1 ? "Yes" : "No"));
52 p = buffer + REPORT_CALL_POS;
53 fprintf(stdout, "Busy...........: %d (%s)\n", p[0], (p[0] == 1 ? "Yes" : "No"));
54 p = buffer + REPORT_PROTOCOL_POS;
55 fprintf(stdout, "Protocol.......: %d (%s)\n", p[0], (p[0] < sizeof(report_protocol)/sizeof(char*)) ? report_protocol[p[0]] : "unknown");
56 }
57
58 void machine_report(const unsigned char *buffer) {
59 const unsigned char *p;
60 p = buffer + REPORT_IP_POS;
61 fprintf(stdout, "%d.%d.%d.%d:", p[0],p[1],p[2],p[3]);
62 p = buffer + REPORT_MAC_POS;
63 fprintf(stdout, "%02x-%02x-%02x-%02x-%02x-%02x:", p[0],p[1],p[2],p[3],p[4],p[5]);
64 p = buffer + REPORT_VERSION_POS;
65 fprintf(stdout, "%.30s:", p);
66 p = buffer + REPORT_NUMBER_POS;
67 fprintf(stdout, "%.20s:", p);
68 p = buffer + REPORT_TYPE_POS;
69 fprintf(stdout, "%s:", (p[0] < sizeof(report_type)/sizeof(char*)) ? report_type[p[0]] : "unknown");
70 p = buffer + REPORT_LOGON_POS;
71 fprintf(stdout, "%s:", (p[0] == 1 ? "Yes" : "No"));
72 p = buffer + REPORT_CALL_POS;
73 fprintf(stdout, "%s:", (p[0] == 1 ? "Yes" : "No"));
74 p = buffer + REPORT_PROTOCOL_POS;
75 fprintf(stdout, "%s\n", (p[0] < sizeof(report_protocol)/sizeof(char*)) ? report_protocol[p[0]] : "unknown");
76 }
77
78 char alarm_signal = 0;
79 void signal_handler(int signal_number) {
80 if (signal_number == SIGALRM) alarm_signal = 1;
81 }
82
83 int main(int argc, const char *argv[]) {
84 const char *progname, *ipaddr;
85 struct in_addr sin_addr;
86 int only_one, answers_count;
87 int sd;
88 struct sockaddr_in sin, sinreq;
89 void (*report_function)(const unsigned char *) = machine_report;
90
91 // check arguments count
92 progname = argv[0];
93 if (argc >= 2 && !strcmp(argv[1], "vertical")) {
94 report_function = human_report;
95 argc--; argv++;
96 }
97 if (argc != 1 && argc != 2) {
98 fprintf(stderr, "Syntax: %s [vertical] [<IPv4-address>]\n", progname);
99 return 1;
100 }
101 setbuf(stdout, NULL);
102
103 // check second argument (IPv4 address)
104 if (argc == 2) {
105 ipaddr = argv[1];
106 only_one = 1;
107 } else {
108 ipaddr = REPORT_DST_IPADDR;
109 only_one = 0;
110 }
111 if (!inet_aton(ipaddr, &sin_addr)) {
112 fprintf(stderr, "'%s' is an invalid IPv4 address!\n", ipaddr);
113 return 2;
114 }
115
116 // prepare receiving answers (bind report port)
117 sd = socket(PF_INET, SOCK_DGRAM, 0);
118 if (sd < 0) {
119 fprintf(stderr, "Unable to create a socket!\n");
120 return 3;
121 }
122 memset(&sin, 0, sizeof(sin));
123 sin.sin_family = AF_INET;
124 sin.sin_port = htons(REPORT_SRC_PORT);
125 sin.sin_addr.s_addr = htonl(INADDR_ANY);
126 if (bind(sd, (struct sockaddr *)&sin, sizeof(sin))) {
127 fprintf(stderr, "Unable to bind!\n");
128 return 4;
129 }
130
131 // send report request
132 memset(&sinreq, 0, sizeof(sinreq));
133 sinreq.sin_family = AF_INET;
134 sinreq.sin_port = htons(UDP_DEBUG_SRC_PORT);
135 memcpy(&sinreq.sin_addr, &sin_addr, sizeof(sinreq.sin_addr));
136 if (sendto(sd, REPORT_REQUEST_STRING, sizeof(REPORT_REQUEST_STRING), 0, (struct sockaddr *)&sinreq, sizeof(sinreq)) < 0) {
137 fprintf(stderr, "Error sending UDP request!\n");
138 return 5;
139 }
140
141 // wait for answers
142 if (!only_one) {
143 fprintf(stdout, "#ipv4-address:mac-address:version:phone-number:connexion:logged:busy:protocol\n");
144 }
145 signal(SIGPIPE, SIG_IGN);
146 signal(SIGALRM, signal_handler);
147 alarm(only_one ? WAIT_TIME_ONLYONE : WAIT_TIME_MANY);
148 answers_count = 0;
149 while (!(only_one && (answers_count == 1)) && !alarm_signal) {
150 unsigned char buffer[REPORT_TOTAL_LEN];
151 int size = recv(sd, buffer, sizeof(buffer), MSG_DONTWAIT);
152 if (size == -1 && errno == EAGAIN) {
153 usleep(200);
154 } else if (size == REPORT_TOTAL_LEN) {
155 (*report_function)(buffer);
156 answers_count++;
157 } else {
158 fprintf(stderr, "Warning: received an invalid packet size of %d bytes!\n", size);
159 }
160 }
161
162 // cleaning
163 close(sd);
164 return (only_one && (answers_count != 1)) ? -1 : 0;
165 }