Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 3900 → Rev 3901

/branches/network/uspace/srv/net/structures/packet/packet.c
27,7 → 27,7
*/
 
/** @addtogroup net
* @{
* @{
*/
 
/** @file
34,124 → 34,167
*/
 
#include <errno.h>
#include <unistd.h>
#include <malloc.h>
//#include <stdio.h>
#include <string.h>
 
#include <ipc/ipc.h>
#include <sys/mman.h>
 
#include "../../err.h"
 
#include "../generic_field.h"
 
#include "packet_header.h"
#include "packet.h"
 
#define PACKET_MAGIC_VALUE 0x11227788
// TODO power of 2 aritmetic => div and mod speedup?
#define PACKET_MAP_SIZE 100
 
struct packet{
size_t length;
size_t max_prefix;
size_t max_content;
size_t data_start;
size_t data_end;
int magic_value;
};
#define PACKET_MAP_PAGE( packet_id ) ((( packet_id ) - 1 ) / PACKET_MAP_SIZE )
#define PACKET_MAP_INDEX( packet_id ) ((( packet_id ) - 1 ) % PACKET_MAP_SIZE )
 
int packet_is_valid( packet_t packet );
 
packet_t packet_create( size_t max_prefix, size_t max_content, size_t max_sufix ){
size_t length;
packet_t packet;
int packet_destroy( packet_t packet );
 
length = max_prefix + max_content + max_sufix;
packet = ( packet_t ) mmap( NULL, sizeof( struct packet ) + length, PROTO_READ | PROTO_WRITE, MAP_SHARED | MAP_ANONYMOUS, 0, 0 );
if( packet == MAP_FAILED ) return NULL;
packet->length = length;
packet->max_prefix = max_prefix;
packet->max_content = max_content;
packet->data_start = sizeof( struct packet ) + packet->max_prefix;
packet->data_end = packet->data_start;
packet->magic_value = PACKET_MAGIC_VALUE;
return packet;
typedef packet_t packet_map_t[ PACKET_MAP_SIZE ];
typedef packet_map_t * packet_map_ref;
 
GENERIC_FIELD_DECLARE( gpm, packet_map_t );
 
GENERIC_FIELD_IMPLEMENT( gpm, packet_map_t );
 
static struct{
// TODO lock
gpm_t map;
} pm_globals;
 
int packet_destroy( packet_t packet ){
if( ! packet_is_valid( packet )) return EINVAL;
return munmap( packet, packet->length );
}
 
int packet_is_valid( packet_t packet ){
return packet && ( packet->magic_value == PACKET_MAGIC_VALUE );
int pm_init( void ){
return gpm_initialize( & pm_globals.map );
}
 
packet_t packet_copy( packet_t packet ){
packet_t new;
packet_t pm_find( packet_id_t packet_id ){
packet_map_ref map;
 
if( ! packet_is_valid( packet )) return NULL;
new = ( packet_t ) mmap( NULL, packet->length, PROTO_READ | PROTO_WRITE, MAP_SHARED | MAP_ANONYMOUS, 0, 0 );
if( new == MAP_FAILED ) return NULL;
memcpy( new, packet, packet->length );
return new;
if( ! packet_id ) return NULL;
if( packet_id > PACKET_MAP_SIZE * gpm_count( & pm_globals.map )) return NULL;
map = gpm_get_index( & pm_globals.map, PACKET_MAP_PAGE( packet_id ));
if( ! map ) return NULL;
return ( * map )[ PACKET_MAP_INDEX( packet_id ) ];
}
 
int packet_copy_data( packet_t packet, void * data, size_t length ){
if( ! packet_is_valid( packet )) return EINVAL;
if( packet->data_start + length >= (( size_t ) packet ) + packet->length ) return ENOMEM;
memcpy( packet + packet->data_start, data, length );
if( packet->data_start + length > packet->data_end ){
packet->data_end = packet->data_start + length;
int pm_add( packet_t packet ){
ERROR_DECLARE;
 
packet_map_ref map;
 
if(( ! packet_is_valid( packet )) || ( gpm_count( & pm_globals.map ) < -1 )) return EINVAL;
if( PACKET_MAP_PAGE( packet->packet_id ) < gpm_count( & pm_globals.map )){
map = gpm_get_index( & pm_globals.map, PACKET_MAP_PAGE( packet->packet_id ));
}else{
do{
map = ( packet_map_ref ) malloc( sizeof( packet_map_t ));
if( ! map ) return ENOMEM;
memset( map, 0, sizeof( packet_map_t ));
if(( ERROR_CODE = gpm_add( & pm_globals.map, map )) < 0 ){
free( map );
return ERROR_CODE;
}
}while( PACKET_MAP_PAGE( packet->packet_id ) >= gpm_count( & pm_globals.map ));
}
( * map )[ PACKET_MAP_INDEX( packet->packet_id ) ] = packet;
return EOK;
}
 
void * packet_prepend( packet_t packet, size_t length ){
if(( ! packet_is_valid( packet )) || ( packet->data_start - sizeof( struct packet ) < length )) return NULL;
packet->data_start -= length;
return packet + packet->data_start;
}
void pm_destroy( void ){
int count;
int index;
packet_map_ref map;
packet_t packet;
 
void * packet_append( packet_t packet, size_t length ){
if(( ! packet_is_valid( packet )) || ( packet->data_end + length >= (( size_t ) packet ) + packet->length )) return NULL;
packet->data_end += length;
return packet + packet->data_end - length;
count = gpm_count( & pm_globals.map );
while( count > 0 ){
map = gpm_get_index( & pm_globals.map, count - 1 );
for( index = PACKET_MAP_SIZE - 1; index >= 0; -- index ){
packet = ( * map )[ index ];
if( packet_is_valid( packet )){
munmap( packet, packet->length );
}
}
}
gpm_destroy( & pm_globals.map );
}
 
int packet_trim( packet_t packet, size_t prefix, size_t sufix ){
if(( ! packet_is_valid( packet )) || ( prefix + sufix > packet->data_end - packet->data_start )) return EINVAL;
packet->data_start += prefix;
packet->data_end -= sufix;
return EOK;
}
packet_t pq_add( packet_t first, packet_t packet, int order, size_t metric ){
packet_t item;
 
int packet_send( packet_t packet, int phone ){
if( ! packet_is_valid( packet )) return EINVAL;
return ipc_share_out_start( phone, packet, PROTO_READ | PROTO_WRITE );
if( ! packet_is_valid( packet )) return NULL;
pq_set( packet, order, metric );
if( packet_is_valid( first )){
item = first;
do{
if( item->order < order ){
if( item->next ){
item = pm_find( item->next );
}else{
item->next = packet->packet_id;
packet->previous = item->packet_id;
return first;
}
}else{
packet->previous = item->previous;
packet->next = item->packet_id;
item->previous = packet->packet_id;
item = pm_find( packet->previous );
if( item ) item->next = packet->packet_id;
return item;
}
}while( packet_is_valid( item ));
}
return packet;
}
 
int packet_receive( packet_ref packet ){
ERROR_DECLARE;
packet_t pq_detach( packet_t packet ){
packet_t next;
packet_t previous;
 
ipc_callid_t callid;
size_t size;
int flags;
 
if( ! packet ) return EINVAL;
if( ! ipc_share_out_receive( & callid, & size, & flags )) return EINVAL;
* packet = ( packet_t ) as_get_mappable_page( size );
if( !( * packet )) return ENOMEM;
if( ERROR_OCCURED( ipc_share_out_finalize( callid, * packet ))){
munmap( * packet, size );
return ERROR_CODE;
if( ! packet_is_valid( packet )) return NULL;
next = pm_find( packet->next );
if( next ){
next->previous = packet->previous;
previous = pm_find( next->previous );
if( previous ){
previous->next = next->packet_id;
}
}
return EOK;
packet->previous = 0;
packet->next = 0;
return next;
}
 
int packet_destroy( packet_t packet ){
int pq_set( packet_t packet, int order, size_t metric ){
if( ! packet_is_valid( packet )) return EINVAL;
return munmap( packet, sizeof( struct packet ) + packet->length );
packet->order = order;
packet->metric = metric;
return EOK;
}
 
size_t packet_get_data_length( packet_t packet ){
if( ! packet_is_valid( packet )) return 0;
return packet->data_end - packet->data_start;
}
void pq_destroy( packet_t first, void ( * packet_release )( packet_t packet )){
packet_t actual;
packet_t next;
 
void * packet_get_data( packet_t packet ){
if( ! packet_is_valid( packet )) return NULL;
return packet + packet->data_start;
actual = first;
while( packet_is_valid( actual )){
next = pm_find( actual->next );
actual->next = 0;
actual->previous = 0;
if( packet_release ) packet_release( actual );
actual = next;
}
}
 
/** @}