Add xprintf() extensible stream formatter

Use it to replace open_memstream(3) in logServalPacket() -- not available on
Mac OS X
This commit is contained in:
Andrew Bettison 2012-08-03 16:44:05 +09:30
parent 4f9abdeb86
commit 03da89225d
7 changed files with 337 additions and 148 deletions

View File

@ -16,6 +16,7 @@ SERVALD_SRC_FILES = \
serval-dna/commandline.c \
serval-dna/conf.c \
serval-dna/dataformats.c \
serval-dna/xprintf.c \
serval-dna/log.c \
serval-dna/net.c \
serval-dna/mkdir.c \

View File

@ -55,7 +55,8 @@ SRCS= \
srandomdev.c \
strbuf.c \
strbuf_helpers.c \
vomp.c
vomp.c \
xprintf.c
MONITORCLIENTSRCS=conf.c \
log.c \
@ -84,6 +85,7 @@ HDRS= fifo.h \
sha2.h \
conf.h \
log.h \
xprintf.h \
constants.h \
monitor-client.h \
sqlite-amalgamation-3070900/sqlite3.h

View File

@ -1032,19 +1032,13 @@ long long parse_quantity(char *q)
void logServalPacket(int level, const char *file, unsigned int line, const char *function, const char *message, const unsigned char *packet, size_t len)
{
char *buffer = NULL;
size_t size = 0;
FILE *m = open_memstream(&buffer, &size);
if (m == NULL) {
WHY_perror("open_memstream");
return;
}
if (serval_packetvisualise(m, message, packet, len) == -1)
struct mallocbuf mb = STRUCT_MALLOCBUF_NULL;
if (serval_packetvisualise(XPRINTF_MALLOCBUF(&mb), message, packet, len) == -1)
WHY("serval_packetvisualise() failed");
if (fclose(m) == EOF)
WHY_perror("fclose");
else if (mb.buffer == NULL)
WHY("serval_packetvisualise() output buffer missing");
else
logString(level, file, line, function, buffer);
if (buffer)
free(buffer);
logString(level, file, line, function, mb.buffer);
if (mb.buffer)
free(mb.buffer);
}

View File

