131921Sbrian/*- 231921Sbrian * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org> 331921Sbrian * All rights reserved. 431921Sbrian * 531921Sbrian * Redistribution and use in source and binary forms, with or without 631921Sbrian * modification, are permitted provided that the following conditions 731921Sbrian * are met: 831921Sbrian * 1. Redistributions of source code must retain the above copyright 931921Sbrian * notice, this list of conditions and the following disclaimer. 1031921Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1131921Sbrian * notice, this list of conditions and the following disclaimer in the 1231921Sbrian * documentation and/or other materials provided with the distribution. 1331921Sbrian * 1431921Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1531921Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1631921Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1731921Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1831921Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1931921Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2031921Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2131921Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2231921Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2331921Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2431921Sbrian * SUCH DAMAGE. 2531921Sbrian * 2650479Speter * $FreeBSD: releng/10.2/usr.sbin/ppp/throughput.c 235822 2012-05-23 06:49:50Z delphij $ 2731272Sbrian */ 2831272Sbrian 2936285Sbrian#include <sys/types.h> 3031272Sbrian 31102500Sbrian#include <stdarg.h> 3231272Sbrian#include <stdio.h> 3349434Sbrian#include <stdlib.h> 3436285Sbrian#include <string.h> 3536285Sbrian#include <termios.h> 3631272Sbrian#include <time.h> 3731272Sbrian 3831343Sbrian#include "log.h" 3931272Sbrian#include "timer.h" 4031272Sbrian#include "throughput.h" 4136285Sbrian#include "descriptor.h" 4236285Sbrian#include "prompt.h" 4331272Sbrian 4464670Sbrian 4531272Sbrianvoid 4649434Sbrianthroughput_init(struct pppThroughput *t, int period) 4731272Sbrian{ 4865178Sbrian t->OctetsIn = t->OctetsOut = t->PacketsIn = t->PacketsOut = 0; 4949434Sbrian t->SamplePeriod = period; 5064670Sbrian t->in.SampleOctets = (long long *) 5164670Sbrian calloc(period, sizeof *t->in.SampleOctets); 5264670Sbrian t->in.OctetsPerSecond = 0; 5364670Sbrian t->out.SampleOctets = (long long *) 5464670Sbrian calloc(period, sizeof *t->out.SampleOctets); 5564670Sbrian t->out.OctetsPerSecond = 0; 5664670Sbrian t->BestOctetsPerSecond = 0; 5749434Sbrian t->nSample = 0; 5849434Sbrian time(&t->BestOctetsPerSecondTime); 5936285Sbrian memset(&t->Timer, '\0', sizeof t->Timer); 6036285Sbrian t->Timer.name = "throughput"; 6136285Sbrian t->uptime = 0; 6249434Sbrian t->downtime = 0; 6336285Sbrian t->rolling = 0; 6449434Sbrian t->callback.data = NULL; 6549434Sbrian t->callback.fn = NULL; 6631272Sbrian throughput_stop(t); 6731272Sbrian} 6831272Sbrian 6931272Sbrianvoid 7049434Sbrianthroughput_destroy(struct pppThroughput *t) 7149434Sbrian{ 7264670Sbrian if (t && t->in.SampleOctets) { 7349434Sbrian throughput_stop(t); 7464670Sbrian free(t->in.SampleOctets); 7564670Sbrian free(t->out.SampleOctets); 7664670Sbrian t->in.SampleOctets = NULL; 7764670Sbrian t->out.SampleOctets = NULL; 7849434Sbrian } 7949434Sbrian} 8049434Sbrian 8149434Sbrianint 8249434Sbrianthroughput_uptime(struct pppThroughput *t) 8349434Sbrian{ 8449434Sbrian time_t downat; 8549434Sbrian 8649434Sbrian downat = t->downtime ? t->downtime : time(NULL); 8749447Sbrian if (t->uptime && downat < t->uptime) { 8849447Sbrian /* Euch ! The clock's gone back ! */ 8998243Sbrian int i; 9098243Sbrian 9149447Sbrian for (i = 0; i < t->SamplePeriod; i++) 9264670Sbrian t->in.SampleOctets[i] = t->out.SampleOctets[i] = 0; 9349447Sbrian t->nSample = 0; 9449447Sbrian t->uptime = downat; 9549447Sbrian } 9649434Sbrian return t->uptime ? downat - t->uptime : 0; 9749434Sbrian} 9849434Sbrian 9949434Sbrianvoid 10036285Sbrianthroughput_disp(struct pppThroughput *t, struct prompt *prompt) 10131272Sbrian{ 10249434Sbrian int secs_up, divisor; 10331272Sbrian 10449434Sbrian secs_up = throughput_uptime(t); 10549434Sbrian prompt_Printf(prompt, "Connect time: %d:%02d:%02d", secs_up / 3600, 10649434Sbrian (secs_up / 60) % 60, secs_up % 60); 10749434Sbrian if (t->downtime) 10849434Sbrian prompt_Printf(prompt, " - down at %s", ctime(&t->downtime)); 10949434Sbrian else 11049434Sbrian prompt_Printf(prompt, "\n"); 11149434Sbrian 11249434Sbrian divisor = secs_up ? secs_up : 1; 11349582Sbrian prompt_Printf(prompt, "%llu octets in, %llu octets out\n", 11436285Sbrian t->OctetsIn, t->OctetsOut); 11565178Sbrian prompt_Printf(prompt, "%llu packets in, %llu packets out\n", 11665178Sbrian t->PacketsIn, t->PacketsOut); 11736285Sbrian if (t->rolling) { 118235822Sdelphij prompt_Printf(prompt, " overall %6llu bytes/sec\n", 11949434Sbrian (t->OctetsIn + t->OctetsOut) / divisor); 120235822Sdelphij prompt_Printf(prompt, " %s %6llu bytes/sec in, %6llu bytes/sec out " 12164670Sbrian "(over the last %d secs)\n", 12264670Sbrian t->downtime ? "average " : "currently", 12364670Sbrian t->in.OctetsPerSecond, t->out.OctetsPerSecond, 12449434Sbrian secs_up > t->SamplePeriod ? t->SamplePeriod : secs_up); 125235822Sdelphij prompt_Printf(prompt, " peak %6llu bytes/sec on %s", 12636819Sbrian t->BestOctetsPerSecond, ctime(&t->BestOctetsPerSecondTime)); 12731272Sbrian } else 12849582Sbrian prompt_Printf(prompt, "Overall %llu bytes/sec\n", 12949434Sbrian (t->OctetsIn + t->OctetsOut) / divisor); 13031272Sbrian} 13131272Sbrian 13231272Sbrian 13331272Sbrianvoid 13431272Sbrianthroughput_log(struct pppThroughput *t, int level, const char *title) 13531272Sbrian{ 13631272Sbrian if (t->uptime) { 13731272Sbrian int secs_up; 13831272Sbrian 13949434Sbrian secs_up = throughput_uptime(t); 14064670Sbrian if (title == NULL) 14164670Sbrian title = ""; 14264670Sbrian log_Printf(level, "%s%sConnect time: %d secs: %llu octets in, %llu octets" 14365178Sbrian " out\n", title, *title ? ": " : "", secs_up, t->OctetsIn, 14465178Sbrian t->OctetsOut); 14594895Sbrian log_Printf(level, "%s%s%llu packets in, %llu packets out\n", 14665178Sbrian title, *title ? ": " : "", t->PacketsIn, t->PacketsOut); 14731272Sbrian if (secs_up == 0) 14831272Sbrian secs_up = 1; 14936285Sbrian if (t->rolling) 15049582Sbrian log_Printf(level, " total %llu bytes/sec, peak %llu bytes/sec on %s", 15149434Sbrian (t->OctetsIn + t->OctetsOut) / secs_up, t->BestOctetsPerSecond, 15249434Sbrian ctime(&t->BestOctetsPerSecondTime)); 15331272Sbrian else 15449582Sbrian log_Printf(level, " total %llu bytes/sec\n", 15549434Sbrian (t->OctetsIn + t->OctetsOut) / secs_up); 15631272Sbrian } 15731272Sbrian} 15831272Sbrian 15931272Sbrianstatic void 16031343Sbrianthroughput_sampler(void *v) 16131272Sbrian{ 16231343Sbrian struct pppThroughput *t = (struct pppThroughput *)v; 16346686Sbrian unsigned long long old; 16449434Sbrian int uptime, divisor; 16564670Sbrian unsigned long long octets; 16631272Sbrian 16736285Sbrian timer_Stop(&t->Timer); 16831272Sbrian 16949434Sbrian uptime = throughput_uptime(t); 17049434Sbrian divisor = uptime < t->SamplePeriod ? uptime + 1 : t->SamplePeriod; 17164670Sbrian 17264670Sbrian old = t->in.SampleOctets[t->nSample]; 17364670Sbrian t->in.SampleOctets[t->nSample] = t->OctetsIn; 17464670Sbrian t->in.OctetsPerSecond = (t->in.SampleOctets[t->nSample] - old) / divisor; 17564670Sbrian 17664670Sbrian old = t->out.SampleOctets[t->nSample]; 17764670Sbrian t->out.SampleOctets[t->nSample] = t->OctetsOut; 17864670Sbrian t->out.OctetsPerSecond = (t->out.SampleOctets[t->nSample] - old) / divisor; 17964670Sbrian 18064670Sbrian octets = t->in.OctetsPerSecond + t->out.OctetsPerSecond; 18164670Sbrian if (t->BestOctetsPerSecond < octets) { 18264670Sbrian t->BestOctetsPerSecond = octets; 18349434Sbrian time(&t->BestOctetsPerSecondTime); 18436819Sbrian } 18564670Sbrian 18649434Sbrian if (++t->nSample == t->SamplePeriod) 18731272Sbrian t->nSample = 0; 18831272Sbrian 18949434Sbrian if (t->callback.fn != NULL && uptime >= t->SamplePeriod) 19049434Sbrian (*t->callback.fn)(t->callback.data); 19149434Sbrian 19236285Sbrian timer_Start(&t->Timer); 19331272Sbrian} 19431272Sbrian 19531272Sbrianvoid 19636285Sbrianthroughput_start(struct pppThroughput *t, const char *name, int rolling) 19731272Sbrian{ 19849434Sbrian int i; 19936285Sbrian timer_Stop(&t->Timer); 20049434Sbrian 20149434Sbrian for (i = 0; i < t->SamplePeriod; i++) 20264670Sbrian t->in.SampleOctets[i] = t->out.SampleOctets[i] = 0; 20349434Sbrian t->nSample = 0; 204212829Sn_hibma t->OctetsIn = t->OctetsOut = t->PacketsIn = t->PacketsOut = 0; 20564670Sbrian t->in.OctetsPerSecond = t->out.OctetsPerSecond = t->BestOctetsPerSecond = 0; 20649434Sbrian time(&t->BestOctetsPerSecondTime); 20749434Sbrian t->downtime = 0; 20849434Sbrian time(&t->uptime); 20949434Sbrian throughput_restart(t, name, rolling); 21049434Sbrian} 21149434Sbrian 21249434Sbrianvoid 21349434Sbrianthroughput_restart(struct pppThroughput *t, const char *name, int rolling) 21449434Sbrian{ 21549434Sbrian timer_Stop(&t->Timer); 21636285Sbrian t->rolling = rolling ? 1 : 0; 21736285Sbrian if (t->rolling) { 21831272Sbrian t->Timer.load = SECTICKS; 21931272Sbrian t->Timer.func = throughput_sampler; 22036285Sbrian t->Timer.name = name; 22131272Sbrian t->Timer.arg = t; 22236285Sbrian timer_Start(&t->Timer); 22349434Sbrian } else { 22449434Sbrian t->Timer.load = 0; 22549434Sbrian t->Timer.func = NULL; 22649434Sbrian t->Timer.name = NULL; 22749434Sbrian t->Timer.arg = NULL; 22831272Sbrian } 22931272Sbrian} 23031272Sbrian 23131272Sbrianvoid 23231272Sbrianthroughput_stop(struct pppThroughput *t) 23331272Sbrian{ 23449434Sbrian if (t->Timer.state != TIMER_STOPPED) 23549434Sbrian time(&t->downtime); 23636285Sbrian timer_Stop(&t->Timer); 23731272Sbrian} 23831272Sbrian 23931272Sbrianvoid 24046686Sbrianthroughput_addin(struct pppThroughput *t, long long n) 24131272Sbrian{ 24231272Sbrian t->OctetsIn += n; 24365178Sbrian t->PacketsIn++; 24431272Sbrian} 24531272Sbrian 24631272Sbrianvoid 24746686Sbrianthroughput_addout(struct pppThroughput *t, long long n) 24831272Sbrian{ 24931272Sbrian t->OctetsOut += n; 25065178Sbrian t->PacketsOut++; 25131272Sbrian} 25236934Sbrian 25336934Sbrianvoid 25436934Sbrianthroughput_clear(struct pppThroughput *t, int clear_type, struct prompt *prompt) 25536934Sbrian{ 25636934Sbrian if (clear_type & (THROUGHPUT_OVERALL|THROUGHPUT_CURRENT)) { 25736934Sbrian int i; 25836934Sbrian 25949434Sbrian for (i = 0; i < t->SamplePeriod; i++) 26064670Sbrian t->in.SampleOctets[i] = t->out.SampleOctets[i] = 0; 26136934Sbrian t->nSample = 0; 26236934Sbrian } 26336934Sbrian 26436934Sbrian if (clear_type & THROUGHPUT_OVERALL) { 26549434Sbrian int divisor; 26636934Sbrian 26749434Sbrian if ((divisor = throughput_uptime(t)) == 0) 26849434Sbrian divisor = 1; 269235822Sdelphij prompt_Printf(prompt, "overall cleared (was %6llu bytes/sec)\n", 27049434Sbrian (t->OctetsIn + t->OctetsOut) / divisor); 271212829Sn_hibma t->OctetsIn = t->OctetsOut = t->PacketsIn = t->PacketsOut = 0; 27249434Sbrian t->downtime = 0; 27349434Sbrian time(&t->uptime); 27498243Sbrian } 27536934Sbrian 27636934Sbrian if (clear_type & THROUGHPUT_CURRENT) { 277235822Sdelphij prompt_Printf(prompt, "current cleared (was %6llu bytes/sec in," 278235822Sdelphij " %6llu bytes/sec out)\n", 27964670Sbrian t->in.OctetsPerSecond, t->out.OctetsPerSecond); 28064670Sbrian t->in.OctetsPerSecond = t->out.OctetsPerSecond = 0; 28136934Sbrian } 28236934Sbrian 28336934Sbrian if (clear_type & THROUGHPUT_PEAK) { 28436934Sbrian char *time_buf, *last; 28536934Sbrian 28636934Sbrian time_buf = ctime(&t->BestOctetsPerSecondTime); 28736934Sbrian last = time_buf + strlen(time_buf); 28836934Sbrian if (last > time_buf && *--last == '\n') 28936934Sbrian *last = '\0'; 290235822Sdelphij prompt_Printf(prompt, "peak cleared (was %6llu bytes/sec on %s)\n", 29198243Sbrian t->BestOctetsPerSecond, time_buf); 29236934Sbrian t->BestOctetsPerSecond = 0; 29349434Sbrian time(&t->BestOctetsPerSecondTime); 29436934Sbrian } 29536934Sbrian} 29649434Sbrian 29749434Sbrianvoid 29849434Sbrianthroughput_callback(struct pppThroughput *t, void (*fn)(void *), void *data) 29949434Sbrian{ 30049434Sbrian t->callback.fn = fn; 30149434Sbrian t->callback.data = data; 30249434Sbrian} 303