⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 monitor.cc

📁 rtpmon-1.0a7.tar.gz for UNIX like
💻 CC
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 1996 The Regents of the University of California. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without written agreement * is hereby granted, provided that the above copyright notice and the * following two paragraphs appear in all copies of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING * OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE * UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * * * $Id: monitor.cc,v 1.24 1997/01/13 23:31:40 aswan Exp $ */#include <stdio.h>#include <stdlib.h>#include <math.h>#include <errno.h>#include <string.h>#include "Tcl.h"//#include "crypt.h"#include "config.h"#include "member.h"#include "rtp.h"#include "monitor.h"#ifndef HAVE_SNPRINTFextern "C" {    int snprintf(char* buf, int s, const char* fmt, ...);}#endif// forget about source if no control message for 6 report intervals#define CTRL_IDLE 6#define HASH(a) ((int)((((a) >> 20) ^ ((a) >> 10) ^ (a)) & (HASH_SIZE-1)))static class MonitorMatcher : public Matcher {  public:    MonitorMatcher() : Matcher("monitor") {}    TclObject* match(const char*) {	return (new Monitor());    }} session_matcher;UpdateTimer::UpdateTimer(Monitor& m) : m_(m), inactive_(1){    Tcl& tcl = Tcl::instance();    const char* bwstr = tcl.attr("sessbw");    bw_ = (bwstr == 0) ? 64. : atof(bwstr);    // Convert session bandwidth from kb/s to bytes/sec (*128)    // and then to control b/w (* 5%)    bw_ *= 128. * .05;}#define TIMER_INTERVAL 2000voidUpdateTimer::timeout() {    // update median    m_.median();    if (--inactive_ == 0) {	int newinterval = m_.CheckActive(bw_);	inactive_ = newinterval / TIMER_INTERVAL;    }    msched(TIMER_INTERVAL);}Monitor::Monitor() : net_(0), nrunt_(0), badversion_(0), badpt_(0),    nmembers_(0),members_(0), senders_(0), last_(0), median_(0),    avgpktsize_(0), bits_(0), sorttype_(SORT_MAX), stat_(0),    thresh_(0), ut_(*this){    pktbuf_ = new u_char[2 * RTP_MTU];    memset((char*)hashtab_, 0, sizeof(hashtab_));    // start the timer firing every 2 seconds    ut_.msched(TIMER_INTERVAL);}Monitor::~Monitor(){    delete pktbuf_;}intMonitor::command(int argc, const char*const* argv){    Tcl& tcl = Tcl::instance();    static char *work;    static int worksize = 0;    if (worksize == 0) {	worksize = 1024;	work = new char[worksize];    }    int size = worksize;    if (argc == 2) {	if (strcmp(argv[1], "clean") == 0) {	    for (Member* m = members_; m != NULL; m = m->next_) {		if (! m->active()) {		    /*		     * remove this member		     */		    Member** p = &hashtab_[HASH(m->srcid())];		    while (*p != m)			p = &(*p)->hlink_;		    *p = (*p)->hlink_;	    		    if (m->sender()) {			p = &senders_;			while (*p != 0 && *p != m)			    p = &(*p)->snext_;			if (*p != 0)			    *p = (*p)->snext_;		    }		    p = &members_;		    while (*p != m)			p = &(*p)->next_;		    if (*p == last_) {			for (Member* t = members_; t != 0; t = t->next_)			    if (t->next_ == 0)				last_ = t;		    }		    *p = (*p)->next_;		    if (median_ == m)			median_ = 0;	/* XXX do something more intelligent */		    delete m;		    --nmembers_;		}		if (m->locked()) {		    for (Member* s = senders_; s != 0; s = s->snext_) {			int n = s->pos();			if ((stat_ == 0 && m->loss(n) < thresh_)			    || (stat_ == 1 && m->filtloss(n) < thresh_)			    || (stat_ == 2 && m->jitter(n) < thresh_))			    m->locked(false);		    }		}	    }	}	if (strcmp(argv[1], "inactive") == 0) {	    Member* m;	    char *p = work;	    *p = 0;	    for (m=members_; m!=NULL; m=m->next_) {		if (! m->active()) {		    strncpy(p, m->name(), size);		    int len = strlen(p);		    size -= len+1;		    p += len;		    *p++ = ' ';		    *p = 0;		    if (size < 2) {			int newsize = worksize << 1;			char* newwork = new char[worksize];			memcpy(newwork, work, worksize);			worksize = newsize;			p = newwork + (p - work);			delete[] work;			work = newwork;		    }		}	    }	    tcl.result(work);	    return(TCL_OK);	}	if (strcmp(argv[1], "listeners") == 0) {	    char *p = work;	    *p = 0;	    for (Member* m=members_; m!=NULL; m=m->next_) {		if (!m->locked())		    continue;		strncpy(p, m->name(), size);		int len = strlen(p);		size -= len+1;		p += len;		*p++ = ' ';		*p = 0;		if (size < 2) {		    int newsize = worksize << 1;		    char* newwork = new char[worksize];		    memcpy(newwork, work, worksize);		    worksize = newsize;		    p = newwork + (p - work);		    delete[] work;		    work = newwork;		}	    }	    tcl.result(work);	    return (TCL_OK);	}	if (strcmp(argv[1], "senders") == 0) {	    char *p = work;	    *p = 0;	    for (Member* s = senders_; s != 0; s = s->snext_) {		strncpy(p, s->name(), size);		int len = strlen(p);		size -= len+1;		p += len;		*p++ = ' ';		*p = 0;		if (size < 2) {		    int newsize = worksize << 1;		    char* newwork = new char[worksize];		    memcpy(newwork, work, worksize);		    worksize = newsize;		    p = newwork + (p - work);		    delete[] work;		    work = newwork;		}	    }	    tcl.result(work);	    return (TCL_OK);	}	if (strcmp(argv[1], "sort") == 0) {	    sort();	    tcl.result("");	    return (TCL_OK);	}	if (strcmp(argv[1], "statnames") == 0) {	    tcl.result("{loss \"Packet Loss\"} {filtlost \"Filtered Packet Loss\"} {jitter \"Delay Jitter\"}");	    return (TCL_OK);	}	if (strcmp(argv[1], "stats") == 0) {	    char* p = work;	    int len = snprintf(p, size, "{\"Bad Version\" %d} {\"Unexpected Payload Type\" %d} {\"Runt Packets\" %d} {\"Average Packet Size\" \"%d bytes\"}", badversion_, badpt_, nrunt_, avgpktsize_);	    tcl.result(work);	    return(TCL_OK);	}    } else if (argc == 3) {	if (strcmp(argv[1], "ignore") == 0) {	    Member* m = (Member*)TclObject::lookup(argv[2]);	    if (!m->sender()) return(TCL_ERROR);	    m->ignore(true);	    Member** p = &senders_;	    while (*p != 0 && *p != m)		p = &(*p)->snext_;	    if (*p != 0)		*p = (*p)->snext_;	    return(TCL_OK);	}	if (strcmp(argv[1], "net") == 0) {	    net((Network*)TclObject::lookup(argv[2]));	    return (TCL_OK);	}   	if (strcmp(argv[1], "sort") == 0) {	    if (strcmp(argv[2], "max") == 0)		sort(SORT_MAX);	    else if (strcmp(argv[2], "avg") == 0)		sort(SORT_AVG);	    else if (strcmp(argv[2], "address") == 0)		sort(SORT_ADDR);	    else {		TclObject* obj = TclObject::lookup(argv[2]);		if (obj != 0) {		    Member* m = (Member*)obj;		    sort(m->pos());		}	    }	    tcl.result("");	    return (TCL_OK);	}	if (strcmp(argv[1], "stat") == 0) {	    int v = atoi(argv[2]);	    if (v < 0 || v > 2)		return(TCL_ERROR);	    stat_ = v;	    Tcl_Interp* interp = Tcl::instance().interp();	    char tmpname[32];	    for (Member* s = members_; s != 0; s = s->next_) {		int n = s->pos();		for (Member* l = members_; l != 0; l = l->next_) {		    sprintf(tmpname, "%s:%s", l->name(), s->name() );		    char val[32];		    switch (stat_) {		      case 0:			sprintf(val, "%d %%", (int)l->loss(n));			break;		      case 1:			sprintf(val, "%d %%", (int)l->filtloss(n));			break;		      case 2:			u_int32_t j = l->jitter(n);			j = (j&0x0ffff) * 1000 > 16;			sprintf(val, "%u ms", j);			break;		    }		    Tcl_SetVar2(interp, "stats", tmpname, val, TCL_GLOBAL_ONLY);		}	    }	    	    tcl.result("");	    return(TCL_OK);	}	if (strcmp(argv[1], "thresh") == 0) {	    int v = atoi(argv[2]);	    // XXX this is ugly; fix it later	    if (stat_ == 2)		thresh_ = (v << 16) / 1000;	    else		thresh_ = v;	    Tcl& tcl = Tcl::instance();	    for (Member* m = members_; m != 0; m = m->next_) {		if (!m->locked()) {		    for (Member* s = senders_; s != 0; s = s->snext_) {			int n = s->pos();			if ((stat_ == 0 && m->loss(n) >= thresh_)			    || (stat_ == 1 && m->filtloss(n) >= thresh_)			    || (stat_ == 2 && m->jitter(n) >= thresh_)) {			    m->locked(true);			    tcl.evalf("new-listener %s", m->name());			}		    }		}	    }	    return (TCL_OK);	}    }    return (TCL_OK);}Member*Monitor::lookup(u_int32_t ssrc, u_int32_t addr){    int h = HASH(ssrc);    Member* m;    for (m = hashtab_[h]; m != NULL; m = m->hlink_) {	if (m->srcid() == ssrc) return m;    }        // if called from parse_rr_records, we don't want to    // create a new entry so just ignore it for now    if (addr == 0) return 0;    m = new Member(ssrc, addr);    m->active(1);    if (members_ == 0) {	m->next_ = 0;	members_ = last_ = m;    } else {	m->next_ = 0;	last_->next_ = m;	last_ = m;    }    m->hlink_ = hashtab_[h];    hashtab_[h] = m;    ++nmembers_;    Tcl_Interp* interp = Tcl::instance().interp();    char tmpname[32], objname[32];    sprintf(tmpname, "#%u", ssrc);    strcpy(objname, m->name());    Tcl_SetVar2(interp, "names", objname, tmpname, TCL_GLOBAL_ONLY);    return m;}intMonitor::getpos(){    for (int i=0; i<32; i++)	if (!((bits_>>i) & 1)) {	    bits_ |= 1<<i;	    return i;	}    return -1;}voidMonitor::freepos(int pos){    bits_ &= ~(1<<pos);}voidMonitor::dispatch(int mask){    u_int32_t src;    int cc = net_->recv(pktbuf_, 2 * RTP_MTU, src);    if (cc <= 0)	return;        rtcphdr* rh = (rtcphdr*) pktbuf_;    if (cc < (int)sizeof(*rh)) {	++nrunt_;	return;    }    /*     * try to filter out junk: first thing in packet must be     * sr, rr or bye & version number must be correct.     */    switch(ntohs(rh->rh_flags) & 0xc0ff) {      case RTP_VERSION << 14 | RTCP_PT_SR:      case RTP_VERSION << 14 | RTCP_PT_RR:      case RTP_VERSION << 14 | RTCP_PT_BYE:	break;	      default:	u_short flags = ntohs(rh->rh_flags);	if ((flags>>14)&3 != RTP_VERSION)	    ++badversion_;	else	    ++badpt_;	return;    }    // update average packet size    avgpktsize_ += (cc - avgpktsize_) >> 4;    u_int32_t ssrc = rh->rh_ssrc;    Member *m = lookup(ssrc, src);    m->active(1);    /*     * Outer loop parses multiple RTCP records of a "compound packet".     * There is no framing between records.  Boundaries are implicit     * and the overall length comes from UDP.     */    u_char* epack = (u_char*)rh + cc;    while ((u_char*)rh < epack) {	u_int len = (ntohs(rh->rh_len) << 2) + 4;	u_char* ep = (u_char*)rh + len;	if (ep > epack) {	    m->badlen(1);	    return;	}	u_int flags = ntohs(rh->rh_flags);	if (flags >> 14 != RTP_VERSION) {	    m->badver(1);	    return;	}	switch (flags & 0xff) {	  case RTCP_PT_SR:	    parse_sr(rh, flags, ep, m, src);	    break;	  case RTCP_PT_RR:	    parse_rr(rh, flags, ep, m, src);	    break;	  case RTCP_PT_SDES:	    parse_sdes(rh, flags, ep, m, ssrc, src);	    break;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -