Files
TAIXIN/sdk/app/spook/pmsg.c

412 lines
10 KiB
C
Raw Normal View History

/*
* Copyright (C) 2004 Nathan Lutchansky <lutchann@litech.org>
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <ctype.h>
//#include "lib/common.h"
//#include "sys_config.h"
#include <log.h>
#include <pmsg.h>
#include "typesdef.h"
#include "osal/string.h"
#if 0
int strcasecmp(const char* str1, const char* str2)
{
while (*str1 != '\0' && *str2 != '\0')
{
if (*str1 != *str2)
{
if (((*str1 > 'a' || *str1 < 'z') && (*str1 - 'a' == *str2 - 'A')) ||
((*str1 > 'A' || *str1 < 'Z') && (*str1 - 'A' == *str2 - 'a')))
{
str1++;
str2++;
}
else
{
break;
}
}
else
{
str1++;
str2++;
}
}
return *str1 - *str2;
}
int strncasecmp(const char* str1, const char* str2, size_t n)
{
while (*str1 != '\0' && *str2 != '\0' && n-- > 1)
{
if (*str1 != *str2)
{
if (((*str1 > 'a' || *str1 < 'z') && (*str1 - 'a' == *str2 - 'A')) ||
((*str1 > 'A' || *str1 < 'Z') && (*str1 - 'A' == *str2 - 'a')))
{
str1++;
str2++;
}
else
{
break;
}
}
else
{
str1++;
str2++;
}
}
if (((*str1 > 'a' || *str1 < 'z') && (*str1 - 'a' == *str2 - 'A')) ||
((*str1 > 'A' || *str1 < 'Z') && (*str1 - 'A' == *str2 - 'a')))
{
return 0;
}
else
{
return *str1 - *str2;
}
}
#endif
char *add_pmsg_string( struct pmsg *msg, char *s )
{
int len = strlen( s ) + 1;
char *p;
if( msg->msg_len + len > msg->max_len ) return NULL;
p = (char *)(msg->msg + msg->msg_len);
msg->msg_len += len;
strcpy( p, s );
return p;
}
static int inline delim( char *d, int len, char term1, char term2 )
{
int s;
for( s = 0; s < len; ++s )
if( d[s] == term1 || d[s] == term2 ||
d[s] == '\r' || d[s] == '\n' )
break;
return s;
}
int parse_pmsg( struct pmsg *msg )
{
int i = 0;
unsigned char *d = msg->msg;
int len = msg->msg_len;
msg->header_count = 0;
/* Was it all whitespace? */
if( len - i < 4 ) return -1;
/* Check for a slash in the first word */
for( i = 0; i < len && d[i] != ' ' && d[i] != '/'; ++i );
if( i == len ) return -1;
/* Responses begin with "PROTO/" */
if( d[i] == '/' )
{
msg->type = PMSG_RESP;
/* The first word is the protocol name and version */
msg->proto_id = (char *)d;
i = delim( (char *)d, len, ' ', 0 );
/* Check for a space following the version number */
if( d[i] != ' ' ) return -1;
d[i++] = 0;
while( i < len && d[i] == ' ' ) ++i;
/* The next word is the 3-digit response code, then a space */
if( len - i < 4 || ! isdigit( d[i] ) || ! isdigit( d[i+1] )
|| ! isdigit( d[i+2] ) || d[i+3] != ' ' )
return -1;
msg->sl.stat.code = atoi( (char *)(d + i) );
i += 4;
while( i < len && d[i] == ' ' ) ++i;
/* The rest of the line is the textual response */
msg->sl.stat.reason = (char *)(d + i);
i += delim( (char *)(d + i), len - i, 0, 0 );
d[i++] = 0;
} else
{
msg->type = PMSG_REQ;
/* The first word is the method */
msg->sl.req.method = (char *)d;
i = delim( (char *)d, len, ' ', 0 );
/* Then a space */
if( i >= len || d[i] != ' ' ) return -1;
d[i++] = 0;
while( i < len && d[i] == ' ' ) ++i;
/* The second word is the URI */
msg->sl.req.uri = (char *)(d + i);
i += delim( (char *)(d + i), len - i, ' ', 0 );
/* Then a space */
if( i >= len || d[i] != ' ' ) return -1;
d[i++] = 0;
while( i < len && d[i] == ' ' ) ++i;
/* The last word is the protocol name and version */
msg->proto_id = (char *)(d + i);
i += delim( (char *)(d + i), len - i, 0, 0 );
d[i++] = 0;
#if 0
if(!strcmp(msg->sl.req.method, "SETID") ||
!strcmp(msg->sl.req.method, "GETID") ||
!strcmp(msg->sl.req.method, "RESET")) {
/* The last word is the protocol name and version */
msg->proto_id = (char *)(d + i);
i += delim( (char *)(d + i), len - i, ' ', 0 );
/* Then a space */
if( i >= len || d[i] != ' ' ) return -1;
d[i++] = 0;
while( i < len && d[i] == ' ' ) ++i;
/* The last word is the essid */
msg->essid = (char *)(d + i);
i += delim( (char *)(d + i), len - i, ' ', 0 );
/* Then a space */
if( i >= len || d[i] != ' ' ) return -1;
d[i++] = 0;
while( i < len && d[i] == ' ' ) ++i;
/* The last word is the password */
msg->password = (char *)(d + i);
i += delim( (char *)(d + i), len - i, ' ', 0 );
/* Then a space */
if( i >= len || d[i] != ' ' ) return -1;
d[i++] = 0;
while( i < len && d[i] == ' ' ) ++i;
/* The last word is the fly_id */
msg->fly_id = (char *)(d + i);
i += delim( (char *)(d + i), len - i, 0, 0 );
d[i++] = 0;
} else {
/* The last word is the protocol name and version */
msg->proto_id = (char *)(d + i);
i += delim( (char *)(d + i), len - i, 0, 0 );
d[i++] = 0;
}
#endif
}
/* Skip any trailing space */
while( i < len && d[i] == ' ' ) ++i;
/* Skip the \r if we didn't kill it already */
if( i < len && d[i] == '\r' ) ++i;
/* We should be at the end of the line now */
if( i >= len || d[i++] != '\n' ) return -1;
/* Now, parse all the header lines */
for(;;)
{
/* There may be a \r here if we're at the end of the headers */
if( i < len && d[i] == '\r' ) ++i;
/* If there's no more data, we're done */
if( i == len ) return len;
/* If there's a newline, we're at the end of the headers */
if( d[i] == '\n' ) return i + 1;
/* XXX headers beginning with whitespace are continuations */
if( d[i] == '\t' || d[i] == ' ' ) return -1;
/* The first thing on the line is the header name */
msg->fields[msg->header_count].name = (char *)(d + i);
/* The name ends with optional spaces then a colon */
i += delim( (char *)(d + i), len - i, ' ', ':' );
if( i >= len ) return -1;
/* If the optional spaces are present, skip them */
if( d[i] == ' ' )
{
d[i++] = 0;
while( i < len && d[i] == ' ' ) ++i;
}
/* Make sure the colon is present */
if( i >= len || d[i] != ':' ) return -1;
d[i++] = 0;
/* Skip any whitespace after the colon */
while( i < len && ( d[i] == ' ' || d[i] == '\t' ) ) ++i;
/* Everything else on the line is the header data */
msg->fields[msg->header_count].value = (char *)(d + i);
i += delim( (char *)(d + i), len - i, 0, 0 );
d[i++] = 0;
/* We should be at the end of the line now */
if( i >= len || d[i++] != '\n' ) return -1;
++msg->header_count;
}
}
char *get_header( struct pmsg *msg, char *name )
{
int i;
for( i = 0; i < msg->header_count; ++i )
if( ! os_strcasecmp( msg->fields[i].name, name ) )
return msg->fields[i].value;
return NULL;
}
int add_header( struct pmsg *msg, char *name, char *value )
{
if( msg->header_count == MAX_FIELDS ) return -1;
/* Put the name and value back-to-back at the end of the message */
msg->fields[msg->header_count].name = add_pmsg_string( msg, name );
if( ! msg->fields[msg->header_count].name ) return -1;
msg->fields[msg->header_count].value = add_pmsg_string( msg, value );
if( ! msg->fields[msg->header_count].value ) return -1;
++msg->header_count;
return 0;
}
int add_header_printf( struct pmsg *msg, char *name, char *fmt, ... )
{
va_list ap;
int len;
/* do the vsnprintf first to clean up the stack */
va_start( ap, fmt );
len = vsnprintf( (char *)(msg->msg + msg->msg_len), msg->max_len - msg->msg_len,
fmt, ap );
va_end( ap );
/* check for errors */
if( msg->header_count == MAX_FIELDS ) return -1;
/* vsnprintf will return the length of the formatted string
* regardless of length, although the actual output may be truncated */
if( msg->msg_len + len >= msg->max_len ) return -1;
msg->fields[msg->header_count].value = (char *)(msg->msg + msg->msg_len);
msg->msg_len += len + 1;
/* add the name */
msg->fields[msg->header_count].name = add_pmsg_string( msg, name );
if( ! msg->fields[msg->header_count].name ) return -1;
++msg->header_count;
return 0;
}
int replace_header( struct pmsg *msg, char *name, char *value )
{
int i;
for( i = 0; i < msg->header_count; ++i )
if( ! strcasecmp( msg->fields[i].name, name ) )
{
/* If we can't reuse the space from the original value,
* we have to allocate space for the new value at the
* end of the message */
if( strlen( msg->fields[i].value ) < strlen( value ) )
{
char *p = add_pmsg_string( msg, value );
if( ! p ) return -1;
msg->fields[i].value = p;
} else strcpy( msg->fields[i].value, value );
return 0;
}
/* It doesn't exist, so we'll insert it as new */
return add_header( msg, name, value );
}
int copy_headers( struct pmsg *dest, struct pmsg *src, char *name )
{
int i, count = 0;
for( i = 0; i < src->header_count; ++i )
if( ! strcasecmp( src->fields[i].name, name ) )
{
add_header( dest, src->fields[i].name,
src->fields[i].value );
++count;
}
return count;
}
#if 0
/* get_param() returns 1 for found, 0 for not found, -1 for error */
int get_param( char *value, char *tag, char *dest, int size )
{
int taglen, i;
char *c;
if( ! value ) return -1;
taglen = strlen( tag );
for( c = value; c; c = strchr( c, ';' ) )
{
++c;
if( ! strncasecmp( c, tag, taglen ) )
{
c += taglen;
if( *c == 0 || *c == ';' ) /* Value-less tag */
{
if( dest && size > 0 ) *dest = 0;
return 1;
} else if( *c == '=' ) /* Tag has an associated value */
{
if( ! dest || size <= 0 ) return 1;
++c;
for( i = 0; *c && *c != ';' && i < size;
++i, ++c )
dest[i] = *c;
if( i == size ) return -1;
dest[i] = 0;
return 1;
} /* Otherwise, it's a false hit */
}
}
return 0;
}
#endif
struct pmsg *new_pmsg( int size )
{
struct pmsg *msg;
void *v;
if( ! ( v = malloc( sizeof( struct pmsg ) + size ) ) )
{
spook_log( SL_ERR, "unable to allocate memory for message" );
return NULL;
}
msg = (struct pmsg *)v;
msg->msg = v + sizeof( struct pmsg );
msg->max_len = size;
msg->msg_len = 0;
msg->header_count = 0;
msg->proto_id = NULL;
//_os_printf("%s malloc:%X\n",__FUNCTION__,msg);
return msg;
}
void free_pmsg( struct pmsg *msg )
{
//_os_printf("%s free:%X\n",__FUNCTION__,msg);
free( msg );
}