2 * jnettop, network online traffic visualiser
3 * Copyright (C) 2002-2006 Jakub Skopal
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "jprocessor.h"
28 #include "juiadisplay.h"
32 #define LISTEN_ERROR_ANSWER "listen:ASCII:NAK:Error compiling rule: syntax error\n\n"
33 #define ERROR_MAXIMUM_TIMEOUT_EXPIRED "\n\n"
34 #define GET_REQUEST_END_BOUNDARY "\n"
37 #define MAX_COMMAND_TIMEOUT_MINUTES 5
38 #define SMALL_WAIT 100
39 #define DEFAULT_LINE_COUNT 15
41 GMutex
*displayStreamsMutex
;
42 jbase_stream
**displayStreams
= NULL
;
43 int displayStreamsCount
= 0;
44 gboolean bHaveData
= FALSE
;
45 int nLineCount
= DEFAULT_LINE_COUNT
;
47 gboolean onoffPackets
;
48 gboolean onoffBitValues
;
50 static void processStreamsFunc(GPtrArray
* streamArray
) {
52 guint lines
, oldLines
;
53 jbase_stream
**streams
,**oldStreams
;
55 streams
= g_new0(jbase_stream
*, nLineCount
);
57 for (i
=0,j
=0; i
<streamArray
->len
&& j
<nLineCount
; i
++) {
58 jbase_stream
*s
= (jbase_stream
*)g_ptr_array_index(streamArray
, i
);
68 g_mutex_lock(displayStreamsMutex
);
71 oldStreams
= displayStreams
;
72 oldLines
= displayStreamsCount
;
73 displayStreams
= streams
;
74 displayStreamsCount
= lines
;
75 g_mutex_unlock(displayStreamsMutex
);
77 for (i
=0; i
<oldLines
; i
++) {
78 oldStreams
[i
]->displayed
--;
85 static gchar
* get_next_token_colon_delim(gchar
** text
){
90 tmp
= strsep(text
, ":");
91 if(tmp
&& *tmp
!= '\0'){
98 void doWriteFormatedNetworkStreams(pid_t nSessionID
, gulong lUSecsWaited
) {
101 gchar srcport
[10], dstport
[10], srcbps
[10], dstbps
[10], bps
[10];
103 debug(LOG_DEBUG
, "streams count %d", displayStreamsCount
);
105 // dump out the totals line...
106 jutil_formatNumber(onoffPackets
?jprocessor_Stats
.totalPPS
:(onoffBitValues
?8:1)*jprocessor_Stats
.totalBPS
, onoffPackets
, bps
, 6);
107 g_strlcat(bps
, "/s", sizeof(bps
));
108 jutil_formatNumber(onoffPackets
?jprocessor_Stats
.totalSrcPPS
:(onoffBitValues
?8:1)*jprocessor_Stats
.totalSrcBPS
, onoffPackets
, srcbps
, 6);
109 g_strlcat(srcbps
, "/s", sizeof(srcbps
));
110 jutil_formatNumber(onoffPackets
?jprocessor_Stats
.totalDstPPS
:(onoffBitValues
?8:1)*jprocessor_Stats
.totalDstBPS
, onoffPackets
, dstbps
, 6);
111 g_strlcat(dstbps
, "/s", sizeof(dstbps
));
113 sprintf(buffer
, "get:ASCII:%d:%d:ACK:TOTAL:::::%s:%s:%s\n", nSessionID
, (int)lUSecsWaited
, srcbps
, dstbps
, bps
);
114 //debug(LOG_DEBUG, "sending %d characters '%s'", strlen(buffer), buffer);
115 printf("%s", buffer
);
117 for (i
=0; i
< displayStreamsCount
; i
++) {
118 gchar srcaddr
[INET6_ADDRSTRLEN
+ 1], dstaddr
[INET6_ADDRSTRLEN
+ 1];
119 gchar total
[10], totalsrc
[10], totaldst
[10];
121 gchar linebuffer
[1024];
122 const gchar
*psrcaddr
, *pdstaddr
;
123 jbase_stream
*s
= displayStreams
[i
];
124 tmp
= onoffPackets
? s
->totalpps
: (onoffBitValues
?8:1)*s
->totalbps
;
125 jutil_formatNumber(tmp
, onoffPackets
, bps
, 6);
126 g_strlcat(bps
, "/s", sizeof(bps
));
127 tmp
= onoffPackets
? s
->srcpps
: (onoffBitValues
?8:1)*s
->srcbps
;
128 jutil_formatNumber(tmp
, onoffPackets
, srcbps
, 6);
129 g_strlcat(srcbps
, "/s", sizeof(srcbps
));
130 tmp
= onoffPackets
? s
->dstpps
: (onoffBitValues
?8:1)*s
->dstbps
;
131 jutil_formatNumber(tmp
, onoffPackets
, dstbps
, 6);
132 g_strlcat(dstbps
, "/s", sizeof(dstbps
));
133 jutil_formatNumber(onoffPackets
? s
->totalpackets
: s
->totalbytes
, onoffPackets
, total
, 6);
134 jutil_formatNumber(onoffPackets
? s
->srcpackets
: s
->srcbytes
, onoffPackets
, totalsrc
, 6);
135 jutil_formatNumber(onoffPackets
? s
->dstpackets
: s
->dstbytes
, onoffPackets
, totaldst
, 6);
136 jutil_Address2String(JBASE_AF(s
->proto
), &s
->src
, srcaddr
, INET6_ADDRSTRLEN
);
137 if (s
->srcresolv
== NULL
|| s
->srcresolv
->name
== NULL
) {
140 psrcaddr
= s
->srcresolv
->name
;
142 jutil_Address2String(JBASE_AF(s
->proto
), &s
->dst
, dstaddr
, INET6_ADDRSTRLEN
);
143 if (s
->dstresolv
== NULL
|| s
->dstresolv
->name
== NULL
) {
146 pdstaddr
= s
->dstresolv
->name
;
148 if (s
->srcport
== -1)
149 strcpy(srcport
, "AGGR.");
151 sprintf(srcport
, "%d", s
->srcport
);
152 if (s
->dstport
== -1)
153 strcpy(dstport
, "AGGR.");
155 sprintf(dstport
, "%d", s
->dstport
);
156 sprintf(linebuffer
, "%s:%s", psrcaddr
, pdstaddr
);
158 sprintf(buffer
, "get:ASCII:%d:%d:ACK:%s:%s:%s:%s:%s:%s:%s:%s\n", nSessionID
, (int)lUSecsWaited
, srcaddr
, srcport
, JBASE_PROTOCOLS
[s
->proto
], dstaddr
, dstport
, srcbps
, dstbps
, bps
);
159 //debug(LOG_DEBUG, "sending %d characters '%s'", strlen(buffer), buffer);
160 printf("%s", buffer
);
162 printf(GET_REQUEST_END_BOUNDARY
);
165 static GTimeVal
timeNow(){
167 g_get_current_time(&timeNow
);
171 static void networkConnectionLoop(){
173 pid_t ourpid
= getpid();
174 gboolean bExit
= FALSE
;
176 // setup timer here...
177 GTimeVal commandTimeout
;
178 g_get_current_time(&commandTimeout
);
180 while(!bExit
&& (timeNow().tv_sec
- commandTimeout
.tv_sec
< MAX_COMMAND_TIMEOUT_MINUTES
* 60)){
181 // make sure we don't block forever...
182 int nSelectReturn
= 0;
185 tm
.tv_sec
= 10; // wait ten seconds...
188 FD_SET(fileno(stdin
), &listenSet
);
190 nSelectReturn
= select(fileno(stdin
)+1, &listenSet
, NULL
, NULL
, &tm
);
192 if(nSelectReturn
> 0){
193 if(FD_ISSET(fileno(stdin
), &listenSet
)){
194 int nDataRecievedCount
= 0;
195 gchar data
[ MAXRECV
+ 1];
196 bzero(data
, MAXRECV
);
197 nDataRecievedCount
= read(fileno(stdin
), data
, MAXRECV
- 2);
199 if(nDataRecievedCount
> 0){
200 gchar
* strPid
= NULL
;
201 gchar
* strType
= NULL
;
202 gchar
* strMethod
= NULL
;
203 gchar
* strMaxWaitUSecs
= NULL
;
204 gchar
* cpdata
= data
;
207 // make sure we end the string...
208 data
[nDataRecievedCount
] = ':';
209 data
[nDataRecievedCount
+ 1] = '\0';
211 // remove any control charaters...
212 for(nIndex
= 0; nIndex
<nDataRecievedCount
; nIndex
++){
213 if(iscntrl(data
[nIndex
])){
214 // this is a control character - change it to a :
219 strMethod
= get_next_token_colon_delim(&cpdata
);
220 strType
= get_next_token_colon_delim(&cpdata
);
221 strPid
= get_next_token_colon_delim(&cpdata
);
222 strMaxWaitUSecs
= get_next_token_colon_delim(&cpdata
);
224 if(strPid
&& ourpid
!= atoi(strPid
)){
225 // error - key id not correct
226 debug(LOG_DEBUG
, "Invalid session - %s given, %d expected", strPid
, ourpid
);
227 printf(LISTEN_ERROR_ANSWER
);
228 }else if(strncmp(strMethod
, "end", strlen("end")) == 0){
229 gchar endAnswer
[16384];
230 g_get_current_time(&commandTimeout
);
231 // recived an end command
232 sprintf(endAnswer
, "end:ASCII:%d:ACK\n\n", ourpid
);
233 debug(LOG_DEBUG
, "Sending '%s'", endAnswer
);
234 printf("%s", endAnswer
);
236 }else if(strncmp(data
, "get", strlen("get")) == 0){
237 gulong lMicroSeconds
= 0;
238 gulong lWaitedSeconds
= 0;
239 g_get_current_time(&commandTimeout
);
240 // see how long we should wait...
243 lMicroSeconds
= atol(strMaxWaitUSecs
);
246 debug(LOG_DEBUG
, "waiting for data - will wait %d useconds", lMicroSeconds
);
247 while(!bHaveData
&& lWaitedSeconds
< lMicroSeconds
){
248 lWaitedSeconds
+= SMALL_WAIT
;
249 g_usleep(SMALL_WAIT
);
252 debug(LOG_DEBUG
, "waited %d useconds - bHaveData - %d", lWaitedSeconds
, bHaveData
);
255 // recieved get request
257 g_mutex_lock(displayStreamsMutex
);
258 doWriteFormatedNetworkStreams(ourpid
, lWaitedSeconds
);
259 g_mutex_unlock(displayStreamsMutex
);
261 debug(LOG_DEBUG
, "Timed out waiting for data - sending '%s'", ERROR_MAXIMUM_TIMEOUT_EXPIRED
);
262 printf(ERROR_MAXIMUM_TIMEOUT_EXPIRED
);
266 } // nDataRecievedCount
270 if(!(timeNow().tv_sec
- commandTimeout
.tv_sec
< MAX_COMMAND_TIMEOUT_MINUTES
* 60)){
271 // send timeout error
272 debug(LOG_WARNING
, "Timed out while waiting for get/end command - waited %d seconds", timeNow().tv_sec
- commandTimeout
.tv_sec
);
273 printf(ERROR_MAXIMUM_TIMEOUT_EXPIRED
);
277 gboolean
parseListenLineAndConfig(){
278 // wait here for a listen command with parameters...
279 gboolean bInitialized
= FALSE
;
281 static gchar data
[ MAXRECV
+ 1];
283 pid_t ourpid
= getpid();
284 gboolean bBitValuesBackup
= onoffBitValues
;
285 GTimeVal commandTimeout
;
287 // backup the device name
288 gchar strDeviceBackup
[30];
289 strDeviceBackup
[0] = '\0';
291 if(jconfig_Settings
.deviceName
)
292 strcpy(strDeviceBackup
, jconfig_Settings
.deviceName
);
295 // setup timer here...
296 g_get_current_time(&commandTimeout
);
299 // keep going while we have not initialized, aren't shutting down, and haven't timed out
300 while(!bInitialized
&& (timeNow().tv_sec
- commandTimeout
.tv_sec
< MAX_COMMAND_TIMEOUT_MINUTES
* 60)){
301 // make sure we don't block forever...
304 int nSelectReturn
= 0;
306 FD_SET(fileno(stdin
), &listenSet
);
307 tm
.tv_sec
= 10; // wait ten seconds...
309 nSelectReturn
= select(fileno(stdin
)+1, &listenSet
, NULL
, NULL
, &tm
);
311 if(nSelectReturn
!= -1){
312 // try to read stdout...
313 if(FD_ISSET(fileno(stdin
), &listenSet
)){
314 int nDataRecievedCount
= read(fileno(stdin
), data
, MAXRECV
- 2);
316 if(nDataRecievedCount
> 0){
318 gchar
* strMethod
= NULL
;
319 gchar
* strType
= NULL
;
320 gchar
* strDevice
= NULL
;
321 gchar
* strBits
= NULL
;
322 gchar
* strFilter
= NULL
;
323 gchar
* strMaxLines
= NULL
;
324 gchar
* cpdata
= data
; //(gchar *) strdup(data);
326 // make sure we end the string...
327 data
[nDataRecievedCount
] = ':';
328 data
[nDataRecievedCount
+1] = '\0';
330 // clear the bpf filter...
331 JCONFIG_BPFFILTERS_SETNONE
;
332 // reset the device name
333 if(strlen(strDeviceBackup
) > 0){
334 strcpy(jconfig_Settings
.deviceName
, strDeviceBackup
);
336 // reset the bit values
337 onoffBitValues
= bBitValuesBackup
;
339 // remove any control charaters...
340 for(nIndex
= 0; nIndex
<nDataRecievedCount
; nIndex
++){
341 if(iscntrl(data
[nIndex
])){
342 // this is a control character - change it to a :
347 strMethod
= get_next_token_colon_delim(&cpdata
);
348 strType
= get_next_token_colon_delim(&cpdata
);
349 strDevice
= get_next_token_colon_delim(&cpdata
);
350 strBits
= get_next_token_colon_delim(&cpdata
);
351 strFilter
= get_next_token_colon_delim(&cpdata
);
352 strMaxLines
= get_next_token_colon_delim(&cpdata
);
354 if(strncmp(strMethod
, "listen", strlen("listen")) == 0){
355 gchar firstAnswer
[16384];
356 int nStrMaxLines
= 0;
357 gboolean bIsRequestGood
= TRUE
;
360 nStrMaxLines
= atoi(strMaxLines
);
362 debug(LOG_DEBUG
, "Got listen request");
363 // got a listen request
368 const char * strFilterResult
= jutil_ValidateBPFFilter(strFilter
);
369 if(!strFilterResult
){
371 JCONFIG_BPFFILTERS_SETSELECTEDFILTER(JCONFIG_BPFFILTERS_LEN
);
372 jconfig_AddBpfFilter("<fromlisten>", strFilter
);
374 debug(LOG_WARNING
, "strFilter is BAD - %s", strFilterResult
);
375 bIsRequestGood
= FALSE
;
376 printf(LISTEN_ERROR_ANSWER
);
381 debug(LOG_DEBUG
, "Setting device name '%s'", strDevice
);
383 jconfig_Settings
.deviceName
= strDevice
;
386 if(strBits
&& strcmp(strBits
, "bits") == 0){
387 debug(LOG_DEBUG
, "Setting bits");
389 onoffBitValues
= TRUE
;
394 if(nStrMaxLines
!= 0)
395 nLineCount
= nStrMaxLines
;
397 sprintf(firstAnswer
, "listen:ASCII:%d:ACK:%s:%s:%s:%s\n\n", ourpid
, strDevice
, strBits
, strFilter
, strMaxLines
);
398 debug(LOG_DEBUG
,"sending '%s'", firstAnswer
);
402 printf(LISTEN_ERROR_ANSWER
);
405 // reset the timeout timer..
406 g_get_current_time(&commandTimeout
);
412 if(!(timeNow().tv_sec
- commandTimeout
.tv_sec
< MAX_COMMAND_TIMEOUT_MINUTES
* 60)){
413 // send timeout error
414 debug(LOG_NOTICE
, "Timed out while waiting for listen command - waited %d seconds", timeNow().tv_sec
- commandTimeout
.tv_sec
);
415 printf(ERROR_MAXIMUM_TIMEOUT_EXPIRED
);fflush(NULL
);
420 static gboolean
juiadisplay_PreSetup() {
421 setvbuf(stdin
, NULL
, _IOLBF
, 0);
422 setvbuf(stdout
, NULL
, _IOLBF
, 0);
423 return parseListenLineAndConfig();
426 static void juiadisplay_Setup() {
427 displayStreamsMutex
= g_mutex_new();
429 jprocessor_SetProcessStreamsFunc((ProcessStreamsFunc
) processStreamsFunc
);
430 onoffBitValues
= FALSE
;
431 onoffPackets
= FALSE
;
434 static gboolean
juiadisplay_PreRunSetup() {
438 static void juiadisplay_PreRun() {
441 static gboolean
juiadisplay_Run() {
442 networkConnectionLoop();
446 static void juiadisplay_Shutdown() {
449 static void juiadisplay_DrawStatus(const gchar
*msg
) {
452 static int juiadisplay_ProcessArgument(const gchar
**arg
, int argc
) {
453 if (!strcmp(*arg
, "-b") || !strcmp(*arg
, "--bit-units")) {
454 onoffBitValues
= TRUE
;
460 jbase_display juiadisplay_Functions
= {
462 juiadisplay_PreSetup
,
464 juiadisplay_PreRunSetup
,
467 juiadisplay_Shutdown
,
468 juiadisplay_DrawStatus
,
469 juiadisplay_ProcessArgument
474 jbase_display juiadisplay_Functions
= { FALSE
};