-
Notifications
You must be signed in to change notification settings - Fork 0
/
netstatus.c
313 lines (272 loc) · 9.52 KB
/
netstatus.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
/* required for function invocation isspace */
#include <ctype.h>
/* Not in debug mode today
* #define DEBUG
*/
/* required for strtok */
#include <string.h>
#define NETWORK "/proc/net/dev"
#define BACKLOG_THIS_MANY_ITERATIONS 3
#include <string.h>
typedef struct read_stats read_stats;
struct read_stats {
long download_bytes;
long upload_bytes;
char * interface;
};
struct parsing_var {
int lineNumber;
char * curLineBuf;
};
struct transfer_datum {
long upload_bytes;
long download_bytes;
};
const int COUNT_PAST = 1000;
const long READ_BUF_SIZE = 1024;
int counterPasts = 0;
char * curNetStatus (struct transfer_datum * transferStats);
char * beautifyByteCount (long byteCount);
void dumbcopy (char * src, char * dst, long bytes_to_copy);
void dumbprintLong (long argument);
read_stats parseLine (struct parsing_var * parse_vars);
long getDownloadIncrement ( struct transfer_datum * transferStats, int currentOffset, int backlogDepth );
long getUploadIncrement ( struct transfer_datum * transferStats, int currentOffset, int backlogDepth );
char * getNetstatus (struct transfer_datum * transferStats, struct parsing_var parse_vars)
{
FILE *fp = NULL;
long charsRead = 0;
parse_vars.lineNumber = 0;
read_stats curReadStats;
char* curTokEnd = NULL;
char* curTokStart = NULL;
char * returnValue = malloc ( 100);
char* mallocSwap = NULL;
char* readBuf = malloc(READ_BUF_SIZE);
if ( 0 == access( NETWORK , R_OK) )
{
fp = fopen(NETWORK, "r");
parse_vars.lineNumber = 0;
parse_vars.curLineBuf = NULL;
//parse through network stats
while ( 0 < ( charsRead = fread ( readBuf, 1, (size_t) (READ_BUF_SIZE - 1), fp) ) )
{
readBuf[charsRead] = '\0';
curTokStart = readBuf;
transferStats[counterPasts].upload_bytes = 0;
transferStats[counterPasts].download_bytes = 0;
curTokEnd = strchr(readBuf, '\n');
/* check if there is some overlap from a previous iteration */
if(NULL != parse_vars.curLineBuf)
{
/* only do something before the loop, if a token end was found */
if(NULL != curTokEnd)
{
/* allocate memory for a new string containing the overlap buf and the current token
* copy the char sequence from the overlap buf and from the current token to it
* finally free the old memory */
curTokEnd[0] = '\0';
mallocSwap = malloc(strlen(readBuf) + strlen(parse_vars.curLineBuf) + 1);
memcpy(mallocSwap, parse_vars.curLineBuf, strlen(parse_vars.curLineBuf));
memcpy(mallocSwap + strlen(parse_vars.curLineBuf), readBuf, curTokEnd-readBuf);
mallocSwap[strlen(parse_vars.curLineBuf) + (curTokEnd-readBuf)] = '\0';
free(parse_vars.curLineBuf);
parse_vars.curLineBuf = mallocSwap;
/* process line */
if(1 < parse_vars.lineNumber)
{
curReadStats = parseLine(&parse_vars);
transferStats[counterPasts].download_bytes += curReadStats.download_bytes;
transferStats[counterPasts].upload_bytes += curReadStats.upload_bytes;
parse_vars.curLineBuf = NULL;
}
/* count up the counters */
parse_vars.lineNumber++;
curTokStart = curTokEnd + 1;
curTokEnd = strchr(curTokEnd + 1, '\n');
}
}
/* iterate through the tokens in the current read out */
for(; NULL != curTokEnd; curTokEnd = strchr(curTokEnd + 1, '\n'))
{
/* process each found line */
if(1 < parse_vars.lineNumber)
{
curTokEnd[0] = '\0';
parse_vars.curLineBuf = curTokStart;
curReadStats = parseLine(&parse_vars);
transferStats[counterPasts].download_bytes += curReadStats.download_bytes;
transferStats[counterPasts].upload_bytes += curReadStats.upload_bytes;
parse_vars.curLineBuf = NULL;
}
/* count up the counters */
curTokStart = curTokEnd + 1;
parse_vars.lineNumber++;
}
/* process the last token */
if((curTokStart - readBuf) < charsRead)
{
/* if curlineBuf is set, then the loop was not executed, the current read out contains no newline */
if(NULL != parse_vars.curLineBuf)
{
mallocSwap = malloc(charsRead + strlen(parse_vars.curLineBuf) + 1);
memcpy(mallocSwap, parse_vars.curLineBuf, strlen(parse_vars.curLineBuf));
memcpy(mallocSwap + strlen(parse_vars.curLineBuf), readBuf, charsRead);
mallocSwap[strlen(parse_vars.curLineBuf) + charsRead] = '\0';
free(parse_vars.curLineBuf);
parse_vars.curLineBuf = mallocSwap;
/* if curline Buf is not set, put the last token to newly allocated memory */
} else
{
mallocSwap = malloc(strlen(curTokStart));
memcpy(mallocSwap, curTokStart, strlen(curTokStart));
mallocSwap[strlen(curTokStart)] = '\0';
parse_vars.curLineBuf = mallocSwap;
}
}
}
/* proccess last line */
if(NULL != parse_vars.curLineBuf)
{
if(1 < parse_vars.lineNumber)
{
curReadStats = parseLine(&parse_vars);
transferStats[counterPasts].download_bytes += curReadStats.download_bytes;
transferStats[counterPasts].upload_bytes += curReadStats.upload_bytes;
parse_vars.curLineBuf = NULL;
parse_vars.lineNumber++;
}
free(parse_vars.curLineBuf);
}
fclose(fp);
free(readBuf);
char * netstats_string;
netstats_string = curNetStatus (transferStats);
returnValue = netstats_string;
counterPasts = (counterPasts + 1) % COUNT_PAST;
} else
{
fprintf(stderr, "Failed to get network information from \"%s\"\n", NETWORK );
}
return returnValue;
}
char * curNetStatus (struct transfer_datum * transferStats)
{
char * netstats_string = malloc (32);
char * downStr;
char * upStr;
int lookUpThisManyIterations = BACKLOG_THIS_MANY_ITERATIONS;
if ( lookUpThisManyIterations > counterPasts )
{
lookUpThisManyIterations = counterPasts;
}
if ( 0 != counterPasts)
{
downStr = beautifyByteCount ( getDownloadIncrement (transferStats, counterPasts, lookUpThisManyIterations));
upStr = beautifyByteCount ( getUploadIncrement (transferStats, counterPasts, lookUpThisManyIterations));
} else
{
downStr = beautifyByteCount (transferStats[counterPasts].download_bytes);
upStr = beautifyByteCount (transferStats[counterPasts].upload_bytes );
}
sprintf (netstats_string, "%7s | %-7s", downStr, upStr);
free (downStr);
free (upStr);
return netstats_string;
}
char * beautifyByteCount (long byteCount)
{
const char * units [8];
units [0] = "B";
units [1] = "KB";
units [2] = "MB";
units [3] = "GB";
units [4] = "TB";
units [5] = "PB";
units [6] = "EB";
units [7] = "ZB";
long i = 0;
int j = 0;
long dividedByteCount = byteCount;
//maximum length can only be 19 + 1 + 2 + 1= 22
// (size of long + whitespace + unit-characters + terminating null byte
//since the decimal representation of a long does not exceed 19 characters.
//but "better be safe than sorry", so allocate an additional ~30% percent, or additional 7 bytes
char * beautifiedStr = malloc (sizeof(char) * 30);
for (i = 1024; i < byteCount; j++)
{
dividedByteCount = dividedByteCount / 1024;
if ( 7 == j)
{
break;
}
i = i * 1024;
}
sprintf ( beautifiedStr, "%ld ", dividedByteCount );
strcpy ( (char *) ( (int) beautifiedStr + strlen(beautifiedStr)), units[j]);
return beautifiedStr;
}
long getDownloadIncrement ( struct transfer_datum * transferStats, int currentOffset, int backlogDepth )
{
long deltaBytes = 0;
int backlogOffset = (currentOffset % COUNT_PAST) - backlogDepth;
if ( 0 > backlogOffset)
{
backlogOffset = (backlogOffset + COUNT_PAST) % COUNT_PAST;
}
deltaBytes = transferStats[ currentOffset % COUNT_PAST ].download_bytes - transferStats[ backlogOffset ].download_bytes;
return deltaBytes;
}
long getUploadIncrement ( struct transfer_datum * transferStats, int currentOffset, int backlogDepth )
{
long deltaBytes = 0;
int backlogOffset = (currentOffset % COUNT_PAST) - backlogDepth;
if ( 0 > backlogOffset)
{
backlogOffset = (backlogOffset + COUNT_PAST) % COUNT_PAST;
}
deltaBytes = transferStats[ currentOffset % COUNT_PAST ].upload_bytes - transferStats[ backlogOffset ].upload_bytes;
return deltaBytes;
}
void dumbcopy (char * dst, char * src, long bytes_to_copy)
{
long i = 0;
for ( ; i < bytes_to_copy; i ++)
{
dst[i] = src [i];
}
}
long stringAsLong (char *c) {
long returnVal = 0;
sscanf ( c, "%ld", &returnVal);
return returnVal;
}
read_stats parseLine (struct parsing_var * parse_vars)
{
const int DOWNLOAD_BYTES_ROW = 1;
const int UPLOAD_BYTES_ROW = 9;
read_stats updown_values = {-1, -1};
char* curToken = NULL;
char* nextToken = NULL;
/* tokenize curLineBuf */
curToken = strtok_r(parse_vars->curLineBuf, " ", &nextToken);
for(int columnIndex = 0; NULL != curToken; ((++columnIndex) && (curToken = strtok_r(NULL, " ", &nextToken))))
{
/* assign values to struct members */
if(0 == columnIndex)
{
updown_values.interface = malloc(strlen(curToken));
memcpy(updown_values.interface, curToken, strlen(curToken));
} else if(DOWNLOAD_BYTES_ROW == columnIndex)
{
updown_values.download_bytes = stringAsLong(curToken);
} else if(UPLOAD_BYTES_ROW == columnIndex)
{
updown_values.upload_bytes = stringAsLong(curToken);
}
}
return updown_values;
}