/branches/network/uspace/srv/net/tl/udp/udp.c |
---|
43,6 → 43,8 |
#include "../../err.h" |
#include "../../messages.h" |
#include "../../modules.h" |
#include "../../structures/dynamic_fifo.h" |
#include "../../structures/packet/packet_client.h" |
#include "../../include/in.h" |
52,7 → 54,6 |
#include "../../include/ip_protocols.h" |
#include "../../include/socket.h" |
#include "../../include/socket_errno.h" |
//#include "../../include/udp_interface.h" |
#include "../../socket/socket_core.h" |
#include "../../socket/socket_messages.h" |
63,10 → 64,16 |
#include "udp_header.h" |
#include "udp_module.h" |
#define MAX_UDP_FRAGMENT_SIZE 65535 |
int udp_received_msg( device_id_t device_id, packet_t packet, services_t receiver ); |
int udp_process_packet( packet_t packet ); |
int process_client_messages( ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count ); |
int udp_sendto_message( socket_cores_ref local_sockets, int socket_id, void * addr, size_t addrlen, void * data, size_t length, int flags ); |
int socket_get_data( void ** data, size_t * length ); |
int udp_sendto_message( socket_cores_ref local_sockets, int socket_id, void * addr, size_t addrlen, int fragments, int flags ); |
int udp_recvfrom_message( socket_cores_ref local_sockets, int socket_id, int flags ); |
int socket_read_data( void ** data, size_t * length ); |
int socket_read_packet_data( packet_ref packet, size_t prefix, struct sockaddr_in * address_in ); |
int socket_write_data( void * data, size_t data_length ); |
udp_globals_t udp_globals; |
75,7 → 82,6 |
int udp_initialize( async_client_conn_t client_connection ){ |
ERROR_DECLARE; |
udp_globals.port_search_start = 1025; |
udp_globals.ip_phone = ip_bind_service( SERVICE_IP, IPPROTO_UDP, SERVICE_UDP, client_connection, udp_received_msg ); |
if( udp_globals.ip_phone < 0 ){ |
return udp_globals.ip_phone; |
88,13 → 94,84 |
} |
int udp_received_msg( device_id_t device_id, packet_t packet, services_t receiver ){ |
// TODO received |
ERROR_DECLARE; |
if( ERROR_OCCURRED( udp_process_packet( packet ))){ |
pq_release( udp_globals.net_phone, packet_get_id( packet )); |
return ERROR_CODE; |
} |
return EOK; |
} |
int udp_process_packet( packet_t packet ){ |
ERROR_DECLARE; |
uint8_t * src; |
uint8_t * dest; |
int length; |
void * data; |
udp_header_ref header; |
socket_core_ref * socket; |
packet_t next_packet; |
int total_length; |
// uint16_t checksum; |
int fragments; |
packet_t tmp_packet; |
// get packet data |
length = packet_get_addr( packet, & src, & dest ); |
if( length < 0 ) return length; |
if( length != sizeof( in_addr_t )) return EINVAL; |
// TODO received ipopts? |
ERROR_PROPAGATE( ip_client_process_packet( packet, NULL, NULL, NULL, NULL, NULL )); |
// TODO remove debug dump: |
uint8_t * data; |
/* uint8_t * rdata; |
rdata = packet_get_data( packet ); |
printf( "Receiving udp packet:\n\tid\t= %d\n\tlength\t= %d\n\tdata\t= %.2hhX %.2hhX %.2hhX %.2hhX:%.2hhX %.2hhX %.2hhX %.2hhX:%.2hhX %.2hhX %.2hhX %.2hhX:%.2hhX %.2hhX %.2hhX %.2hhX:%.2hhX %.2hhX %.2hhX %.2hhX:%.2hhX %.2hhX\n\t\t%.2hhX %.2hhX:%.2hhX %.2hhX %.2hhX %.2hhX:%.2hhX %.2hhX %.2hhX %.2hhX:%.2hhX %.2hhX %.2hhX %.2hhX:%.2hhX %.2hhX %.2hhX %.2hhX:%.2hhX %.2hhX %.2hhX %.2hhX:%.2hhX %.2hhX %.2hhX %.2hhX:%.2hhX %.2hhX %.2hhX %.2hhX:%.2hhX %.2hhX %.2hhX %.2hhX:%.2hhX %.2hhX %.2hhX %.2hhX\n", packet_get_id( packet ), packet_get_data_length( packet ), rdata[ 0 ], rdata[ 1 ], rdata[ 2 ], rdata[ 3 ], rdata[ 4 ], rdata[ 5 ], rdata[ 6 ], rdata[ 7 ], rdata[ 8 ], rdata[ 9 ], rdata[ 10 ], rdata[ 11 ], rdata[ 12 ], rdata[ 13 ], rdata[ 14 ], rdata[ 15 ], rdata[ 16 ], rdata[ 17 ], rdata[ 18 ], rdata[ 19 ], rdata[ 20 ], rdata[ 21 ], rdata[ 22 ], rdata[ 23 ], rdata[ 24 ], rdata[ 25 ], rdata[ 26 ], rdata[ 27 ], rdata[ 28 ], rdata[ 29 ], rdata[ 30 ], rdata[ 31 ], rdata[ 32 ], rdata[ 33 ], rdata[ 34 ], rdata[ 35 ], rdata[ 36 ], rdata[ 37 ], rdata[ 38 ], rdata[ 39 ], rdata[ 40 ], rdata[ 41 ], rdata[ 42 ], rdata[ 43 ], rdata[ 44 ], rdata[ 45 ], rdata[ 46 ], rdata[ 47 ], rdata[ 48 ], rdata[ 49 ], rdata[ 50 ], rdata[ 51 ], rdata[ 52 ], rdata[ 53 ], rdata[ 54 ], rdata[ 55 ], rdata[ 56 ], rdata[ 57 ], rdata[ 58 ], rdata[ 59 ] ); |
*/ |
length = packet_get_data_length( packet ); |
if( length < 0 ) return length; |
if( length < sizeof( udp_header_t )) return NO_DATA; |
data = packet_get_data( packet ); |
printf( "Receiving packet:\n\tid\t= %d\n\tlength\t= %d\n\tdata\t= %.2hhX %.2hhX %.2hhX %.2hhX:%.2hhX %.2hhX %.2hhX %.2hhX:%.2hhX %.2hhX %.2hhX %.2hhX:%.2hhX %.2hhX %.2hhX %.2hhX:%.2hhX %.2hhX %.2hhX %.2hhX:%.2hhX %.2hhX\n\t\t%.2hhX %.2hhX:%.2hhX %.2hhX %.2hhX %.2hhX:%.2hhX %.2hhX %.2hhX %.2hhX:%.2hhX %.2hhX %.2hhX %.2hhX:%.2hhX %.2hhX %.2hhX %.2hhX:%.2hhX %.2hhX %.2hhX %.2hhX:%.2hhX %.2hhX %.2hhX %.2hhX:%.2hhX %.2hhX %.2hhX %.2hhX:%.2hhX %.2hhX %.2hhX %.2hhX:%.2hhX %.2hhX %.2hhX %.2hhX\n", packet_get_id( packet ), packet_get_data_length( packet ), data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ], data[ 7 ], data[ 8 ], data[ 9 ], data[ 10 ], data[ 11 ], data[ 12 ], data[ 13 ], data[ 14 ], data[ 15 ], data[ 16 ], data[ 17 ], data[ 18 ], data[ 19 ], data[ 20 ], data[ 21 ], data[ 22 ], data[ 23 ], data[ 24 ], data[ 25 ], data[ 26 ], data[ 27 ], data[ 28 ], data[ 29 ], data[ 30 ], data[ 31 ], data[ 32 ], data[ 33 ], data[ 34 ], data[ 35 ], data[ 36 ], data[ 37 ], data[ 38 ], data[ 39 ], data[ 40 ], data[ 41 ], data[ 42 ], data[ 43 ], data[ 44 ], data[ 45 ], data[ 46 ], data[ 47 ], data[ 48 ], data[ 49 ], data[ 50 ], data[ 51 ], data[ 52 ], data[ 53 ], data[ 54 ], data[ 55 ], data[ 56 ], data[ 57 ], data[ 58 ], data[ 59 ] ); |
pq_release( udp_globals.net_phone, packet_get_id( packet )); |
if( ! data ) return NO_DATA; |
// get udp header |
header = ( udp_header_ref ) data; |
// find the destination socket |
socket = socket_ports_find( & udp_globals.sockets, ntohs( header->dest )); |
if( ! socket ) return EADDRNOTAVAIL; |
// count the received packet fragments |
next_packet = packet; |
fragments = 0; |
total_length = ntohs( header->len ); |
do{ |
++ fragments; |
length = packet_get_data_length( packet ); |
if( length < 0 ) return length; |
if( ! length ) return NO_DATA; |
if( total_length < length ){ |
// cut of the suffix if too long |
ERROR_PROPAGATE( packet_trim( next_packet, 0, length - total_length )); |
// relese the rest of the packet fragments |
tmp_packet = pq_next( next_packet ); |
while( tmp_packet ){ |
next_packet = pq_detach( tmp_packet ); |
pq_release( udp_globals.net_phone, packet_get_id( tmp_packet )); |
tmp_packet = next_packet; |
} |
break; |
} |
total_length -= length; |
/* if( header->header_checksum ){ |
} |
*/ |
}while(( next_packet = pq_next( next_packet )) && ( total_length > 0 )); |
// queue the received packet |
ERROR_PROPAGATE( dyn_fifo_push( &( ** socket ).received, packet_get_id( packet ), SOCKET_MAX_RECEIVED_SIZE )); |
// notify the destination socket |
async_msg_2(( ** socket ).phone, NET_SOCKET_RECEIVED, ( ** socket ).socket_id, fragments ); |
return EOK; |
} |
123,8 → 200,6 |
int app_phone = IPC_GET_PHONE( call ); |
void * addr; |
size_t addrlen; |
void * data; |
size_t length; |
/* |
* Accept the connection |
147,7 → 222,7 |
IPC_SET_ARG5( * answer, 0 ); |
callid = async_get_call( call ); |
printf( "message %d\n", IPC_GET_METHOD( * call )); |
// printf( "message %d\n", IPC_GET_METHOD( * call )); |
switch( IPC_GET_METHOD( * call )){ |
case IPC_M_PHONE_HUNGUP: |
155,10 → 230,13 |
res = EOK; |
break; |
case NET_SOCKET: |
res = socket_create( & local_sockets, app_phone ); |
res = socket_create( & local_sockets, app_phone, SOCKET_SET_SOCKET_ID( answer )); |
* SOCKET_SET_HEADER_SIZE( answer ) = sizeof( udp_header_t ); |
* SOCKET_SET_DATA_FRAGMENT_SIZE( answer ) = MAX_UDP_FRAGMENT_SIZE; |
* answer_count = 3; |
break; |
case NET_SOCKET_BIND: |
if( ERROR_OCCURRED( socket_get_data( & addr, & addrlen ))){ |
if( ERROR_OCCURRED( socket_read_data( & addr, & addrlen ))){ |
res = ERROR_CODE; |
break; |
} |
166,22 → 244,20 |
free( addr ); |
break; |
case NET_SOCKET_SENDTO: |
if( ERROR_OCCURRED( socket_get_data( & addr, & addrlen ))){ |
if( ERROR_OCCURRED( socket_read_data( & addr, & addrlen ))){ |
res = ERROR_CODE; |
break; |
} |
if( ERROR_OCCURRED( socket_get_data( & data, & length ))){ |
free( addr ); |
res = ERROR_CODE; |
break; |
} |
res = udp_sendto_message( & local_sockets, SOCKET_GET_SOCKET_ID( call ), addr, addrlen, data, length, SOCKET_GET_FLAGS( call )); |
res = udp_sendto_message( & local_sockets, SOCKET_GET_SOCKET_ID( call ), addr, addrlen, SOCKET_GET_DATA_FRAGMENTS( call ), SOCKET_GET_FLAGS( call )); |
free( addr ); |
free( data ); |
break; |
case NET_SOCKET_RECVFROM: |
// TODO read first received packet queue data continuesly |
res = ENOTSUP; |
res = udp_recvfrom_message( & local_sockets, SOCKET_GET_SOCKET_ID( call ), SOCKET_GET_FLAGS( call )); |
if( res > 0 ){ |
* SOCKET_SET_READ_DATA_LENGTH( answer ) = res; |
* answer_count = 1; |
res = EOK; |
} |
break; |
case NET_SOCKET_CLOSE: |
res = socket_destroy( udp_globals.net_phone, SOCKET_GET_SOCKET_ID( call ), & local_sockets, & udp_globals.sockets ); |
193,8 → 269,7 |
break; |
} |
// TODO debug |
printf( "res = %d\n", res ); |
// printf( "res = %d\n", res ); |
switch( * answer_count ){ |
case 0: ipc_answer_0( callid, res ); |
217,7 → 292,7 |
return EOK; |
} |
int udp_sendto_message( socket_cores_ref local_sockets, int socket_id, void * addr, size_t addrlen, void * data, size_t length, int flags ){ |
int udp_sendto_message( socket_cores_ref local_sockets, int socket_id, void * addr, size_t addrlen, int fragments, int flags ){ |
ERROR_DECLARE; |
socket_core_ref socket; |
224,7 → 299,11 |
struct sockaddr * address; |
struct sockaddr_in * address_in; |
packet_t packet; |
packet_t next_packet; |
udp_header_ref header; |
int index; |
int total_length; |
int length; |
if( addrlen < sizeof( struct sockaddr )) return EINVAL; |
address = ( struct sockaddr * ) addr; |
234,41 → 313,42 |
address_in = ( struct sockaddr_in * ) addr; |
socket = socket_cores_find( local_sockets, socket_id ); |
if( ! socket ) return ENOTSOCK; |
/* if( socket->port < 0 ){ |
return ENOTCONN; |
socket->port = udp_globals.port_search_start; |
while( socket_ports_find( global_sockets, socket->port ) >= 0 ){ |
socket_port = ( socket->port + 1 ) % ( 65535 - 1025 ) + 1025; |
} |
ERROR_PROPAGATE( socket_ports_add( global_sockets, socket->port ); |
udp_globals.port_search_start = socket->port + 1; |
} |
*/ // TODO create and send fragmented packets |
// TODO do not ask all the time |
ERROR_PROPAGATE( ip_packet_size_req( udp_globals.ip_phone, -1, & udp_globals.addr_len, & udp_globals.prefix, & udp_globals.content, & udp_globals.suffix )); |
packet = packet_get_4( udp_globals.net_phone, length, udp_globals.addr_len, udp_globals.prefix, udp_globals.suffix ); |
if( ! packet ) return ENOMEM; |
if( ERROR_OCCURRED( packet_copy_data( packet, data, length )) |
|| ERROR_OCCURRED( packet_set_addr( packet, NULL, ( uint8_t * ) & address_in->sin_addr.s_addr, sizeof( address_in->sin_addr.s_addr )))){ |
pq_release( udp_globals.net_phone, packet_get_id( packet )); |
return ERROR_CODE; |
} |
// read the first packet fragment |
total_length = socket_read_packet_data( & packet, sizeof( udp_header_t ), address_in ); |
if( total_length < 0 ) return total_length; |
// prefix the udp header |
header = PACKET_PREFIX( packet, udp_header_t ); |
if( ! header ){ |
pq_release( udp_globals.net_phone, packet_get_id( packet )); |
return ENOMEM; |
} |
// read the rest of the packet fragments |
for( index = 1; index < fragments; ++ index ){ |
length = socket_read_packet_data( & next_packet, 0, address_in ); |
if( length < 0 ){ |
pq_release( udp_globals.net_phone, packet_get_id( packet )); |
return length; |
} |
packet = pq_add( packet, next_packet, index, 0 ); |
total_length += length; |
} |
// set the udp header |
header->source = ( socket->port < 0 ) ? 0 : htons( socket->port ); |
header->dest = htons( address_in->sin_port ); |
header->len = htons( length ); |
header->len = htons( total_length + sizeof( udp_header_t )); |
// TODO my ip address for the pseudo header checksum |
header->check = 0; |
// prepare the first packet fragment |
if( ERROR_OCCURRED( ip_client_prepare_packet( packet, IPPROTO_UDP, 0, 0, 0, 0 ))){ |
pq_release( udp_globals.net_phone, packet_get_id( packet )); |
return ERROR_CODE; |
} |
// send the packet |
return ip_send_msg( udp_globals.ip_phone, socket->device_id, packet, SERVICE_UDP ); |
break; |
// TODO IPv6 |
default: |
return EAFNOSUPPORT; |
276,11 → 356,109 |
return EOK; |
} |
int socket_get_data( void ** data, size_t * length ){ |
int udp_recvfrom_message( socket_cores_ref local_sockets, int socket_id, int flags ){ |
ERROR_DECLARE; |
socket_core_ref socket; |
int packet_id; |
packet_t packet; |
udp_header_ref header; |
struct sockaddr_in address; |
int length; |
packet_t next_packet; |
void * data; |
int fragments; |
int * lengths; |
int index; |
uint8_t * addr; |
// find the socket |
socket = socket_cores_find( local_sockets, socket_id ); |
if( ! socket ) return ENOTSOCK; |
// get the next received packet |
packet_id = dyn_fifo_value( & socket->received ); |
if( packet_id < 0 ) return packet_id; |
ERROR_PROPAGATE( packet_translate( udp_globals.net_phone, & packet, packet_id )); |
// get udp header |
data = packet_get_data( packet ); |
if( ! data ){ |
pq_release( udp_globals.net_phone, packet_id ); |
return NO_DATA; |
} |
header = ( udp_header_ref ) data; |
// set the source address |
address.sin_family = PF_INET; |
address.sin_port = ntohs( header->dest ); |
length = packet_get_addr( packet, & addr, NULL ); |
if( length != sizeof( address.sin_addr.s_addr )){ |
pq_release( udp_globals.net_phone, packet_id ); |
return EINVAL; |
} |
address.sin_addr.s_addr = *(( uint32_t * ) addr ); |
bzero( & address.sin_zero, sizeof( address.sin_zero )); |
// send the source address |
ERROR_PROPAGATE( socket_write_data( & address, sizeof( address ))); |
next_packet = pq_next( packet ); |
if( ! next_packet ){ |
// write all if only one fragment |
ERROR_PROPAGATE( socket_write_data( data + sizeof( udp_header_t ), packet_get_data_length( packet ) - sizeof( udp_header_t ))); |
// store the total length |
length = packet_get_data_length( packet ) - sizeof( udp_header_t ); |
}else{ |
// count the packet fragments |
fragments = 1; |
next_packet = pq_next( packet ); |
while(( next_packet = pq_next( next_packet ))){ |
++ fragments; |
} |
// compute and store the fragment lengths |
lengths = ( int * ) malloc( sizeof( int ) * ( fragments + 1 )); |
if( ! lengths ) return ENOMEM; |
lengths[ 0 ] = packet_get_data_length( packet ) - sizeof( udp_header_t ); |
lengths[ fragments ] = lengths[ 0 ]; |
next_packet = pq_next( packet ); |
for( index = 1; index < fragments; ++ index ){ |
lengths[ index ] = packet_get_data_length( next_packet ); |
lengths[ fragments ] += lengths[ index ]; |
next_packet = pq_next( packet ); |
}while( next_packet ); |
// write the fragment lengths |
ERROR_PROPAGATE( socket_write_data( lengths, sizeof( int ) * ( fragments + 1 ))); |
// write the first fragment |
ERROR_PROPAGATE( socket_write_data( data + sizeof( udp_header_t ), lengths[ 0 ] )); |
next_packet = pq_next( packet ); |
// write the rest of the fragments |
for( index = 1; index < fragments; ++ index ){ |
ERROR_PROPAGATE( socket_write_data( packet_get_data( next_packet ), lengths[ index ] )); |
next_packet = pq_next( packet ); |
}while( next_packet ); |
// store the total length |
length = lengths[ fragments ]; |
free( lengths ); |
} |
// release the packet |
dyn_fifo_pop( & socket->received ); |
pq_release( udp_globals.net_phone, packet_get_id( packet )); |
// return the total length |
return length; |
} |
int socket_write_data( void * data, size_t data_length ){ |
size_t length; |
ipc_callid_t callid; |
if(( ! ipc_data_read_receive( & callid, & length )) |
|| ( length < data_length )){ |
return EINVAL; |
} |
return ipc_data_read_finalize( callid, data, data_length ); |
} |
int socket_read_data( void ** data, size_t * length ){ |
ERROR_DECLARE; |
ipc_callid_t callid; |
if( !( data && length )) return EBADMEM; |
if( ! ipc_data_write_receive( & callid, length )) return EINVAL; |
* data = malloc( * length ); |
292,5 → 470,33 |
return EOK; |
} |
int socket_read_packet_data( packet_ref packet, size_t prefix, struct sockaddr_in * address_in ){ |
ERROR_DECLARE; |
ipc_callid_t callid; |
size_t length; |
void * data; |
// get the data length |
if( ! ipc_data_write_receive( & callid, & length )) return EINVAL; |
// get a new packet |
* packet = packet_get_4( udp_globals.net_phone, length, udp_globals.addr_len, prefix + udp_globals.prefix, udp_globals.suffix ); |
if( ! packet ) return ENOMEM; |
// allocate space in the packet |
data = packet_suffix( * packet, length ); |
if( ! data ){ |
pq_release( udp_globals.net_phone, packet_get_id( * packet )); |
return ENOMEM; |
} |
// read the data into the packet |
if( ERROR_OCCURRED( ipc_data_write_finalize( callid, data, length )) |
// set the packet destination address |
|| ERROR_OCCURRED( packet_set_addr( * packet, NULL, ( uint8_t * ) & address_in->sin_addr.s_addr, sizeof( address_in->sin_addr.s_addr )))){ |
pq_release( udp_globals.net_phone, packet_get_id( * packet )); |
return ERROR_CODE; |
} |
return length; |
} |
/** @} |
*/ |
/branches/network/uspace/srv/net/tl/udp/Makefile |
---|
43,6 → 43,7 |
$(STRUCTURES)packet/packet.c \ |
$(STRUCTURES)packet/packet_client.c \ |
$(STRUCTURES)packet/packet_remote.c \ |
$(STRUCTURES)dynamic_fifo.c \ |
$(STRUCTURES)measured_strings.c \ |
$(NET_BASE)il/ip/ip_client.c \ |
$(NET_BASE)il/ip/ip_remote.c \ |
/branches/network/uspace/srv/net/tl/udp/udp.h |
---|
47,7 → 47,6 |
size_t content; |
size_t suffix; |
int net_phone; |
int port_search_start; |
socket_ports_t sockets; |
}; |
/branches/network/uspace/srv/net/include/ip_client.h |
---|
135,6 → 135,8 |
int ip_client_prepare_packet( packet_t packet, ip_protocol_t protocol, ip_ttl_t ttl, ip_tos_t tos, int dont_fragment, size_t ipopt_length ); |
int ip_client_process_packet( packet_t packet, ip_protocol_t * protocol, ip_ttl_t * ttl, ip_tos_t * tos, int * dont_fragment, size_t * ipopt_length ); |
// TODO ipopt manipulation |
#endif |
/branches/network/uspace/srv/net/socket/socket_core.c |
---|
41,6 → 41,7 |
#include "../include/socket.h" |
#include "../include/socket_errno.h" |
#include "../structures/dynamic_fifo.h" |
#include "../structures/int_map.h" |
#include "../structures/packet/packet.h" |
#include "../structures/packet/packet_client.h" |
65,17 → 66,26 |
case AF_INET: |
if( addrlen != sizeof( struct sockaddr_in )) return EINVAL; |
address_in = ( struct sockaddr_in * ) addr; |
// find the socket |
socket = socket_cores_find( local_sockets, socket_id ); |
if( ! socket ) return ENOTSOCK; |
// try to find the port |
socket_pointer = socket_ports_find( global_sockets, address_in->sin_port ); |
if( * socket_pointer ){ |
if( socket_pointer ){ |
// already used |
return EADDRINUSE; |
} |
// disbind if bound |
socket_ports_exclude( global_sockets, socket->port ); |
// create a wrapper |
socket_pointer = ( socket_core_ref * ) malloc( sizeof( * socket_pointer )); |
if( ! socket_pointer ) return ENOMEM; |
* socket_pointer = socket; |
ERROR_PROPAGATE( socket_ports_add( global_sockets, address_in->sin_port, socket_pointer )); |
// register the port |
ERROR_CODE = socket_ports_add( global_sockets, address_in->sin_port, socket_pointer ); |
if( ERROR_CODE < 0 ){ |
free( socket_pointer ); |
} |
socket->port = address_in->sin_port; |
break; |
// TODO IPv6 |
85,65 → 95,63 |
return EOK; |
} |
int socket_create( socket_cores_ref local_sockets, int app_phone ){ |
int socket_create( socket_cores_ref local_sockets, int app_phone, int * socket_id ){ |
ERROR_DECLARE; |
socket_core_ref socket; |
int res; |
if( ! socket_id ) return EBADMEM; |
socket = ( socket_core_ref ) malloc( sizeof( * socket )); |
if( ! socket ) return ENOMEM; |
// initialize |
socket->phone = app_phone; |
socket->port = -1; |
socket->device_id = -1; |
socket->peer_addr = NULL; |
socket->connect_size = 2; |
socket->receive_size = 8; |
socket->connected = ( int * ) malloc( sizeof( int ) * socket->connect_size ); |
if( ! socket->connected ){ |
if( ERROR_OCCURRED( dyn_fifo_initialize( & socket->received, SOCKET_INITIAL_RECEIVED_SIZE ))){ |
free( socket ); |
return ENOMEM; |
return ERROR_CODE; |
} |
bzero( socket->connected, sizeof( int ) * socket->connect_size ); |
socket->received = ( int * ) malloc( sizeof( int ) * socket->receive_size ); |
if( ! socket->received ){ |
free( socket->connected ); |
if( ERROR_OCCURRED( dyn_fifo_initialize( & socket->accepted, SOCKET_INITIAL_ACCEPTED_SIZE ))){ |
dyn_fifo_destroy( & socket->received ); |
free( socket ); |
return ENOMEM; |
return ERROR_CODE; |
} |
bzero( socket->received, sizeof( int ) * socket->receive_size ); |
// get a next free socket number |
socket->socket_id = socket_cores_count( local_sockets ) + 1; |
// store the socket |
res = socket_cores_add( local_sockets, socket->socket_id, socket ); |
if( res < 0 ){ |
free( socket->received ); |
free( socket->connected ); |
dyn_fifo_destroy( & socket->received ); |
dyn_fifo_destroy( & socket->accepted ); |
free( socket ); |
return res; |
} |
return socket->socket_id; |
// return the socket identifier |
* socket_id = socket->socket_id; |
return EOK; |
} |
int socket_destroy( int packet_phone, int socket_id, socket_cores_ref local_sockets, socket_ports_ref global_sockets ){ |
socket_core_ref socket; |
size_t i; |
int accepted_id; |
int packet_id; |
// find the socket |
socket = socket_cores_find( local_sockets, socket_id ); |
if( ! socket ) return ENOTSOCK; |
socket_ports_exclude( global_sockets, socket->port ); |
if( socket->connected ){ |
for( i = 0; i < socket->connect_size; ++ i ){ |
if( socket->connected[ i ] ){ |
socket_destroy( packet_phone, socket->connected[ i ], local_sockets, global_sockets ); |
} |
} |
// destroy all accepted sockets |
while(( accepted_id = dyn_fifo_pop( & socket->accepted ))){ |
socket_destroy( packet_phone, accepted_id, local_sockets, global_sockets ); |
} |
if( socket->received ){ |
for( i = 0; i < socket->receive_size; ++ i ){ |
if( socket->received[ i ] ){ |
pq_release( packet_phone, socket->received[ i ] ); |
} |
} |
// release all received packets |
while(( packet_id = dyn_fifo_pop( & socket->received ))){ |
pq_release( packet_phone, packet_id ); |
} |
if( socket->connected ) free( socket->connected ); |
if( socket->received ) free( socket->received ); |
dyn_fifo_destroy( & socket->received ); |
dyn_fifo_destroy( & socket->accepted ); |
socket_cores_exclude( local_sockets, socket_id ); |
return EOK; |
} |
/branches/network/uspace/srv/net/socket/socket_messages.h |
---|
54,17 → 54,31 |
NET_SOCKET_GETSOCKOPT, |
NET_SOCKET_SETSOCKOPT, |
NET_SOCKET_ACCEPTED, |
NET_SOCKET_RECEIVED |
NET_SOCKET_RECEIVED, |
NET_SOCKET_DATA_FRAGMENT_SIZE |
} socket_messages; |
#define SOCKET_SET_SOCKET_ID( call ) ( int * ) & IPC_GET_ARG1( * call ) |
#define SOCKET_GET_SOCKET_ID( call ) ( int ) IPC_GET_ARG1( * call ) |
#define SOCKET_SET_READ_DATA_LENGTH( call ) ( int * ) & IPC_GET_ARG1( * call ) |
#define SOCKET_GET_READ_DATA_LENGTH( call ) ( int ) IPC_GET_ARG1( * call ) |
#define SOCKET_GET_NEW_SOCKET_ID( call ) ( int ) IPC_GET_ARG2( * call ) |
#define SOCKET_SET_HEADER_SIZE( call ) ( int * ) & IPC_GET_ARG2( * call ) |
#define SOCKET_GET_HEADER_SIZE( call ) ( int ) IPC_GET_ARG2( * call ) |
#define SOCKET_GET_BACKLOG( call ) ( int ) IPC_GET_ARG2( * call ) |
//#define SOCKET_GET_OPT_LEVEL( call ) ( int ) IPC_GET_ARG2( * call ) |
#define SOCKET_GET_OPT_NAME( call ) ( int ) IPC_GET_ARG2( * call ) |
#define SOCKET_GET_FLAGS( call ) ( int ) IPC_GET_ARG2( * call ) |
#define SOCKET_GET_OPT_LEVEL( call ) ( int ) IPC_GET_ARG2( * call ) |
#define SOCKET_SET_DATA_FRAGMENTS( call ) ( int * ) & IPC_GET_ARG2( * call ) |
#define SOCKET_GET_DATA_FRAGMENTS( call ) ( int ) IPC_GET_ARG2( * call ) |
#define SOCKET_SET_DATA_FRAGMENT_SIZE( call ) ( int * ) & IPC_GET_ARG3( * call ) |
#define SOCKET_GET_DATA_FRAGMENT_SIZE( call ) ( int ) IPC_GET_ARG3( * call ) |
#define SOCKET_GET_FLAGS( call ) ( int ) IPC_GET_ARG4( * call ) |
#define SOCKET_GET_OPT_NAME( call ) ( int ) IPC_GET_ARG4( * call ) |
#endif |
/** @} |
/branches/network/uspace/srv/net/socket/socket_core.h |
---|
41,9 → 41,16 |
#include "../include/in.h" |
#include "../include/device.h" |
#include "../structures/dynamic_fifo.h" |
#include "../structures/int_map.h" |
#include "../structures/packet/packet.h" |
#define SOCKET_INITIAL_RECEIVED_SIZE 4 |
#define SOCKET_MAX_RECEIVED_SIZE 64 |
#define SOCKET_INITIAL_ACCEPTED_SIZE 1 |
#define SOCKET_MAX_ACCEPTEDED_SIZE 64 |
typedef struct socket_core socket_core_t; |
typedef socket_core_t * socket_core_ref; |
51,13 → 58,11 |
int socket_id; |
int phone; |
int port; |
int * connected; |
size_t connect_size; |
packet_id_t * received; |
size_t receive_size; |
size_t mtu; |
device_id_t device_id; |
int data_fragment_size; |
device_id_t device_id; |
struct sockaddr_in * peer_addr; |
dyn_fifo_t received; |
dyn_fifo_t accepted; |
}; |
INT_MAP_DECLARE( socket_cores, socket_core_t ); |
65,7 → 70,7 |
INT_MAP_DECLARE( socket_ports, socket_core_ref ); |
int socket_bind( socket_cores_ref local_sockets, socket_ports_ref global_sockets, int socket_id, void * addr, size_t addrlen ); |
int socket_create( socket_cores_ref local_sockets, int app_phone ); |
int socket_create( socket_cores_ref local_sockets, int app_phone, int * socket_id ); |
int socket_destroy( int packet_phone, int socket_id, socket_cores_ref local_sockets, socket_ports_ref global_sockets ); |
#endif |
/branches/network/uspace/srv/net/socket/socket_client.c |
---|
49,10 → 49,17 |
#include "../include/socket.h" |
#include "../include/socket_errno.h" |
#include "../structures/dynamic_fifo.h" |
#include "../structures/int_map.h" |
#include "socket_messages.h" |
#define SOCKET_INITIAL_RECEIVED_SIZE 4 |
#define SOCKET_MAX_RECEIVED_SIZE 64 |
#define SOCKET_INITIAL_ACCEPTED_SIZE 1 |
#define SOCKET_MAX_ACCEPTED_SIZE 64 |
typedef struct socket socket_t; |
typedef socket_t * socket_ref; |
60,11 → 67,12 |
int socket_id; |
int phone; |
services_t service; |
int max_content; |
int received; |
int header_size; |
int data_fragment_size; |
dyn_fifo_t received; |
fibril_mutex_t receive_lock; |
fibril_condvar_t receive_signal; |
int accepted; |
dyn_fifo_t accepted; |
fibril_mutex_t accept_lock; |
fibril_condvar_t accept_signal; |
}; |
85,6 → 93,9 |
void socket_connection( ipc_callid_t iid, ipc_call_t * icall ); |
int socket_send_data( int socket_id, int message, ipcarg_t arg2, const void * data, size_t datalength ); |
void socket_initialize( socket_ref socket, int socket_id, int phone, services_t service ); |
void socket_destroy( socket_ref socket ); |
int recvfrom_core( int message, int socket_id, void * data, size_t datalength, int flags, struct sockaddr * fromaddr, socklen_t * addrlen ); |
int sendto_core( int message, int socket_id, const void * data, size_t datalength, int flags, const struct sockaddr * toaddr, socklen_t addrlen ); |
static int socket_get_tcp_phone(){ |
if( socket_globals.tcp_phone < 0 ){ |
116,8 → 127,8 |
socket->socket_id = socket_id; |
socket->phone = phone; |
socket->service = service; |
socket->received = 0; |
socket->accepted = 0; |
dyn_fifo_initialize( & socket->received, SOCKET_INITIAL_RECEIVED_SIZE ); |
dyn_fifo_initialize( & socket->accepted, SOCKET_INITIAL_ACCEPTED_SIZE ); |
fibril_mutex_initialize( & socket->receive_lock ); |
fibril_condvar_initialize( & socket->receive_signal ); |
fibril_mutex_initialize( & socket->accept_lock ); |
137,6 → 148,7 |
callid = async_get_call( & call ); |
switch( IPC_GET_METHOD( call )){ |
case NET_SOCKET_RECEIVED: |
// find the socket |
socket = sockets_find( socket_get_sockets(), SOCKET_GET_SOCKET_ID( & call )); |
if( ! socket ){ |
ERROR_CODE = ENOTSOCK; |
143,41 → 155,56 |
break; |
} |
fibril_mutex_lock( & socket->receive_lock ); |
++ socket->received; |
fibril_condvar_signal( & socket->receive_signal ); |
// push the number of received packet fragments |
if( ! ERROR_OCCURRED( dyn_fifo_push( & socket->received, SOCKET_GET_DATA_FRAGMENTS( & call ), SOCKET_MAX_RECEIVED_SIZE ))){ |
// signal the received packet |
fibril_condvar_signal( & socket->receive_signal ); |
} |
fibril_mutex_unlock( & socket->receive_lock ); |
ERROR_CODE = EOK; |
break; |
case NET_SOCKET_ACCEPTED: |
// find the socket |
socket = sockets_find( socket_get_sockets(), SOCKET_GET_SOCKET_ID( & call )); |
if( ! socket ){ |
ERROR_CODE = ENOTSOCK; |
break; |
} |
fibril_mutex_lock( & socket->accept_lock ); |
// create a new scoket |
new_socket = ( socket_ref ) malloc( sizeof( socket_t )); |
if( ! new_socket ){ |
ERROR_CODE = ENOMEM; |
break; |
} |
socket_initialize( new_socket, SOCKET_GET_NEW_SOCKET_ID( & call ), socket->phone, socket->service ); |
if( ERROR_OCCURRED( sockets_add( socket_get_sockets(), new_socket->socket_id, new_socket ))){ |
break; |
socket_initialize( new_socket, SOCKET_GET_SOCKET_ID( & call ), socket->phone, socket->service ); |
ERROR_CODE = sockets_add( socket_get_sockets(), new_socket->socket_id, new_socket ); |
if( ERROR_CODE < 0 ){ |
free( new_socket ); |
}else{ |
// push the new socket identifier |
fibril_mutex_lock( & socket->accept_lock ); |
if( ERROR_OCCURRED( dyn_fifo_push( & socket->accepted, new_socket->socket_id, SOCKET_MAX_ACCEPTED_SIZE ))){ |
sockets_exclude( socket_get_sockets(), new_socket->socket_id ); |
free( new_socket ); |
}else{ |
// signal the accepted socket |
fibril_condvar_signal( & socket->accept_signal ); |
} |
fibril_mutex_unlock( & socket->accept_lock ); |
ERROR_CODE = EOK; |
} |
++ socket->accepted; |
fibril_condvar_signal( & socket->accept_signal ); |
fibril_mutex_unlock( & socket->accept_lock ); |
break; |
/* case NET_SOCKET_MTU: |
case NET_SOCKET_DATA_FRAGMENT_SIZE: |
// find the socket |
socket = sockets_find( socket_get_sockets(), SOCKET_GET_SOCKET_ID( & call )); |
if( ! socket ){ |
ERROR_CODE = ENOTSOCK; |
break; |
} |
socket->mtu = |
// set the data fragment size |
socket->data_fragment_size = SOCKET_GET_DATA_FRAGMENT_SIZE( & call ); |
ERROR_CODE = EOK; |
break; |
*/ default: |
default: |
ERROR_CODE = ENOTSUP; |
} |
ipc_answer_0( callid, ERROR_CODE ); |
185,11 → 212,14 |
} |
int socket( int domain, int type, int protocol ){ |
ERROR_DECLARE; |
socket_ref socket; |
int phone; |
int socket_id; |
services_t service; |
// find the appropriate service |
switch( domain ){ |
case PF_INET: |
switch( type ){ |
224,19 → 254,37 |
default: |
return EPFNOSUPPORT; |
} |
assert( phone ); |
// create a new socket structure |
socket = ( socket_ref ) malloc( sizeof( socket_t )); |
if( ! socket ) return ENOMEM; |
socket_id = async_req_3_0( phone, NET_SOCKET, 0, 0, service ); |
if( socket_id > 0 ){ |
socket_initialize( socket, socket_id, phone, service ); |
if( sockets_add( socket_get_sockets(), socket_id, socket ) != EOK ){ |
free( socket ); |
async_msg_3( phone, NET_SOCKET_CLOSE, socket_id, 0, service ); |
} |
}else{ |
if( ERROR_OCCURRED( dyn_fifo_initialize( & socket->received, SOCKET_INITIAL_RECEIVED_SIZE ))){ |
free( socket ); |
return ERROR_CODE; |
} |
if( ERROR_OCCURRED( dyn_fifo_initialize( & socket->accepted, SOCKET_INITIAL_ACCEPTED_SIZE ))){ |
dyn_fifo_destroy( & socket->received ); |
free( socket ); |
return ERROR_CODE; |
} |
// request a new socket |
if( ERROR_OCCURRED( async_req_3_3( phone, NET_SOCKET, 0, 0, service, ( ipcarg_t * ) & socket_id, ( ipcarg_t * ) & socket->header_size, ( ipcarg_t * ) & socket->data_fragment_size ))){ |
dyn_fifo_destroy( & socket->received ); |
dyn_fifo_destroy( & socket->accepted ); |
free( socket ); |
return ERROR_CODE; |
} |
// finish the new socket initialization |
socket_initialize( socket, socket_id, phone, service ); |
// store the new socket |
ERROR_CODE = sockets_add( socket_get_sockets(), socket_id, socket ); |
if( ERROR_CODE < 0 ){ |
dyn_fifo_destroy( & socket->received ); |
dyn_fifo_destroy( & socket->accepted ); |
free( socket ); |
async_msg_3( phone, NET_SOCKET_CLOSE, socket_id, 0, service ); |
return ERROR_CODE; |
} |
return socket_id; |
} |
247,9 → 295,12 |
if( ! data ) return EBADMEM; |
if( ! datalength ) return NO_DATA; |
// find the socket |
socket = sockets_find( socket_get_sockets(), socket_id ); |
if( ! socket ) return ENOTSOCK; |
// request the message |
message_id = async_send_3( socket->phone, message, socket->socket_id, arg2, socket->service, NULL ); |
// send the address |
ipc_data_write_start( socket->phone, data, datalength ); |
async_wait_for( message_id, & result ); |
return ( int ) result; |
256,6 → 307,7 |
} |
int bind( int socket_id, const struct sockaddr * my_addr, socklen_t addrlen ){ |
// send the address |
return socket_send_data( socket_id, NET_SOCKET_BIND, 0, my_addr, addrlen ); |
} |
263,8 → 315,10 |
socket_ref socket; |
if( backlog <= 0 ) return EINVAL; |
// find the socket |
socket = sockets_find( socket_get_sockets(), socket_id ); |
if( ! socket ) return ENOTSOCK; |
// request listen backlog change |
return async_req_3_0( socket->phone, NET_SOCKET_LISTEN, socket->socket_id, backlog, socket->service ); |
} |
271,109 → 325,187 |
int accept( int socket_id, struct sockaddr * cliaddr, socklen_t * addrlen ){ |
socket_ref socket; |
aid_t message_id; |
ipcarg_t result; |
int result; |
if( ! cliaddr ) return EBADMEM; |
if( ! addrlen ) return NO_DATA; |
// find the socket |
socket = sockets_find( socket_get_sockets(), socket_id ); |
if( ! socket ) return ENOTSOCK; |
fibril_mutex_lock( & socket->accept_lock ); |
while( socket->accepted <= 0 ){ |
// wait for an accepted socket |
while( dyn_fifo_value( & socket->accepted ) <= 0 ){ |
fibril_condvar_wait( & socket->accept_signal, & socket->accept_lock ); |
} |
message_id = async_send_3( socket->phone, NET_SOCKET_ACCEPT, socket->socket_id, 0, socket->service, NULL ); |
// request accept |
message_id = async_send_3( socket->phone, NET_SOCKET_ACCEPT, socket->socket_id, dyn_fifo_value( & socket->accepted ), socket->service, NULL ); |
// read address |
ipc_data_read_start( socket->phone, cliaddr, * addrlen ); |
async_wait_for( message_id, & result ); |
async_wait_for( message_id, ( ipcarg_t * ) & result ); |
if( result > 0 ){ |
-- socket->accepted; |
// dequeue the accepted apcket if successful |
dyn_fifo_pop( & socket->accepted ); |
} |
fibril_mutex_unlock( & socket->accept_lock ); |
return ( int ) result; |
return result; |
} |
int connect( int socket_id, const struct sockaddr * serv_addr, socklen_t addrlen ){ |
// send the address |
return socket_send_data( socket_id, NET_SOCKET_CONNECT, 0, serv_addr, addrlen ); |
} |
int closesocket( int socket_id ){ |
ERROR_DECLARE; |
socket_ref socket; |
socket = sockets_find( socket_get_sockets(), socket_id ); |
if( ! socket ) return ENOTSOCK; |
return async_req_3_0( socket->phone, NET_SOCKET_CLOSE, socket->socket_id, 0, socket->service ); |
// request close |
ERROR_PROPAGATE( async_req_3_0( socket->phone, NET_SOCKET_CLOSE, socket->socket_id, 0, socket->service )); |
// free the socket structure |
socket_destroy( socket ); |
return EOK; |
} |
void socket_destroy( socket_ref socket ){ |
int accepted_id; |
// destroy all accepted sockets |
while(( accepted_id = dyn_fifo_pop( & socket->accepted ))){ |
socket_destroy( sockets_find( socket_get_sockets(), accepted_id )); |
} |
dyn_fifo_destroy( & socket->received ); |
dyn_fifo_destroy( & socket->accepted ); |
sockets_exclude( socket_get_sockets(), socket->socket_id ); |
} |
int send( int socket_id, void * data, size_t datalength, int flags ){ |
return socket_send_data( socket_id, NET_SOCKET_SEND, flags, data, datalength ); |
// without the address |
return sendto_core( NET_SOCKET_SEND, socket_id, data, datalength, flags, NULL, 0 ); |
} |
int sendto( int socket_id, const void * data, size_t datalength, int flags, const struct sockaddr * toaddr, socklen_t addrlen ){ |
socket_ref socket; |
aid_t message_id; |
ipcarg_t result; |
if( ! toaddr ) return EBADMEM; |
if( ! addrlen ) return NO_DATA; |
if( ! data ) return EBADMEM; |
if( ! datalength ) return NO_DATA; |
socket = sockets_find( socket_get_sockets(), socket_id ); |
if( ! socket ) return ENOTSOCK; |
message_id = async_send_3( socket->phone, NET_SOCKET_SENDTO, socket->socket_id, flags, socket->service, NULL ); |
if( ipc_data_write_start( socket->phone, toaddr, addrlen ) == EOK ){ |
ipc_data_write_start( socket->phone, data, datalength ); |
} |
async_wait_for( message_id, & result ); |
return ( int ) result; |
// with the address |
return sendto_core( NET_SOCKET_SENDTO, socket_id, data, datalength, flags, toaddr, addrlen ); |
} |
int recv( int socket_id, void * data, size_t datalength, int flags ){ |
int sendto_core( int message, int socket_id, const void * data, size_t datalength, int flags, const struct sockaddr * toaddr, socklen_t addrlen ){ |
socket_ref socket; |
aid_t message_id; |
ipcarg_t result; |
int fragments; |
if( ! data ) return EBADMEM; |
if( ! datalength ) return NO_DATA; |
// find socket |
socket = sockets_find( socket_get_sockets(), socket_id ); |
if( ! socket ) return ENOTSOCK; |
fibril_mutex_lock( & socket->receive_lock ); |
while( socket->received <= 0 ){ |
fibril_condvar_wait( & socket->receive_signal, & socket->receive_lock ); |
// compute data fragment count |
fragments = ( datalength + socket->header_size ) / socket->data_fragment_size; |
if(( datalength + socket->header_size ) % socket->data_fragment_size ) ++ fragments; |
// request send |
message_id = async_send_4( socket->phone, message, socket->socket_id, fragments, socket->service, flags, NULL ); |
// send the address if given |
if(( ! toaddr ) || ( ipc_data_write_start( socket->phone, toaddr, addrlen ) == EOK )){ |
if( fragments == 1 ){ |
// send all if only one fragment |
ipc_data_write_start( socket->phone, data, datalength ); |
}else{ |
// send the first fragment |
ipc_data_write_start( socket->phone, data, socket->data_fragment_size - socket->header_size ); |
data += socket->data_fragment_size - socket->header_size; |
// send the middle fragments |
while(( -- fragments ) > 1 ){ |
ipc_data_write_start( socket->phone, data, socket->data_fragment_size ); |
data += socket->data_fragment_size; |
} |
// send the last fragment |
ipc_data_write_start( socket->phone, data, ( datalength + socket->header_size ) % socket->data_fragment_size ); |
} |
} |
message_id = async_send_3( socket->phone, NET_SOCKET_RECV, socket->socket_id, flags, socket->service, NULL ); |
ipc_data_read_start( socket->phone, data, datalength ); |
async_wait_for( message_id, & result ); |
if( result > 0 ){ |
-- socket->received; |
} |
fibril_mutex_unlock( & socket->receive_lock ); |
return ( int ) result; |
} |
int recv( int socket_id, void * data, size_t datalength, int flags ){ |
// without the address |
return recvfrom_core( NET_SOCKET_RECV, socket_id, data, datalength, flags, NULL, NULL ); |
} |
int recvfrom( int socket_id, void * data, size_t datalength, int flags, struct sockaddr * fromaddr, socklen_t * addrlen ){ |
if( ! fromaddr ) return EBADMEM; |
if( ! addrlen ) return NO_DATA; |
// with the address |
return recvfrom_core( NET_SOCKET_RECVFROM, socket_id, data, datalength, flags, fromaddr, addrlen ); |
} |
int recvfrom_core( int message, int socket_id, void * data, size_t datalength, int flags, struct sockaddr * fromaddr, socklen_t * addrlen ){ |
socket_ref socket; |
aid_t message_id; |
ipcarg_t result; |
int result; |
int fragments; |
int * lengths; |
int index; |
ipc_call_t answer; |
if( ! fromaddr ) return EBADMEM; |
if( ! addrlen ) return NO_DATA; |
if( ! data ) return EBADMEM; |
if( ! datalength ) return NO_DATA; |
// find the socket |
socket = sockets_find( socket_get_sockets(), socket_id ); |
if( ! socket ) return ENOTSOCK; |
fibril_mutex_lock( & socket->receive_lock ); |
while( socket->received <= 0 ){ |
// wait for a received packet |
while(( fragments = dyn_fifo_value( & socket->received )) <= 0 ){ |
fibril_condvar_wait( & socket->receive_signal, & socket->receive_lock ); |
} |
message_id = async_send_3( socket->phone, NET_SOCKET_RECVFROM, socket->socket_id, flags, socket->service, NULL ); |
if( ipc_data_read_start( socket->phone, fromaddr, * addrlen ) == EOK ){ |
ipc_data_read_start( socket->phone, data, datalength ); |
// prepare lengths if more fragments |
if( fragments > 1 ){ |
lengths = ( int * ) malloc( sizeof( int ) * ( fragments + 1 )); |
if( ! lengths ){ |
fibril_mutex_unlock( & socket->receive_lock ); |
return ENOMEM; |
} |
} |
async_wait_for( message_id, & result ); |
if( result > 0 ){ |
-- socket->received; |
// request packet data |
message_id = async_send_4( socket->phone, message, socket->socket_id, 0, socket->service, flags, & answer ); |
// read the address if desired |
if( fromaddr ){ |
* addrlen = sizeof( struct sockaddr_in ); |
} |
if(( ! fromaddr ) || ( ipc_data_read_start( socket->phone, fromaddr, * addrlen ) == EOK )){ |
if( fragments == 1 ){ |
// read all if only one fragment |
ipc_data_read_start( socket->phone, data, datalength ); |
}else{ |
// read the fragment lengths |
if( ipc_data_read_start( socket->phone, lengths, sizeof( int ) * ( fragments + 1 )) == EOK ){ |
if( lengths[ fragments ] <= datalength ){ |
// read all fragments if long enough |
for( index = 0; index < fragments; ++ index ){ |
ipc_data_read_start( socket->phone, data, lengths[ index ] ); |
data += lengths[ index ]; |
} |
} |
} |
free( lengths ); |
} |
}else if( fragments > 1 ){ |
free( lengths ); |
} |
async_wait_for( message_id, ( ipcarg_t * ) & result ); |
// if successful |
if( result == EOK ){ |
// dequeue the received packet |
dyn_fifo_pop( & socket->received ); |
// return read data length |
result = SOCKET_GET_READ_DATA_LENGTH( & answer ); |
} |
fibril_mutex_unlock( & socket->receive_lock ); |
return ( int ) result; |
return result; |
} |
int getsockopt( int socket_id, int level, int optname, void * value, size_t * optlen ){ |
381,18 → 513,26 |
aid_t message_id; |
ipcarg_t result; |
if( ! value ) return EBADMEM; |
if( ! optlen ) return NO_DATA; |
if( !( value && optlen )) return EBADMEM; |
if( !( * optlen )) return NO_DATA; |
// find the socket |
socket = sockets_find( socket_get_sockets(), socket_id ); |
if( ! socket ) return ENOTSOCK; |
// request option value |
message_id = async_send_3( socket->phone, NET_SOCKET_GETSOCKOPT, socket->socket_id, optname, socket->service, NULL ); |
ipc_data_read_start( socket->phone, value, * optlen ); |
// read the length |
if( ipc_data_read_start( socket->phone, optlen, sizeof( * optlen )) == EOK ){ |
// read the value |
ipc_data_read_start( socket->phone, value, * optlen ); |
} |
async_wait_for( message_id, & result ); |
return ( int ) result; |
} |
int setsockopt( int socket_id, int level, int optname, const void * value, size_t optlen ){ |
// send the value |
return socket_send_data( socket_id, NET_SOCKET_SETSOCKOPT, optname, value, optlen ); |
} |
/** @} |
/branches/network/uspace/srv/net/socket/Makefile |
---|
37,6 → 37,7 |
LIB = lib$(NAME).a |
SOURCES = \ |
$(NAME)_client.c \ |
$(NET_BASE)inet.c |
$(NET_BASE)inet.c \ |
$(STRUCTURES)dynamic_fifo.c |
include $(NET_BASE)Makefile.module |
/branches/network/uspace/srv/net/il/ip/ip_client.c |
---|
67,5 → 67,22 |
return EOK; |
} |
int ip_client_process_packet( packet_t packet, ip_protocol_t * protocol, ip_ttl_t * ttl, ip_tos_t * tos, int * dont_fragment, size_t * ipopt_length ){ |
ip_header_ref header; |
header = ( ip_header_ref ) packet_get_data( packet ); |
if( ! header ) return ENOMEM; |
if( protocol ) * protocol = header->protocol; |
if( ttl ) * ttl = header->ttl; |
if( tos ) * tos = header->tos; |
if( dont_fragment ) * dont_fragment = header->flags & IPFLAG_DONT_FRAGMENT; |
if( ipopt_length ){ |
* ipopt_length = header->ihl * 4 - sizeof( ip_header_t ); |
return packet_trim( packet, sizeof( ip_header_t ), 0 ); |
}else{ |
return packet_trim( packet, header->ihl * 4, 0 ); |
} |
} |
/** @} |
*/ |
/branches/network/uspace/srv/net/il/ip/ip.c |
---|
110,7 → 110,7 |
int ip_fragment_packet( packet_t packet, size_t length, size_t prefix, size_t suffix, size_t addr_len ); |
int ip_fragment_packet_data( packet_t packet, packet_t new_packet, ip_header_ref header, ip_header_ref new_header, size_t length, void * src, void * dest, size_t address_length ); |
ip_header_ref ip_create_middle_header( packet_t packet, ip_header_ref last ); |
ip_header_ref ip_create_last_header( packet_t packet, ip_header_ref first ); |
void ip_create_last_header( ip_header_ref last, ip_header_ref first ); |
in_addr_t * ip_netif_addr( ip_netif_ref netif ); |
ip_route_ref ip_find_route( in_addr_t destination ); |
485,8 → 485,6 |
int ip_send_route( packet_t packet, ip_netif_ref netif, ip_route_ref route, in_addr_t * src, in_addr_t dest ){ |
ERROR_DECLARE; |
packet_t next; |
packet_t tmp; |
measured_string_t destination; |
measured_string_ref translation; |
char * data; |
508,31 → 506,19 |
return EINVAL; |
} |
}else translation = NULL; |
// process packet queue |
next = packet; |
do{ |
if( ERROR_OCCURRED( ip_prepare_packet( src, dest, next, translation ))){ |
// release invalid packet |
tmp = pq_detach( next ); |
if( next == packet ) packet = tmp; |
pq_release( ip_globals.net_phone, packet_get_id( next )); |
next = tmp; |
}else{ |
next = pq_next( next ); |
if( ERROR_OCCURRED( ip_prepare_packet( src, dest, packet, translation ))){ |
pq_release( ip_globals.net_phone, packet_get_id( packet )); |
}else{ |
packet = ip_split_packet( packet, netif->prefix, netif->content, netif->suffix, netif->addr_len ); |
if( packet ){ |
nil_send_msg( netif->phone, netif->device_id, packet, SERVICE_IP ); |
} |
}while( next ); |
} |
if( translation ){ |
free( translation ); |
free( data ); |
} |
// send packet queue |
if( packet ){ |
packet = ip_split_packet( packet, netif->prefix, netif->content, netif->suffix, netif->addr_len ); |
if( packet ){ |
nil_send_msg( netif->phone, netif->device_id, packet, SERVICE_IP ); |
} |
} |
return EOK; |
return ERROR_CODE; |
} |
int ip_prepare_packet( in_addr_t * source, in_addr_t dest, packet_t packet, measured_string_ref destination ){ |
540,6 → 526,9 |
size_t length; |
ip_header_ref header; |
ip_header_ref last_header; |
ip_header_ref middle_header; |
packet_t next; |
length = packet_get_data_length( packet ); |
if(( length < sizeof( ip_header_t )) || ( length > IP_MAX_CONTENT )) return EINVAL; |
548,8 → 537,8 |
ERROR_PROPAGATE( packet_set_addr( packet, NULL, ( uint8_t * ) destination->value, CONVERT_SIZE( char, uint8_t, destination->length ))); |
} |
header->version = 4; |
header->total_length = htons( length ); |
header->fragment_offset = 0; |
header->header_checksum = 0; |
if( source ) header->source_address = source->s_addr; |
header->destination_address = dest.s_addr; |
fibril_rwlock_write_lock( & ip_globals.lock ); |
556,12 → 545,47 |
++ ip_globals.packet_counter; |
header->identification = htons( ip_globals.packet_counter ); |
fibril_rwlock_write_unlock( & ip_globals.lock ); |
header->header_checksum = 0; |
length = packet_get_data_length( packet ); |
if( pq_next( packet )){ |
last_header = ( ip_header_ref ) malloc( IP_HEADER_LENGTH( header )); |
if( ! last_header ) return ENOMEM; |
ip_create_last_header( last_header, header ); |
next = pq_next( packet ); |
while( pq_next( next )){ |
middle_header = ( ip_header_ref ) packet_prefix( next, IP_HEADER_LENGTH( last_header )); |
if( ! middle_header ) return ENOMEM; |
memcpy( middle_header, last_header, IP_HEADER_LENGTH( last_header )); |
header->flags |= IPFLAG_MORE_FRAGMENTS; |
middle_header->total_length = htons( packet_get_data_length( next )); |
middle_header->fragment_offset = length / 8; |
middle_header->header_checksum = IP_HEADER_CHECKSUM( middle_header ); |
if( destination ){ |
ERROR_PROPAGATE( packet_set_addr( next, NULL, ( uint8_t * ) destination->value, CONVERT_SIZE( char, uint8_t, destination->length ))); |
} |
length += packet_get_data_length( next ); |
next = pq_next( next ); |
} |
middle_header = ( ip_header_ref ) packet_prefix( next, IP_HEADER_LENGTH( last_header )); |
if( ! middle_header ) return ENOMEM; |
memcpy( middle_header, last_header, IP_HEADER_LENGTH( last_header )); |
middle_header->total_length = htons( packet_get_data_length( next )); |
middle_header->fragment_offset = length / 8; |
middle_header->header_checksum = IP_HEADER_CHECKSUM( middle_header ); |
if( destination ){ |
ERROR_PROPAGATE( packet_set_addr( next, NULL, ( uint8_t * ) destination->value, CONVERT_SIZE( char, uint8_t, destination->length ))); |
} |
length += packet_get_data_length( next ); |
free( last_header ); |
header->flags |= IPFLAG_MORE_FRAGMENTS; |
} |
header->total_length = htons( length ); |
// unnecessary for all protocols |
header->header_checksum = IP_HEADER_CHECKSUM( header ); |
return EOK; |
} |
int ip_message( ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count ){ |
ERROR_DECLARE; |
760,11 → 784,18 |
// create the last fragment |
new_packet = packet_get_4( ip_globals.net_phone, prefix, length, suffix, ((( size_t ) address_length > addr_len ) ? ( size_t ) address_length : addr_len )); |
if( ! new_packet ) return ENOMEM; |
last_header = ip_create_last_header( new_packet, header ); |
// allocate as much as originally |
last_header = ( ip_header_ref ) packet_suffix( new_packet, IP_HEADER_LENGTH( header )); |
if( ! last_header ){ |
pq_release( ip_globals.net_phone, packet_get_id( new_packet )); |
return ENOMEM; |
} |
ip_create_last_header( last_header, header ); |
// trim the unused space |
if( ERROR_OCCURRED( packet_trim( new_packet, 0, IP_HEADER_LENGTH( header ) - IP_HEADER_LENGTH( last_header )))){ |
pq_release( ip_globals.net_phone, packet_get_id( new_packet )); |
return ERROR_CODE; |
} |
// biggest multiple of 8 lower than content |
// TODO even fragmentation? |
length = length & ( ~ 0x7 );// ( content / 8 ) * 8 |
821,15 → 852,11 |
return middle; |
} |
ip_header_ref ip_create_last_header( packet_t packet, ip_header_ref first ){ |
ip_header_ref last; |
void ip_create_last_header( ip_header_ref last, ip_header_ref first ){ |
ip_option_ref option; |
size_t next; |
size_t length; |
// allocate as much as originally |
last = ( ip_header_ref ) packet_suffix( packet, IP_HEADER_LENGTH( first )); |
if( ! last ) return NULL; |
// copy first itself |
memcpy( last, first, sizeof( ip_header_t )); |
length = sizeof( ip_header_t ); |
857,9 → 884,7 |
}else{ |
last->ihl = length / 4; |
} |
// trim the unused space |
if( packet_trim( packet, 0, IP_HEADER_LENGTH( first ) - IP_HEADER_LENGTH( last )) != EOK ) return NULL; |
return last; |
last->header_checksum = 0; |
} |
int ip_received_msg( device_id_t device_id, packet_t packet ){ |