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; |
} |
} |
|
/** @} |