@ -109,10 +109,10 @@ struct in_addr {
#include <sys/stat.h>
#include "constants.h"
#include "xprintf.h"
#include "log.h"
#include "conf.h"
/* bzero(3) is deprecated in favour of memset(3). */
#define bzero(addr,len) memset((addr), 0, (len))
@ -801,7 +801,7 @@ int overlay_saw_mdp_containing_frame(overlay_frame *f,long long now);
#include "nacl.h"
int serval_packetvisualise(FILE *f, const char *message, const unsigned char *packet, size_t len);
int serval_packetvisualise(XPRINTF xpf, const char *message, const unsigned char *packet, size_t len);
int overlay_broadcast_drop_check(unsigned char *a);
int overlay_address_is_broadcast(unsigned char *a);

View File

@ -18,10 +18,10 @@ You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include "xprintf.h"
#define MAX_SPACES 120
const char *spaces=" "" "" "" "
@ -34,9 +34,10 @@ const char *indent(int n)
int senderSet=0;
unsigned char senderAddress[32];
static void _dump(FILE *f, const unsigned char *data, size_t len, size_t ofs, const char *fmt, ...);
static void _dump(XPRINTF xpf, const unsigned char *data, size_t len, size_t ofs, const char *fmt, ...);
#ifdef STANDALONE
int main(int argc,char **argv)
{
int i,n;
@ -48,35 +49,35 @@ int main(int argc,char **argv)
int i;
len=random()%8192;
for(i=0;i<len;i++) buff[i]=random()&0xff;
serval_packetvisualise(stdout,"Fuzz Test",buff,len);
serval_packetvisualise(XPRINTF_STDIO(stdout), "Fuzz Test", buff, len);
}
return 0;
}
#endif
int serval_packetvisualise_renderaddress(FILE *f, const unsigned char *packet, size_t *ofs, int senderP)
int serval_packetvisualise_renderaddress(XPRINTF xpf, const unsigned char *packet, size_t *ofs, int senderP)
{
switch(packet[*ofs]) {
case 0x00: /* ourself */
if (senderSet) {
int i;
for(i=0;i<senderSet;i++) fprintf(f,"%02X",senderAddress[i]);
if (senderSet<32) fprintf(f,"*");
fprintf(f," <same as sender's address>");
for(i=0;i<senderSet;i++) xprintf(xpf,"%02X",senderAddress[i]);
if (senderSet<32) xprintf(xpf,"*");
xprintf(xpf," <same as sender's address>");
} else {
fprintf(f," <WARNING: self-reference to sender's address>");
xprintf(xpf," <WARNING: self-reference to sender's address>");
}
(*ofs)++;
break;
case 0x01: /* by index */
fprintf(f,"<address associated with index #%02x by sender>",
xprintf(xpf,"<address associated with index #%02x by sender>",
packet[(*ofs)+1]);
(*ofs)+=2;
break;
case 0x03: /* previously used address */
fprintf(f,"<same as previous address>");
xprintf(xpf,"<same as previous address>");
(*ofs)++;
break;
case 0x09: /* prefix 3 bytes and assign index */
@ -84,11 +85,11 @@ int serval_packetvisualise_renderaddress(FILE *f, const unsigned char *packet, s
{ int skip=0;
if (packet[*ofs]&8) skip=1;
(*ofs)++;
fprintf(f,"%02X%02X%02X* <24 bit prefix",
xprintf(xpf,"%02X%02X%02X* <24 bit prefix",
packet[(*ofs)],packet[(*ofs)+1],packet[(*ofs)+2]);
if (senderP) bcopy(&packet[*ofs],senderAddress,3); senderSet=3;
if (skip) fprintf(f," assigned index 0x%02x",packet[(*ofs)+3]);
fprintf(f,">");
if (skip) xprintf(xpf," assigned index 0x%02x",packet[(*ofs)+3]);
xprintf(xpf,">");
(*ofs)+=3+skip;
}
break;
@ -97,18 +98,18 @@ int serval_packetvisualise_renderaddress(FILE *f, const unsigned char *packet, s
{ int skip=0;
if (packet[*ofs]&8) skip=1;
(*ofs)++;
fprintf(f,"%02X%02X%02X%02X%02X%02X%02X* <56 bit prefix",
xprintf(xpf,"%02X%02X%02X%02X%02X%02X%02X* <56 bit prefix",
packet[(*ofs)],packet[(*ofs)+1],packet[(*ofs)+2],packet[(*ofs)+3],
packet[(*ofs)+4],packet[(*ofs)+5],packet[(*ofs)+6]);
if (senderP) bcopy(&packet[*ofs],senderAddress,7); senderSet=7;
if (skip) fprintf(f," assigned index 0x%02x",packet[(*ofs)+7]);
fprintf(f,">");
if (skip) xprintf(xpf," assigned index 0x%02x",packet[(*ofs)+7]);
xprintf(xpf,">");
(*ofs)+=7+skip;
}
break;
case 0x07: /* prefix 11 bytes */
(*ofs)++;
fprintf(f,"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X* <88 bit prefix>",
xprintf(xpf,"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X* <88 bit prefix>",
packet[(*ofs)],packet[(*ofs)+1],packet[(*ofs)+2],packet[(*ofs)+3],
packet[(*ofs)+4],packet[(*ofs)+5],packet[(*ofs)+6],packet[(*ofs)+7],
packet[(*ofs)+8],packet[(*ofs)+9],packet[(*ofs)+10]);
@ -119,10 +120,10 @@ int serval_packetvisualise_renderaddress(FILE *f, const unsigned char *packet, s
{
int i;
(*ofs)++;
fprintf(f,"<broadcast BPI=");
for(i=0;i<8;i++) fprintf(f,"%02X",packet[(*ofs)+i]);
xprintf(xpf,"<broadcast BPI=");
for(i=0;i<8;i++) xprintf(xpf,"%02X",packet[(*ofs)+i]);
(*ofs)+=8;
fprintf(f,">"); break;
xprintf(xpf,">"); break;
}
case 0x0b: /* prefix 11 bytes and assign index */
case 0x0d: /* prefix 11 bytes and assign 2-byte index */
@ -130,7 +131,7 @@ int serval_packetvisualise_renderaddress(FILE *f, const unsigned char *packet, s
case 0x02: /* reserved */
case 0x04: /* reserved */
case 0x0c: /* reserved */
fprintf(f,"<illegal address token 0x%02x>",packet[(*ofs)]);
xprintf(xpf,"<illegal address token 0x%02x>",packet[(*ofs)]);
return -1;
break;
default:
@ -143,16 +144,16 @@ int serval_packetvisualise_renderaddress(FILE *f, const unsigned char *packet, s
/* naturally presented 32 byte address */
{
int i;
for(i=0;i<32;i++) fprintf(f,"%02x",packet[(*ofs)+i]);
for(i=0;i<32;i++) xprintf(xpf,"%02x",packet[(*ofs)+i]);
if (senderP) bcopy(&packet[*ofs],senderAddress,32); senderSet=32;
}
if (skip) {
fprintf(f," <literal 256 bit address, assigned index 0x");
xprintf(xpf," <literal 256 bit address, assigned index 0x");
int i;
for(i=0;i<skip;i++) fprintf(f,"%02x",packet[(*ofs)+skip]);
fprintf(f,">");
for(i=0;i<skip;i++) xprintf(xpf,"%02x",packet[(*ofs)+skip]);
xprintf(xpf,">");
} else
fprintf(f," <literal 256 bit address>");
xprintf(xpf," <literal 256 bit address>");
(*ofs)+=32+skip;
}
}
@ -160,17 +161,17 @@ int serval_packetvisualise_renderaddress(FILE *f, const unsigned char *packet, s
}
int isOverlayPacket(FILE *f, const unsigned char *packet, size_t *ofs, size_t len)
int isOverlayPacket(XPRINTF xpf, const unsigned char *packet, size_t *ofs, size_t len)
{
if (packet[(*ofs)]!=0x4f) return 0;
if (packet[(*ofs)+1]!=0x10) return 0;
int version = (packet[(*ofs)+2]<<8)+packet[(*ofs)+3];
fprintf(f,"%sServal Overlay Mesh Packet version %d (0x%04x)\n",
xprintf(xpf,"%sServal Overlay Mesh Packet version %d (0x%04x)\n",
indent(4),version,version);
if (version>0x001) {
fprintf(f,"%s WARNING: Packet version is newer than I know about.\n",indent(4));
xprintf(xpf,"%s WARNING: Packet version is newer than I know about.\n",indent(4));
}
(*ofs)+=4;
@ -209,9 +210,9 @@ int isOverlayPacket(FILE *f, const unsigned char *packet, size_t *ofs, size_t le
}
(*ofs)++;
fprintf(f,"%sOverlay Frame at offset 0x%x\n%stype identifier = 0x%x, modifier bits = 0x%x.\n",
xprintf(xpf,"%sOverlay Frame at offset 0x%x\n%stype identifier = 0x%x, modifier bits = 0x%x.\n",
indent(6),frame_ofs,indent(8),frame_type,frame_flags);
fprintf(f,"%sTime-to-live = %d (0x%02x)\n%sframe payload bytes = %d (0x%x).\n",
xprintf(xpf,"%sTime-to-live = %d (0x%02x)\n%sframe payload bytes = %d (0x%x).\n",
indent(8),ttl,ttl,indent(8),rfs,rfs);
/* Assuming that there is no compression or crypto, we just use the plain body
@ -224,66 +225,66 @@ int isOverlayPacket(FILE *f, const unsigned char *packet, size_t *ofs, size_t le
int cantDecodeFrame=0;
int cantDecodeRecipient=0;
int showSignature=0;
fprintf(f,"%sframe is ",indent(8));
xprintf(xpf,"%sframe is ",indent(8));
switch(frame_flags&0x3) {
case 0: fprintf(f,"not compressed"); break;
case 1: fprintf(f,"gzip-compressed"); break;
case 2: fprintf(f,"bzip2-compressed"); break;
case 3: fprintf(f,"marked as compressed using illegal code 0x3");
case 0: xprintf(xpf,"not compressed"); break;
case 1: xprintf(xpf,"gzip-compressed"); break;
case 2: xprintf(xpf,"bzip2-compressed"); break;
case 3: xprintf(xpf,"marked as compressed using illegal code 0x3");
cantDecodeFrame=1;
break;
}
fprintf(f,"\n%sframe is ",indent(8));
xprintf(xpf,"\n%sframe is ",indent(8));
switch(frame_flags&0xc) {
case 0: fprintf(f,"not encrypted"); break;
case 4: fprintf(f,"encrypted using recipients public key (SID)");
case 0: xprintf(xpf,"not encrypted"); break;
case 4: xprintf(xpf,"encrypted using recipients public key (SID)");
cantDecodeFrame=1; break;
case 8: fprintf(f,"signed using senders public signing key (SAS)");
case 8: xprintf(xpf,"signed using senders public signing key (SAS)");
/* This doesn't stop us displaying the frame, as the body is still en claire.
It does mean that we should present the signature block, and not
show the signature as part of the packet body. */
cantDecodeFrame=0;
showSignature=1;
break;
case 0xc: fprintf(f,"authcrypted (encrypted and authenticated) using CryptoBox (SID)");
case 0xc: xprintf(xpf,"authcrypted (encrypted and authenticated) using CryptoBox (SID)");
cantDecodeFrame=1; break;
}
fprintf(f,"\n");
xprintf(xpf,"\n");
if (!cantDecodeRecipient) {
/* Show next-hop, sender and destination addresses */
fprintf(f,"%sFrame next-hop address: ",indent(8));
if (serval_packetvisualise_renderaddress(f,packet,ofs,0))
{ fprintf(f,"\n%sERROR: Cannot decode remainder of frame\n",indent(8));
xprintf(xpf,"%sFrame next-hop address: ",indent(8));
if (serval_packetvisualise_renderaddress(xpf,packet,ofs,0))
{ xprintf(xpf,"\n%sERROR: Cannot decode remainder of frame\n",indent(8));
dumpRaw=1;
goto nextframe;
}
fprintf(f,"\n%sFrame destination address: ",indent(8));
if (serval_packetvisualise_renderaddress(f,packet,ofs,0))
{ fprintf(f,"\n%sERROR: Cannot decode remainder of frame\n",indent(8));
xprintf(xpf,"\n%sFrame destination address: ",indent(8));
if (serval_packetvisualise_renderaddress(xpf,packet,ofs,0))
{ xprintf(xpf,"\n%sERROR: Cannot decode remainder of frame\n",indent(8));
dumpRaw=1;
goto nextframe;
}
fprintf(f,"\n%sFrame source address: ",indent(8));
if (serval_packetvisualise_renderaddress(f,packet,ofs,1))
{ fprintf(f,"\n%sERROR: Cannot decode remainder of frame\n",indent(8));
xprintf(xpf,"\n%sFrame source address: ",indent(8));
if (serval_packetvisualise_renderaddress(xpf,packet,ofs,1))
{ xprintf(xpf,"\n%sERROR: Cannot decode remainder of frame\n",indent(8));
dumpRaw=1;
goto nextframe;
}
fprintf(f,"\n");
fprintf(f,"%sFrame payload begins at offset 0x%x\n",indent(8),*ofs);
xprintf(xpf,"\n");
xprintf(xpf,"%sFrame payload begins at offset 0x%x\n",indent(8),*ofs);
frame=&packet[*ofs];
frame_len=next_frame_ofs-(*ofs);
if (showSignature) frame_len-=64;
frame_ofs=0;
} else {
fprintf(f,"%sWARNING: Cannot decode frame addresses due to encryption.\n",
xprintf(xpf,"%sWARNING: Cannot decode frame addresses due to encryption.\n",
indent(8));
}
if (cantDecodeFrame) {
fprintf(f,"%sWARNING: Cannot decode compressed and/or encrypted frame.\n",indent(8));
_dump(f, frame, frame_len, 0, "%s", indent(10));
xprintf(xpf,"%sWARNING: Cannot decode compressed and/or encrypted frame.\n",indent(8));
_dump(xpf, frame, frame_len, 0, "%s", indent(10));
}
else {
/* Decrypt and/or decompress frame */
@ -293,32 +294,32 @@ int isOverlayPacket(FILE *f, const unsigned char *packet, size_t *ofs, size_t le
{
unsigned long long time;
int i;
fprintf(f,"%sSelf-announcement\n",indent(8));
xprintf(xpf,"%sSelf-announcement\n",indent(8));
time=0; for(i=0;i<4;i++) time=(time<<8)|frame[frame_ofs++];
fprintf(f,"%sStart time: %10lldms (0x%08llx)\n",indent(10),time,time);
xprintf(xpf,"%sStart time: %10lldms (0x%08llx)\n",indent(10),time,time);
time=0; for(i=0;i<4;i++) time=(time<<8)|frame[frame_ofs++];
fprintf(f,"%sEnd time: %10lldms (0x%08llx)\n",indent(10),time,time);
fprintf(f,"%sSender's Interface number: %d\n",indent(10),frame[frame_ofs++]);
xprintf(xpf,"%sEnd time: %10lldms (0x%08llx)\n",indent(10),time,time);
xprintf(xpf,"%sSender's Interface number: %d\n",indent(10),frame[frame_ofs++]);
}
break;
case 0x20: /* self-announce ack */
{
unsigned long long time;
int i;
fprintf(f,"%sACK of self-announce\n",indent(8));
xprintf(xpf,"%sACK of self-announce\n",indent(8));
time=0; for(i=0;i<4;i++) time=(time<<8)|frame[frame_ofs++];
fprintf(f,"%sStart time: %10lldms (0x%08llx)\n",indent(10),time,time);
xprintf(xpf,"%sStart time: %10lldms (0x%08llx)\n",indent(10),time,time);
time=0; for(i=0;i<4;i++) time=(time<<8)|frame[frame_ofs++];
fprintf(f,"%sEnd time: %10lldms (0x%08llx)\n",indent(10),time,time);
xprintf(xpf,"%sEnd time: %10lldms (0x%08llx)\n",indent(10),time,time);
int iface=frame[frame_ofs++];
fprintf(f,"%sSender Interface : %d\n",indent(10),iface);
xprintf(xpf,"%sSender Interface : %d\n",indent(10),iface);
}
break;
case 0x50: /* rhizome advertisement */
{
int i,j,k;
int rhizome_ad_frame_type=frame[0];
fprintf(f,"%sRhizome bundle advertisement frame, version %d\n",indent(8),rhizome_ad_frame_type);
xprintf(xpf,"%sRhizome bundle advertisement frame, version %d\n",indent(8),rhizome_ad_frame_type);
unsigned short int http_port = 0;
i=1;
switch (rhizome_ad_frame_type) {
@ -326,18 +327,18 @@ int isOverlayPacket(FILE *f, const unsigned char *packet, size_t *ofs, size_t le
case 4:
http_port = (frame[i] << 8) + frame[i+1];
i += 2;
fprintf(f,"%sHTTP port = %d\n", indent(8), http_port);
xprintf(xpf,"%sHTTP port = %d\n", indent(8), http_port);
break;
}
switch (rhizome_ad_frame_type) {
case 2:
case 4:
fprintf(f,"%sBundle BAR(s) (i=%d, frame_len=%d):\n", indent(8),i,frame_len);
xprintf(xpf,"%sBundle BAR(s) (i=%d, frame_len=%d):\n", indent(8),i,frame_len);
break;
case 1:
case 3:
/* Frame contains whole manifest(s) */
fprintf(f,"%sBundle Manifest(s) (i=%d, frame_len=%d):\n", indent(8),i,frame_len);
xprintf(xpf,"%sBundle Manifest(s) (i=%d, frame_len=%d):\n", indent(8),i,frame_len);
while(i<frame_len) {
/* Check for end of manifests */
if (frame[i] == 0xff) { i+=1; break; }
@ -345,66 +346,66 @@ int isOverlayPacket(FILE *f, const unsigned char *packet, size_t *ofs, size_t le
int manifest_len=(frame[i]<<8)+frame[i+1];
i+=2;
if (i > frame_len) {
fprintf(f,"%sERROR: Unexpected end of Frame -- skipping rest of frame.\n",indent(10));
xprintf(xpf,"%sERROR: Unexpected end of Frame -- skipping rest of frame.\n",indent(10));
break;
}
if (manifest_len>(frame_len-i)) {
fprintf(f,"%sERROR: Manifest extends for 0x%x bytes, but frame contains only 0x%x more bytes -- skipping rest of frame.\n",indent(10),manifest_len,frame_len-i);
_dump(f, frame, frame_len, 0, "%s", indent(12));
xprintf(xpf,"%sERROR: Manifest extends for 0x%x bytes, but frame contains only 0x%x more bytes -- skipping rest of frame.\n",indent(10),manifest_len,frame_len-i);
_dump(xpf, frame, frame_len, 0, "%s", indent(12));
i=frame_len;
break;
}
/* find manifest self-signature block */
for(j=0;j<manifest_len;j++) if (frame[i+j]==0) { j++; break;}
fprintf(f,"%smanifest id @0x%x-0x%x/0x%x (len=0x%x) (from first signature block) = ",
xprintf(xpf,"%smanifest id @0x%x-0x%x/0x%x (len=0x%x) (from first signature block) = ",
indent(10),i,i+manifest_len-1,frame_len,manifest_len);
for(k=0;k<32;k++) fprintf(f,"%02X",frame[i+j+k+1+64]);
fprintf(f,"\n");
for(k=0;k<32;k++) xprintf(xpf,"%02X",frame[i+j+k+1+64]);
xprintf(xpf,"\n");
/* Print manifest text body */
int column=0;
fprintf(f,"%sManifest variables:\n",indent(12));
xprintf(xpf,"%sManifest variables:\n",indent(12));
for(k=0;k<(j-1);k++) {
if (!column) { fprintf(f,"%s",indent(14)); column=14; }
if (!column) { xprintf(xpf,"%s",indent(14)); column=14; }
switch(frame[i+k]) {
case '\r': /* ignore CR */
case '\n': /* LF */
column=0;
/* fall through */
default:
fprintf(f,"%c",frame[i+k]);
xprintf(xpf,"%c",frame[i+k]);
}
}
/* Print manifest signature blocks */
fprintf(f,"%sManifest signature blocks\n",indent(12));
xprintf(xpf,"%sManifest signature blocks\n",indent(12));
for(;j<manifest_len;)
{
int sigLen=frame[i+j];
switch(sigLen) {
case 0x61: /* cryptosign signature */
fprintf(f,"%sNaCl CryptoSign Generated Signature\n",indent(14));
fprintf(f,"%sPublic key of signatory = ",indent(16));
for(k=0;k<32;k++) fprintf(f,"%02X",frame[i+j+1+64+k]);
fprintf(f,"\n");
fprintf(f,"%sSignature data:",indent(16));
xprintf(xpf,"%sNaCl CryptoSign Generated Signature\n",indent(14));
xprintf(xpf,"%sPublic key of signatory = ",indent(16));
for(k=0;k<32;k++) xprintf(xpf,"%02X",frame[i+j+1+64+k]);
xprintf(xpf,"\n");
xprintf(xpf,"%sSignature data:",indent(16));
for(k=0;k<64;k++)
{
if (!(k&0xf)) fprintf(f,"\n%s",indent(18-1));
fprintf(f," %02X",frame[i+j+1+k]);
if (!(k&0xf)) xprintf(xpf,"\n%s",indent(18-1));
xprintf(xpf," %02X",frame[i+j+1+k]);
}
fprintf(f,"\n");
xprintf(xpf,"\n");
break;
case 0:
sigLen=1;
default:
fprintf(f,"%sUnknown Signature Type 0x%02x\n",indent(14),frame[i+j]);
fprintf(f,"%sSignature data:",indent(16));
xprintf(xpf,"%sUnknown Signature Type 0x%02x\n",indent(14),frame[i+j]);
xprintf(xpf,"%sSignature data:",indent(16));
for(k=0;k<(sigLen-1);k++)
{
if (!(k&0xf)) fprintf(f,"\n%s",indent(18-1));
fprintf(f," %02X",frame[i+j+1+k]);
if (!(k&0xf)) xprintf(xpf,"\n%s",indent(18-1));
xprintf(xpf," %02X",frame[i+j+1+k]);
}
fprintf(f,"\n");
xprintf(xpf,"\n");
break;
}
j+=sigLen;
@ -413,31 +414,31 @@ int isOverlayPacket(FILE *f, const unsigned char *packet, size_t *ofs, size_t le
}
break;
default:
fprintf(f,"%sWARNING: Version is newer than I understand.\n",indent(10));
xprintf(xpf,"%sWARNING: Version is newer than I understand.\n",indent(10));
break;
}
fprintf(f,"%sBundle Advertisement Records (BARs):\n",indent(8));
xprintf(xpf,"%sBundle Advertisement Records (BARs):\n",indent(8));
for(;i<(frame_len-31);i+=32) {
fprintf(f,"%smanifest id = %02X%02X%02X%02X%02X%02X%02X%02X*\n",
xprintf(xpf,"%smanifest id = %02X%02X%02X%02X%02X%02X%02X%02X*\n",
indent(10),frame[i],frame[i+1],frame[i+2],frame[i+3],
frame[i+4],frame[i+5],frame[i+6],frame[i+7]);
unsigned long long manifest_version=0;
for(j=0;j<7;j++) manifest_version=(manifest_version<<8)|frame[i+8+j];
fprintf(f,"%smanifest revision = %lld (0x%llx)\n",
xprintf(xpf,"%smanifest revision = %lld (0x%llx)\n",
indent(12),manifest_version,manifest_version);
fprintf(f,"%smanifest TTL = %d (0x%x)\n",
xprintf(xpf,"%smanifest TTL = %d (0x%x)\n",
indent(12),frame[i+16],frame[i+16]);
unsigned long long file_size=0;
for(j=0;j<6;j++) file_size=(file_size<<8)+frame[i+18+j];
fprintf(f,"%sassociated file size = %lld (0x%llx) bytes\n",
xprintf(xpf,"%sassociated file size = %lld (0x%llx) bytes\n",
indent(12),file_size,file_size);
double lat0=((frame[i+24]<<8)+frame[i+25])*180/65535-90;
double long0=((frame[i+26]<<8)+frame[i+27])*360/65535-180;
double lat1=((frame[i+28]<<8)+frame[i+29])*180/65535-90;
double long1=((frame[i+30]<<8)+frame[i+31])*360/65535-180;
fprintf(f,"%sgeographic extent of relevance (lat,long) = (%.f,%.f) - (%.f,%.f)\n",
xprintf(xpf,"%sgeographic extent of relevance (lat,long) = (%.f,%.f) - (%.f,%.f)\n",
indent(12),lat0,long0,lat1,long1);
}
}
@ -445,9 +446,9 @@ int isOverlayPacket(FILE *f, const unsigned char *packet, size_t *ofs, size_t le
case 0x70: /* node announce */
{
int i;
fprintf(f,"%sNode reachability announcment(s):\n",indent(8));
xprintf(xpf,"%sNode reachability announcment(s):\n",indent(8));
for(i=0;i<frame_len;i+=8)
fprintf(f,"%s %02X%02X%02X%02X%02X%02X* best link score = %d, via %d gateways\n",
xprintf(xpf,"%s %02X%02X%02X%02X%02X%02X* best link score = %d, via %d gateways\n",
indent(10),
frame[i+0],frame[i+1],frame[i+2],frame[i+3],
frame[i+4],frame[i+5],
@ -458,15 +459,15 @@ int isOverlayPacket(FILE *f, const unsigned char *packet, size_t *ofs, size_t le
case 0x30: /* MDP frame */
{
int version=(frame[0]<<8)|(frame[1]);
fprintf(f,"%sMDP frame (version=0x%04x):\n",indent(8),version);
xprintf(xpf,"%sMDP frame (version=0x%04x):\n",indent(8),version);
int src_port=(frame[2]<<24)|(frame[3]<<16)|(frame[4]<<8)|frame[5];
int dst_port=(frame[6]<<24)|(frame[7]<<16)|(frame[8]<<8)|frame[9];
fprintf(f,"%s source port =%-6d (0x%08x)\n",
xprintf(xpf,"%s source port =%-6d (0x%08x)\n",
indent(10),src_port,src_port);
fprintf(f,"%s destination port =%-6d (0x%08x)\n",
xprintf(xpf,"%s destination port =%-6d (0x%08x)\n",
indent(10),dst_port,dst_port);
fprintf(f,"%sMDP Payload:\n",indent(10));
_dump(f, frame + 10, frame_len - 10, 0, "%sframe+", indent(12));
xprintf(xpf,"%sMDP Payload:\n",indent(10));
_dump(xpf, frame + 10, frame_len - 10, 0, "%sframe+", indent(12));
}
break;
case 0x40: /* voice frame */
@ -474,26 +475,26 @@ int isOverlayPacket(FILE *f, const unsigned char *packet, size_t *ofs, size_t le
default:
{
/* Reserved values */
fprintf(f,"%sWARNING: Packet contains reserved/unknown frame type 0x%02x\n", indent(8),frame_type);
_dump(f, frame, frame_len, 0, "%sframe+", indent(10));
xprintf(xpf,"%sWARNING: Packet contains reserved/unknown frame type 0x%02x\n", indent(8),frame_type);
_dump(xpf, frame, frame_len, 0, "%sframe+", indent(10));
}
break;
}
if (showSignature) {
fprintf(f,"%sWARNING: Signature is for display purposes, and has not been verified\n",indent(8));
fprintf(f,"%sFrame signature block (SAS signed):\n",indent(8));
_dump(f, frame + frame_len, len < 64 ? len : 64, 0, "%s" ,indent(10));
xprintf(xpf,"%sWARNING: Signature is for display purposes, and has not been verified\n",indent(8));
xprintf(xpf,"%sFrame signature block (SAS signed):\n",indent(8));
_dump(xpf, frame + frame_len, len < 64 ? len : 64, 0, "%s" ,indent(10));
}
}
nextframe:
if (next_frame_ofs<0) {
fprintf(f,"%sERROR: Cannot continue decoding payload due to previous error(s)\n",indent(6));
xprintf(xpf,"%sERROR: Cannot continue decoding payload due to previous error(s)\n",indent(6));
return 1;
}
if (dumpRaw)
_dump(f, packet, next_frame_ofs, *ofs, "%s", indent(10));
_dump(xpf, packet, next_frame_ofs, *ofs, "%s", indent(10));
(*ofs)=next_frame_ofs;
continue;
}
@ -501,52 +502,50 @@ int isOverlayPacket(FILE *f, const unsigned char *packet, size_t *ofs, size_t le
return 1;
}
int isDNAPacket(FILE *f, const unsigned char *packet, size_t *ofs, size_t len)
int isDNAPacket(XPRINTF xpf, const unsigned char *packet, size_t *ofs, size_t len)
{
return 0;
}
int serval_packetvisualise(FILE *f, const char *message, const unsigned char *packet, size_t len)
int serval_packetvisualise(XPRINTF xpf, const char *message, const unsigned char *packet, size_t len)
{
if (f == NULL)
return -1;
if (message)
fprintf(f, "%s: ",message);
fprintf(f,"Packet body of %d (0x%x) bytes:\n",len,len);
_dump(f, packet, len, 0, " ");
xprintf(xpf, "%s: ",message);
xprintf(xpf,"Packet body of %d (0x%x) bytes:\n",len,len);
_dump(xpf, packet, len, 0, " ");
size_t ofs=0;
fprintf(f," Packet Structure:\n");
if (isOverlayPacket(f,packet,&ofs,len))
xprintf(xpf," Packet Structure:\n");
if (isOverlayPacket(xpf,packet,&ofs,len))
;
else if (isDNAPacket(f,packet,&ofs,len))
else if (isDNAPacket(xpf,packet,&ofs,len))
;
else {
/* Unknown packet type. */
}
if (ofs<len) {
fprintf(f," WARNING: The last %d (0x%x) bytes of the packet were not parsed.\n",len-ofs,len-ofs);
_dump(f, packet, len, ofs, " ");
xprintf(xpf," WARNING: The last %d (0x%x) bytes of the packet were not parsed.\n",len-ofs,len-ofs);
_dump(xpf, packet, len, ofs, " ");
}
return 0;
}
static void _dump(FILE *f, const unsigned char *data, size_t len, size_t ofs, const char *fmt, ...)
static void _dump(XPRINTF xpf, const unsigned char *data, size_t len, size_t ofs, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
int i, j;
for (i = (ofs / 16) * 16; i < len; i += 16) {
vfprintf(f, fmt, ap);
fprintf(f, "%04x:", i);
vxprintf(xpf, fmt, ap);
xprintf(xpf, "%04x:", i);
for (j = 0; j < 16; ++j)
if (i + j >= ofs && i + j < len)
fprintf(f," %02x", data[i+j]);
xprintf(xpf," %02x", data[i+j]);
else
fprintf(f, " ");
fprintf(f, " ");
xprintf(xpf, " ");
xprintf(xpf, " ");
for (j = 0; j < 16 && i + j < len; ++j)
fputc(i + j < ofs ? ' ' : data[i+j] >= ' ' && data[i+j] < 0x7c ? data[i+j] : '.', f);
fputc('\n', f);
xputc(i + j < ofs ? ' ' : data[i+j] >= ' ' && data[i+j] < 0x7c ? data[i+j] : '.', xpf);
xputc('\n', xpf);
}
va_end(ap);
}

91
xprintf.c Normal file
View File

@ -0,0 +1,91 @@
/*
Serval extensible printf.
Copyright (C) 2012 Serval Project Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include "xprintf.h"
void xprintf(XPRINTF xfp, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vxprintf(xfp, fmt, ap);
va_end(ap);
}
void vxprintf(XPRINTF xfp, const char *fmt, va_list ap)
{
(*xfp.func)(xfp.context, fmt, ap);
}
void xputs(const char *str, XPRINTF xpf)
{
xprintf(xpf, "%s", str);
}
void xputc(char c, XPRINTF xpf)
{
xprintf(xpf, "%c", c);
}
void _cx_vprintf_stdio(void *context, const char *fmt, va_list ap)
{
vfprintf((FILE *)context, fmt, ap);
}
static void grow_mallocbuf(struct mallocbuf *mb, size_t extra)
{
size_t newsize = mb->size + extra;
// Round up to nearest multiple of 1024.
newsize = newsize + 1024 - ((newsize - 1) % 1024 + 1);
char *newbuf = realloc(mb->buffer, newsize);
if (newbuf) {
mb->current += newbuf - mb->buffer;
mb->size = newsize;
mb->buffer = newbuf;
}
}
void _cx_vprintf_mallocbuf(void *context, const char *fmt, va_list ap)
{
struct mallocbuf *mb = (struct mallocbuf *) context;
if (mb->buffer == NULL)
grow_mallocbuf(mb, 1024);
if (mb->current) {
if (mb->current + 1 >= mb->buffer + mb->size)
grow_mallocbuf(mb, 1024);
int n = vsnprintf(mb->current, mb->buffer + mb->size - mb->current, fmt, ap);
char *newcurrent = mb->current + n;
char *end = mb->buffer + mb->size;
if (newcurrent < end)
mb->current = newcurrent;
else {
grow_mallocbuf(mb, newcurrent - end + 1);
n = vsnprintf(mb->current, mb->buffer + mb->size - mb->current, fmt, ap);
char *newcurrent = mb->current + n;
char *end = mb->buffer + mb->size;
if (newcurrent < end)
mb->current = newcurrent;
else {
mb->current = mb->buffer + mb->size - 1;
*mb->current = '\0';
}
}
}
}

102
xprintf.h Normal file
View File

@ -0,0 +1,102 @@
/*
Serval extensible printf.
Copyright (C) 2012 Serval Project Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __SERVALD_XPRINTF_H
#define __SERVALD_XPRINTF_H
/* Generalised (extensible) printf framework.
*
* Instead of writing a function to send output to a <stdio.h> FILE stream,
* write it to send output to an extensible stream. Eg, this code:
*
* void print_something(FILE *fp, int something) {
* fprintf(fp, "%d (0x%08X)", something, something);
* }
*
* Becomes:
*
* void print_something(XPRINTF xpf, int something) {
* xprintf(xpf, "%d (0x%08X)", something, something);
* }
*
* Then, instead of writing this:
*
* print_something(stdout, 10);
*
* you write this:
*
* print_something(XPRINTF_STDIO(stdout), 10);
*
* But with the extensible version you can also do this:
*
* struct mallocbuf mb = STRUCT_MALLOCBUF_NULL;
* print_something(XPRINTF_MALLOCBUF(&mb), 10);
* if (mb.buffer)
* puts(mb.buffer);
*
* And this:
*
* void __log_vprintf(int level, const char *fmt, va_list);
*
* void log_vprintf(void *context, const char *fmt, va_list ap) {
* __log_vprintf((int)context, fmt, ap);
* }
*
* print_something(XPRINTF_GEN(log_vprintf, LOG_LEVEL_INFO), 10);
*/
#include <stdarg.h>
typedef void CONTEXT_VPRINTF(void *context, const char *fmt, va_list);
typedef struct _xprintf {
CONTEXT_VPRINTF *func;
void *context;
} XPRINTF;
#define _XPRINTF(F,C) ((XPRINTF){(F),(C)})
void xprintf(XPRINTF xpf, const char *fmt, ...);
void vxprintf(XPRINTF xpf, const char *fmt, va_list);
void xputs(const char *str, XPRINTF xpf);
void xputc(char c, XPRINTF xpf);
#define XPRINTF_GEN(F,C) _XPRINTF((F),(void *)(C))
/* Standard i/o adapter. An XPRINTF constructed with XPRINTF_STDIO(stream)
* will write all its output to stream using fprintf(stream,...).
*/
#define XPRINTF_STDIO(S) _XPRINTF(_cx_vprintf_stdio,(S))
CONTEXT_VPRINTF _cx_vprintf_stdio;
/* Malloc memory buffer adapter. An XPRINTF constructed with
* XPRINTF_MALLOCBUF(&mb) will use realloc() to allocate and grow a memory
* buffer and fill it using sprintf(), always with a nul terminator at the end.
* The caller must free() the buffer after use.
*/
struct mallocbuf {
char *buffer; // Start of buffer, NULL if not allocated yet
char *current; // Current position of terminating nul in buffer
size_t size; // Size of current allocated buffer
};
#define STRUCT_MALLOCBUF_NULL ((struct mallocbuf){NULL,NULL,0})
#define XPRINTF_MALLOCBUF(MB) _XPRINTF(_cx_vprintf_mallocbuf, (MB))
CONTEXT_VPRINTF _cx_vprintf_mallocbuf;
#endif // __SERVALD_XPRINTF_H