networkbrowser: nbtscan: make private functions static
[enigma2-plugins.git] / networkbrowser / src / lib / nbtscan.c
1 /*###########################################################################
2 #
3 # written by :  Stephen J. Friedl
4 #               Software Consultant
5 #               steve@unixwiz.net
6 #
7 # Copyright (C) 2007 - 2008 by
8 # nixkoenner <nixkoenner@newnigma2.to>
9 # License: GPL
10 #
11 # This program is free software; you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation; either version 2 of the License, or
14 # (at your option) any later version.
15 #
16 # This program is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # GNU General Public License for more details.
20 #
21 # You should have received a copy of the GNU General Public License
22 # along with this program; if not, write to the Free Software
23 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #
25 ###########################################################################*/
26
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #include <arpa/inet.h>
31 #include <stdlib.h>
32 #include <sys/time.h>
33 #include <string.h>
34 #include <unistd.h>
35 #include <getopt.h>
36 #if HAVE_STDINT_H
37 #include <stdint.h>
38 #endif
39
40 #include "nbtscan.h"
41
42 int quiet = 0;
43
44 static int set_range(const char *range_str, struct ip_range *range_struct)
45 {
46         if (is_ip(range_str, range_struct))
47                 return 1;
48         if (is_range1(range_str, range_struct))
49                 return 1;
50         if (is_range2(range_str, range_struct))
51                 return 1;
52         return 0;
53 };
54
55 static int python_hostinfo(struct in_addr addr, const struct nb_host_info *hostinfo, netinfo *nInfo, int pos)
56 {
57         int unique;
58         my_uint8_t service;
59
60         sleep(1);
61         service = hostinfo->names[0].ascii_name[15];
62         unique = !(hostinfo->names[0].rr_flags & 0x0080);
63         strncpy(nInfo[pos].name, hostinfo->names[0].ascii_name, 15);
64         strncpy(nInfo[pos].domain, hostinfo->names[1].ascii_name, 15);
65         sprintf(nInfo[pos].service, "%s", (char *)getnbservicename(service, unique, hostinfo->names[0].ascii_name));
66         if (hostinfo->footer) {
67                 sprintf(nInfo[pos].mac, "%02x:%02x:%02x:%02x:%02x:%02x",
68                         hostinfo->footer->adapter_address[0], hostinfo->footer->adapter_address[1],
69                         hostinfo->footer->adapter_address[2], hostinfo->footer->adapter_address[3],
70                         hostinfo->footer->adapter_address[4], hostinfo->footer->adapter_address[5]);
71         }
72         strcpy(nInfo[pos].ip, inet_ntoa(addr));
73         return 0;
74 }
75
76 netinfo *newNetInfo()
77 {
78         netinfo *nInfo = malloc(sizeof(netinfo) * 255);
79         if (!nInfo)
80                 exit(0);        // TODO: besser machen 
81         memset(nInfo, 0, sizeof(netinfo) * 255);
82         return nInfo;
83 }
84
85 void freeNetInfo(netinfo * nInfo)
86 {
87         free(nInfo);
88 }
89
90 #define BUFFSIZE 1024
91
92 int netInfo(char *pythonIp, netinfo * nInfo)
93 {
94         int timeout = 10000, send_ok;
95         char *target_string;
96         struct ip_range range;
97         void *buff;
98         int sock;
99         unsigned int addr_size;
100         struct sockaddr_in src_sockaddr, dest_sockaddr;
101         struct in_addr *prev_in_addr = NULL;
102         struct in_addr *next_in_addr;
103         struct timeval select_timeout, last_send_time, current_time, diff_time, send_interval;
104         struct timeval transmit_started, now, recv_time;
105         struct nb_host_info *hostinfo;
106         fd_set *fdsr;
107         fd_set *fdsw;
108         int size;
109         int pos = 0;
110         struct list *scanned;
111         my_uint32_t rtt_base;   /* Base time (seconds) for round trip time calculations */
112         float rtt;              /* most recent measured RTT, seconds */
113         float srtt = 0;         /* smoothed rtt estimator, seconds */
114         float rttvar = 0.75;    /* smoothed mean deviation, seconds */
115         double delta;           /* used in retransmit timeout calculations */
116         int rto, retransmits = 0, more_to_send = 1, i;
117         char errmsg[80];
118
119         if ((target_string = strdup(pythonIp)) == NULL) {
120                 err_die("Malloc failed.\n", quiet);
121         }
122         if (!set_range(target_string, &range)) {
123                 printf("Error: %s is not an IP address or address range.\n", target_string);
124                 free(target_string);
125         };
126         /* Finished with options */
127   /*************************/
128
129         /* Prepare socket and address structures */
130   /*****************************************/
131         sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
132         if (sock < 0)
133                 err_die("Failed to create socket", quiet);
134
135         bzero((void *)&src_sockaddr, sizeof(src_sockaddr));
136         src_sockaddr.sin_family = AF_INET;
137         if (bind(sock, (struct sockaddr *)&src_sockaddr, sizeof(src_sockaddr)) == -1)
138                 err_die("Failed to bind", quiet);
139
140         fdsr = malloc(sizeof(fd_set));
141         if (!fdsr)
142                 err_die("Malloc failed", quiet);
143         FD_ZERO(fdsr);
144         FD_SET(sock, fdsr);
145
146         fdsw = malloc(sizeof(fd_set));
147         if (!fdsw)
148                 err_die("Malloc failed", quiet);
149         FD_ZERO(fdsw);
150         FD_SET(sock, fdsw);
151
152         /* timeout is in milliseconds */
153         select_timeout.tv_sec = 60;     /* Default 1 min to survive ARP timeouts */
154         select_timeout.tv_usec = 0;
155
156         addr_size = sizeof(struct sockaddr_in);
157
158         next_in_addr = malloc(sizeof(struct in_addr));
159         if (!next_in_addr)
160                 err_die("Malloc failed", quiet);
161
162         buff = malloc(BUFFSIZE);
163         if (!buff)
164                 err_die("Malloc failed", quiet);
165
166         /* Calculate interval between subsequent sends */
167
168         timerclear(&send_interval);
169         send_interval.tv_usec = 1;      /* for 10baseT interval should be about 1 ms */
170
171         gettimeofday(&last_send_time, NULL);    /* Get current time */
172
173         rtt_base = last_send_time.tv_sec;
174
175         /* Send queries, receive answers and print results */
176   /***************************************************/
177
178         scanned = new_list();
179
180         for (i = 0; i <= retransmits; i++) {
181                 gettimeofday(&transmit_started, NULL);
182                 while ((select(sock + 1, fdsr, fdsw, NULL, &select_timeout)) > 0) {
183                         if (FD_ISSET(sock, fdsr)) {
184                                 if ((size = recvfrom(sock, buff, BUFFSIZE, 0, (struct sockaddr *)&dest_sockaddr, &addr_size)) <= 0) {
185                                         snprintf(errmsg, 80, "%s\tRecvfrom failed", inet_ntoa(dest_sockaddr.sin_addr));
186                                         err_print(errmsg, quiet);
187                                         continue;
188                                 };
189                                 gettimeofday(&recv_time, NULL);
190                                 memset(&hostinfo, 0, sizeof(hostinfo));
191                                 hostinfo = (struct nb_host_info *)parse_response(buff, size);
192                                 if (!hostinfo) {
193                                         err_print("parse_response returned NULL", quiet);
194                                         continue;
195                                 };
196                                 /* If this packet isn't a duplicate */
197                                 if (insert(scanned, ntohl(dest_sockaddr.sin_addr.s_addr))) {
198                                         rtt = recv_time.tv_sec + recv_time.tv_usec / 1000000 - rtt_base - hostinfo->header->transaction_id / 1000;
199                                         /* Using algorithm described in Stevens' 
200                                            Unix Network Programming */
201                                         delta = rtt - srtt;
202                                         srtt += delta / 8;
203                                         if (delta < 0.0)
204                                                 delta = -delta;
205                                         rttvar += (delta - rttvar) / 4;
206                                         if (hostinfo->names == 0x0) {
207                                                 printf("hostinfo->names == NULL\n");
208                                         } else {
209                                                 python_hostinfo(dest_sockaddr.sin_addr, hostinfo, nInfo, pos);
210                                                 pos++;
211                                         }
212                                 };
213                                 free(hostinfo);
214                         };
215
216                         FD_ZERO(fdsr);
217                         FD_SET(sock, fdsr);
218
219                         /* check if send_interval time passed since last send */
220                         gettimeofday(&current_time, NULL);
221                         timersub(&current_time, &last_send_time, &diff_time);
222                         send_ok = timercmp(&diff_time, &send_interval, >=);
223
224                         if (more_to_send && FD_ISSET(sock, fdsw) && send_ok) {
225                                 if (next_address(&range, prev_in_addr, next_in_addr)) {
226                                         if (!in_list(scanned, ntohl(next_in_addr->s_addr)))
227                                                 send_query(sock, *next_in_addr, rtt_base);
228                                         prev_in_addr = next_in_addr;
229                                         /* Update last send time */
230                                         gettimeofday(&last_send_time, NULL);
231                                 } else {        /* No more queries to send */
232                                         more_to_send = 0;
233                                         FD_ZERO(fdsw);
234                                         /* timeout is in milliseconds */
235                                         select_timeout.tv_sec = timeout / 1000;
236                                         select_timeout.tv_usec = (timeout % 1000) * 1000;       /* Microseconds */
237                                         continue;
238                                 };
239                         };
240                         if (more_to_send) {
241                                 FD_ZERO(fdsw);
242                                 FD_SET(sock, fdsw);
243                         };
244                 };
245
246                 if (i >= retransmits)
247                         break;  /* If we are not going to retransmit
248                                    we can finish right now without waiting */
249
250                 rto = (srtt + 4 * rttvar) * (i + 1);
251
252                 if (rto < 2.0)
253                         rto = 2.0;
254                 if (rto > 60.0)
255                         rto = 60.0;
256                 gettimeofday(&now, NULL);
257
258                 if (now.tv_sec < (transmit_started.tv_sec + rto))
259                         sleep((transmit_started.tv_sec + rto) - now.tv_sec);
260                 prev_in_addr = NULL;
261                 more_to_send = 1;
262                 FD_ZERO(fdsw);
263                 FD_SET(sock, fdsw);
264                 FD_ZERO(fdsr);
265                 FD_SET(sock, fdsr);
266         };
267
268         delete_list(scanned);
269         if (buff) {
270                 free(buff);
271         }
272         return 0;
273 };