-add Networkbrowser and Mountmanager to easy browse network for networkdevices and...
[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 #if HAVE_STDINT_H
36 #include <stdint.h>
37 #endif
38
39 #include "nbtscan.h"
40
41 int quiet=0;
42 netinfo *nInfo = 0;
43
44 int set_range(char* range_str, struct ip_range* range_struct) {
45   if(is_ip(range_str, range_struct)) return 1;
46   if(is_range1(range_str, range_struct)) return 1;
47   if(is_range2(range_str, range_struct)) return 1;
48   return 0;
49 };
50
51 int print_header() {
52   printf("%-17s%-17s%-10s%-17s%-17s\n", "IP address", "NetBIOS Name", 
53          "Server", "User", "MAC address");
54   printf("------------------------------------------------------------------------------\n");
55   return 0;
56 };
57
58 int python_hostinfo(struct in_addr addr, const struct nb_host_info* hostinfo, netinfo *nInfo, int pos)
59 {
60         int unique;
61   my_uint8_t service;
62
63         sleep(1);
64         service = hostinfo->names[0].ascii_name[15];
65         unique = !(hostinfo->names[0].rr_flags & 0x0080);
66         strncpy(nInfo[pos].name, hostinfo->names[0].ascii_name, 15);
67         strncpy(nInfo[pos].domain, hostinfo->names[1].ascii_name, 15);
68         sprintf(nInfo[pos].service,"%s", (char*)getnbservicename(service, unique, hostinfo->names[0].ascii_name));
69         if(hostinfo->footer) {
70                 sprintf(nInfo[pos].mac,"%02x-%02x-%02x-%02x-%02x-%02x",
71                 hostinfo->footer->adapter_address[0], hostinfo->footer->adapter_address[1],
72                 hostinfo->footer->adapter_address[2], hostinfo->footer->adapter_address[3],
73                 hostinfo->footer->adapter_address[4], hostinfo->footer->adapter_address[5]);
74         }
75         strcpy(nInfo[pos].ip, inet_ntoa(addr));
76         return 0;
77 }
78
79 netinfo * newNetInfo()
80 {
81         netinfo *nInfo = malloc(sizeof(netinfo)*255);
82         if(!nInfo)
83                 exit(0); // TODO: besser machen 
84         memset(nInfo,0,sizeof(netinfo)*255);
85         return nInfo;
86 }
87
88 void freeNetInfo(netinfo *nInfo)
89 {
90         free(nInfo); 
91 }
92
93
94 #define BUFFSIZE 1024
95 #define MAX 255
96
97 int netzInfo(char *pythonIp, netinfo *nInfo) {
98   int timeout=10000, verbose=0, use137=0, bandwidth=0, send_ok=0, hr=0;
99   extern char *optarg;
100   extern int optind;
101   char* target_string;
102   char* sf=NULL;
103   char* filename =NULL;
104   struct ip_range range;
105   void *buff;
106   int sock;
107         unsigned int addr_size;
108   struct sockaddr_in src_sockaddr, dest_sockaddr;
109   struct  in_addr *prev_in_addr=NULL;
110   struct  in_addr *next_in_addr;
111   struct timeval select_timeout, last_send_time, current_time, diff_time, send_interval;
112   struct timeval transmit_started, now, recv_time;
113   struct nb_host_info* hostinfo;
114   fd_set* fdsr;
115   fd_set* fdsw;
116   int size;
117         int pos =0;
118   struct list* scanned;
119   my_uint32_t rtt_base; /* Base time (seconds) for round trip time calculations */
120   float rtt; /* most recent measured RTT, seconds */
121   float srtt=0; /* smoothed rtt estimator, seconds */
122   float rttvar=0.75; /* smoothed mean deviation, seconds */ 
123   double delta; /* used in retransmit timeout calculations */
124   int rto, retransmits=0, more_to_send=1, i;
125   char errmsg[80];
126   char str[80];
127   FILE* targetlist=NULL;
128         hr =0;
129         sf=optarg;
130         verbose = 1;
131
132         if((target_string=strdup(pythonIp))==NULL)
133         { 
134                 err_die("Malloc failed.\n", quiet);
135         }
136         if(!set_range(target_string, &range)) {
137                 printf("Error: %s is not an IP address or address range.\n", target_string);
138                 free(target_string);
139         };
140   /* Finished with options */
141   /*************************/
142
143   /* Prepare socket and address structures */
144   /*****************************************/
145   sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
146   if (sock < 0) 
147     err_die("Failed to create socket", quiet);
148
149   bzero((void*)&src_sockaddr, sizeof(src_sockaddr));
150   src_sockaddr.sin_family = AF_INET;
151   if(use137) src_sockaddr.sin_port = htons(NB_DGRAM);
152   if (bind(sock, (struct sockaddr *)&src_sockaddr, sizeof(src_sockaddr)) == -1) 
153     err_die("Failed to bind", quiet);
154         
155   fdsr=malloc(sizeof(fd_set));
156   if(!fdsr)  err_die("Malloc failed", quiet);
157   FD_ZERO(fdsr);
158   FD_SET(sock, fdsr);
159         
160   fdsw=malloc(sizeof(fd_set));
161   if(!fdsw) err_die("Malloc failed", quiet);
162   FD_ZERO(fdsw);
163   FD_SET(sock, fdsw);
164
165   /* timeout is in milliseconds */
166   select_timeout.tv_sec = timeout / 1000;
167   select_timeout.tv_usec = (timeout % 1000) * 1000; /* Microseconds */
168
169   addr_size = sizeof(struct sockaddr_in);
170
171   next_in_addr = malloc(sizeof(struct  in_addr));
172   if(!next_in_addr) err_die("Malloc failed", quiet);
173
174   buff=malloc(BUFFSIZE);
175   if(!buff) err_die("Malloc failed", quiet);
176         
177   /* Calculate interval between subsequent sends */
178
179   timerclear(&send_interval);
180   if(bandwidth) send_interval.tv_usec = 
181                   (NBNAME_REQUEST_SIZE + UDP_HEADER_SIZE + IP_HEADER_SIZE)*8*1000000 /
182                   bandwidth;  /* Send interval in microseconds */
183   else /* Assuming 10baseT bandwidth */
184     send_interval.tv_usec = 1; /* for 10baseT interval should be about 1 ms */
185   if (send_interval.tv_usec >= 1000000) {
186     send_interval.tv_sec = send_interval.tv_usec / 1000000;
187     send_interval.tv_usec = send_interval.tv_usec % 1000000;
188   }
189         
190   gettimeofday(&last_send_time, NULL); /* Get current time */
191
192   rtt_base = last_send_time.tv_sec; 
193
194   /* Send queries, receive answers and print results */
195   /***************************************************/
196         
197   scanned = new_list();
198
199   for(i=0; i <= retransmits; i++) {
200     gettimeofday(&transmit_started, NULL);
201     while ( (select(sock+1, fdsr, fdsw, NULL, &select_timeout)) > 0) {
202       if(FD_ISSET(sock, fdsr)) {
203         if ( (size = recvfrom(sock, buff, BUFFSIZE, 0,
204                               (struct sockaddr*)&dest_sockaddr, &addr_size)) <= 0 ) {
205           snprintf(errmsg, 80, "%s\tRecvfrom failed", inet_ntoa(dest_sockaddr.sin_addr));
206           err_print(errmsg, quiet);
207           continue;
208         };
209         gettimeofday(&recv_time, NULL);
210         hostinfo = (struct nb_host_info*)parse_response(buff, size);
211         if(!hostinfo) {
212           err_print("parse_response returned NULL", quiet);
213           continue;
214         };
215                                 /* If this packet isn't a duplicate */
216         if(insert(scanned, ntohl(dest_sockaddr.sin_addr.s_addr))) {
217           rtt = recv_time.tv_sec + 
218             recv_time.tv_usec/1000000 - rtt_base - 
219             hostinfo->header->transaction_id/1000;
220           /* Using algorithm described in Stevens' 
221              Unix Network Programming */
222           delta = rtt - srtt;
223           srtt += delta / 8;
224           if(delta < 0.0) delta = - delta;
225           rttvar += (delta - rttvar) / 4 ;
226                 python_hostinfo(dest_sockaddr.sin_addr, hostinfo, nInfo, pos);
227                 pos ++;
228                 
229         };
230         free(hostinfo);
231   };
232
233   FD_ZERO(fdsr);
234   FD_SET(sock, fdsr);           
235
236       /* check if send_interval time passed since last send */
237       gettimeofday(&current_time, NULL);
238       timersub(&current_time, &last_send_time, &diff_time);
239       send_ok = timercmp(&diff_time, &send_interval, >=);
240                         
241                 
242       if(more_to_send && FD_ISSET(sock, fdsw) && send_ok) {
243         if(targetlist) {
244           if(fgets(str, 80, targetlist)) {
245             if(!inet_aton(str, next_in_addr)) {
246             /* if(!inet_pton(AF_INET, str, next_in_addr)) { */
247               fprintf(stderr,"%s - bad IP address\n", str);
248             } else {
249               if(!in_list(scanned, ntohl(next_in_addr->s_addr))) 
250                 send_query(sock, *next_in_addr, rtt_base);
251             }
252           } else {
253             if(feof(targetlist)) {
254               more_to_send=0; 
255               FD_ZERO(fdsw);
256               /* timeout is in milliseconds */
257               select_timeout.tv_sec = timeout / 1000;
258               select_timeout.tv_usec = (timeout % 1000) * 1000; /* Microseconds */
259               continue;
260             } else {
261               snprintf(errmsg, 80, "Read failed from file %s", filename);
262               err_die(errmsg, quiet);
263             }
264           }
265         } else if(next_address(&range, prev_in_addr, next_in_addr) ) {
266           if(!in_list(scanned, ntohl(next_in_addr->s_addr))) 
267             send_query(sock, *next_in_addr, rtt_base);
268           prev_in_addr=next_in_addr;
269           /* Update last send time */
270           gettimeofday(&last_send_time, NULL); 
271         } else { /* No more queries to send */
272           more_to_send=0; 
273           FD_ZERO(fdsw);
274           /* timeout is in milliseconds */
275           select_timeout.tv_sec = timeout / 1000;
276           select_timeout.tv_usec = (timeout % 1000) * 1000; /* Microseconds */
277           continue;
278         };
279       };        
280       if(more_to_send) {
281         FD_ZERO(fdsw);
282         FD_SET(sock, fdsw);
283       };
284     };
285
286     if (i>=retransmits) break; /* If we are not going to retransmit
287                                  we can finish right now without waiting */
288
289     rto = (srtt + 4 * rttvar) * (i+1);
290
291     if ( rto < 2.0 ) rto = 2.0;
292     if ( rto > 60.0 ) rto = 60.0;
293     gettimeofday(&now, NULL);
294                 
295     if(now.tv_sec < (transmit_started.tv_sec+rto)) 
296       sleep((transmit_started.tv_sec+rto)-now.tv_sec);
297     prev_in_addr = NULL ;
298     more_to_send=1;
299     FD_ZERO(fdsw);
300     FD_SET(sock, fdsw);
301     FD_ZERO(fdsr);
302     FD_SET(sock, fdsr);
303   };
304
305   delete_list(scanned);
306         return 0;
307   exit(0);
308 };
309