plan9fox/sys/src/9/ip/netlog.c
cinap_lenrek 9500191af6 devip: handle malloc errors, fix queue leaks
Fsprotocone():

qopen() and qbypass() can fail and return nil, so make sure
the connection was not partially created by checking if read
and write queues have been setup by the protocol create hanler.
on error, free any resources of the partial connection and
error out.

netlogopen(): check malloc() error.
2013-05-05 03:56:11 +02:00

268 lines
4 KiB
C

#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "../port/error.h"
#include "../ip/ip.h"
enum {
Nlog = 16*1024,
};
/*
* action log
*/
struct Netlog {
Lock;
int opens;
char* buf;
char *end;
char *rptr;
int len;
int logmask; /* mask of things to debug */
uchar iponly[IPaddrlen]; /* ip address to print debugging for */
int iponlyset;
QLock;
Rendez;
};
typedef struct Netlogflag {
char* name;
int mask;
} Netlogflag;
static Netlogflag flags[] =
{
{ "ppp", Logppp, },
{ "ip", Logip, },
{ "fs", Logfs, },
{ "il", Logil, },
{ "tcp", Logtcp, },
{ "icmp", Logicmp, },
{ "udp", Logudp, },
{ "compress", Logcompress, },
{ "logilmsg", Logilmsg, },
{ "gre", Loggre, },
{ "tcpwin", Logtcp|Logtcpwin, },
{ "tcprxmt", Logtcp|Logtcprxmt, },
{ "udpmsg", Logudp|Logudpmsg, },
{ "ipmsg", Logip|Logipmsg, },
{ "esp", Logesp, },
{ nil, 0, },
};
char Ebadnetctl[] = "too few arguments for netlog control message";
enum
{
CMset,
CMclear,
CMonly,
};
static
Cmdtab routecmd[] = {
CMset, "set", 0,
CMclear, "clear", 0,
CMonly, "only", 0,
};
void
netloginit(Fs *f)
{
f->alog = smalloc(sizeof(Netlog));
}
void
netlogopen(Fs *f)
{
lock(f->alog);
if(waserror()){
unlock(f->alog);
nexterror();
}
if(f->alog->opens == 0){
if(f->alog->buf == nil){
f->alog->buf = malloc(Nlog);
if(f->alog->buf == nil)
error(Enomem);
}
f->alog->rptr = f->alog->buf;
f->alog->end = f->alog->buf + Nlog;
}
f->alog->opens++;
unlock(f->alog);
poperror();
}
void
netlogclose(Fs *f)
{
lock(f->alog);
if(waserror()){
unlock(f->alog);
nexterror();
}
f->alog->opens--;
if(f->alog->opens == 0){
free(f->alog->buf);
f->alog->buf = nil;
}
unlock(f->alog);
poperror();
}
static int
netlogready(void *a)
{
Fs *f = a;
return f->alog->len;
}
long
netlogread(Fs *f, void *a, ulong, long n)
{
int i, d;
char *p, *rptr;
qlock(f->alog);
if(waserror()){
qunlock(f->alog);
nexterror();
}
for(;;){
lock(f->alog);
if(f->alog->len){
if(n > f->alog->len)
n = f->alog->len;
d = 0;
rptr = f->alog->rptr;
f->alog->rptr += n;
if(f->alog->rptr >= f->alog->end){
d = f->alog->rptr - f->alog->end;
f->alog->rptr = f->alog->buf + d;
}
f->alog->len -= n;
unlock(f->alog);
i = n-d;
p = a;
memmove(p, rptr, i);
memmove(p+i, f->alog->buf, d);
break;
}
else
unlock(f->alog);
sleep(f->alog, netlogready, f);
}
qunlock(f->alog);
poperror();
return n;
}
void
netlogctl(Fs *f, char* s, int n)
{
int i, set;
Netlogflag *fp;
Cmdbuf *cb;
Cmdtab *ct;
cb = parsecmd(s, n);
if(waserror()){
free(cb);
nexterror();
}
if(cb->nf < 2)
error(Ebadnetctl);
ct = lookupcmd(cb, routecmd, nelem(routecmd));
SET(set);
switch(ct->index){
case CMset:
set = 1;
break;
case CMclear:
set = 0;
break;
case CMonly:
parseip(f->alog->iponly, cb->f[1]);
if(ipcmp(f->alog->iponly, IPnoaddr) == 0)
f->alog->iponlyset = 0;
else
f->alog->iponlyset = 1;
free(cb);
poperror();
return;
default:
cmderror(cb, "unknown ip control message");
}
for(i = 1; i < cb->nf; i++){
for(fp = flags; fp->name; fp++)
if(strcmp(fp->name, cb->f[i]) == 0)
break;
if(fp->name == nil)
continue;
if(set)
f->alog->logmask |= fp->mask;
else
f->alog->logmask &= ~fp->mask;
}
free(cb);
poperror();
}
void
netlog(Fs *f, int mask, char *fmt, ...)
{
char buf[256], *t, *fp;
int i, n;
va_list arg;
if(!(f->alog->logmask & mask))
return;
if(f->alog->opens == 0)
return;
va_start(arg, fmt);
n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
va_end(arg);
lock(f->alog);
i = f->alog->len + n - Nlog;
if(i > 0){
f->alog->len -= i;
f->alog->rptr += i;
if(f->alog->rptr >= f->alog->end)
f->alog->rptr = f->alog->buf + (f->alog->rptr - f->alog->end);
}
t = f->alog->rptr + f->alog->len;
fp = buf;
f->alog->len += n;
while(n-- > 0){
if(t >= f->alog->end)
t = f->alog->buf + (t - f->alog->end);
*t++ = *fp++;
}
unlock(f->alog);
wakeup(f->alog);
}