source: mainline/uspace/srv/net/tl/tcp/tcp.c@ ede63e4

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since ede63e4 was ede63e4, checked in by Lukas Mejdrech <lukasmejdrech@…>, 16 years ago
  • socket identifier generation moved to libsocket, + data fragment size fix and enhancement, + [ICMP|TCP|UDP]_HEADER_SIZE definition, + int_map_update() function to alter item key
  • Property mode set to 100644
File size: 69.3 KB
Line 
1/*
2 * Copyright (c) 2008 Lukas Mejdrech
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup tcp
30 * @{
31 */
32
33/** @file
34 * TCP module implementation.
35 * @see tcp.h
36 */
37
38#include <assert.h>
39#include <async.h>
40#include <fibril_synch.h>
41#include <malloc.h>
42//TODO remove stdio
43#include <stdio.h>
44
45#include <ipc/ipc.h>
46#include <ipc/services.h>
47
48#include "../../err.h"
49#include "../../messages.h"
50#include "../../modules.h"
51
52#include "../../structures/dynamic_fifo.h"
53#include "../../structures/packet/packet_client.h"
54
55#include "../../include/checksum.h"
56#include "../../include/in.h"
57#include "../../include/in6.h"
58#include "../../include/inet.h"
59#include "../../include/ip_client.h"
60#include "../../include/ip_interface.h"
61#include "../../include/ip_protocols.h"
62#include "../../include/icmp_client.h"
63#include "../../include/icmp_interface.h"
64#include "../../include/net_interface.h"
65#include "../../include/socket_codes.h"
66#include "../../include/socket_errno.h"
67#include "../../include/tcp_codes.h"
68
69#include "../../socket/socket_core.h"
70#include "../../socket/socket_messages.h"
71
72#include "../tl_common.h"
73#include "../tl_messages.h"
74
75#include "tcp.h"
76#include "tcp_header.h"
77#include "tcp_module.h"
78
79/** The TCP window default value.
80 */
81#define NET_DEFAULT_TCP_WINDOW 10240
82
83/** Initial timeout for new connections.
84 */
85#define NET_DEFAULT_TCP_INITIAL_TIMEOUT 3000000L
86
87/** Default timeout for closing.
88 */
89#define NET_DEFAULT_TCP_TIME_WAIT_TIMEOUT 2000L
90
91/** The initial outgoing sequence number.
92 */
93#define TCP_INITIAL_SEQUENCE_NUMBER 2999
94
95/** Maximum TCP fragment size.
96 */
97#define MAX_TCP_FRAGMENT_SIZE 65535
98
99/** Free ports pool start.
100 */
101#define TCP_FREE_PORTS_START 1025
102
103/** Free ports pool end.
104 */
105#define TCP_FREE_PORTS_END 65535
106
107/** Timeout for connection initialization, SYN sent.
108 */
109#define TCP_SYN_SENT_TIMEOUT 1000000L
110
111/** The maximum number of timeouts in a row before singaling connection lost.
112 */
113#define TCP_MAX_TIMEOUTS 8
114
115/** The number of acknowledgements before retransmit.
116 */
117#define TCP_FAST_RETRANSMIT_COUNT 3
118
119/** Returns a value indicating whether the value is in the interval respecting the possible overflow.
120 * The high end and/or the value may overflow, be lower than the low value.
121 * @param[in] lower The last value before the interval.
122 * @param[in] value The value to be checked.
123 * @param[in] higher_equal The last value in the interval.
124 */
125#define IS_IN_INTERVAL_OVERFLOW( lower, value, higher_equal ) (((( lower ) < ( value )) && ((( value ) <= ( higher_equal )) || (( higher_equal ) < ( lower )))) || ((( value ) <= ( higher_equal )) && (( higher_equal ) < ( lower ))))
126
127/** Type definition of the TCP timeout.
128 * @see tcp_timeout
129 */
130typedef struct tcp_timeout tcp_timeout_t;
131
132/** Type definition of the TCP timeout pointer.
133 * @see tcp_timeout
134 */
135typedef tcp_timeout_t * tcp_timeout_ref;
136
137/** TCP reply timeout data.
138 * Used as a timeouting fibril argument.
139 * @see tcp_timeout()
140 */
141struct tcp_timeout{
142 /** TCP global data are going to be read only.
143 */
144 int globals_read_only;
145 /** Socket port.
146 */
147 int port;
148 /** Local sockets.
149 */
150 socket_cores_ref local_sockets;
151 /** Socket identifier.
152 */
153 int socket_id;
154 /** Socket state.
155 */
156 tcp_socket_state_t state;
157 /** Sent packet sequence number.
158 */
159 int sequence_number;
160 /** Timeout in microseconds.
161 */
162 suseconds_t timeout;
163 /** Port map key.
164 */
165 char * key;
166 /** Port map key length.
167 */
168 size_t key_length;
169};
170
171/** Releases the packet and returns the result.
172 * @param[in] packet The packet queue to be released.
173 * @param[in] result The result to be returned.
174 * @return The result parameter.
175 */
176int tcp_release_and_return( packet_t packet, int result );
177
178void tcp_prepare_operation_header( socket_core_ref socket, tcp_socket_data_ref socket_data, tcp_header_ref header, int synchronize, int finalize );
179int tcp_prepare_timeout( int ( * timeout_function )( void * tcp_timeout_t ), socket_core_ref socket, tcp_socket_data_ref socket_data, size_t sequence_number, tcp_socket_state_t state, suseconds_t timeout, int globals_read_only );
180void tcp_free_socket_data( socket_core_ref socket );
181int tcp_timeout( void * data );
182int tcp_release_after_timeout( void * data );
183int tcp_process_packet( device_id_t device_id, packet_t packet, services_t error );
184int tcp_connect_core( socket_core_ref socket, socket_cores_ref local_sockets, struct sockaddr * addr, socklen_t addrlen );
185int tcp_queue_prepare_packet( socket_core_ref socket, tcp_socket_data_ref socket_data, packet_t packet, size_t data_length );
186int tcp_queue_packet( socket_core_ref socket, tcp_socket_data_ref socket_data, packet_t packet, size_t data_length );
187packet_t tcp_get_packets_to_send( socket_core_ref socket, tcp_socket_data_ref socket_data );
188void tcp_send_packets( device_id_t device_id, packet_t packet );
189void tcp_process_acknowledgement( socket_core_ref socket, tcp_socket_data_ref socket_data, tcp_header_ref header );
190packet_t tcp_send_prepare_packet( socket_core_ref socket, tcp_socket_data_ref socket_data, packet_t packet, size_t data_length, size_t sequence_number );
191packet_t tcp_prepare_copy( socket_core_ref socket, tcp_socket_data_ref socket_data, packet_t packet, size_t data_length, size_t sequence_number );
192void tcp_retransmit_packet( socket_core_ref socket, tcp_socket_data_ref socket_data, size_t sequence_number );
193int tcp_create_notification_packet( packet_t * packet, socket_core_ref socket, tcp_socket_data_ref socket_data, int synchronize, int finalize );
194void tcp_refresh_socket_data( tcp_socket_data_ref socket_data );
195void tcp_initialize_socket_data( tcp_socket_data_ref socket_data );
196int tcp_process_listen( socket_core_ref listening_socket, tcp_socket_data_ref listening_socket_data, tcp_header_ref header, packet_t packet, struct sockaddr * src, struct sockaddr * dest, size_t addrlen );
197int tcp_process_syn_sent( socket_core_ref socket, tcp_socket_data_ref socket_data, tcp_header_ref header, packet_t packet );
198int tcp_process_syn_received( socket_core_ref socket, tcp_socket_data_ref socket_data, tcp_header_ref header, packet_t packet );
199int tcp_process_established( socket_core_ref socket, tcp_socket_data_ref socket_data, tcp_header_ref header, packet_t packet, int fragments, size_t total_length );
200int tcp_queue_received_packet( socket_core_ref socket, tcp_socket_data_ref socket_data, packet_t packet, int fragments, size_t total_length );
201
202int tcp_received_msg( device_id_t device_id, packet_t packet, services_t receiver, services_t error );
203int tcp_process_client_messages( ipc_callid_t callid, ipc_call_t call );
204int tcp_listen_message( socket_cores_ref local_sockets, int socket_id, int backlog );
205int tcp_connect_message( socket_cores_ref local_sockets, int socket_id, struct sockaddr * addr, socklen_t addrlen );
206int tcp_recvfrom_message( socket_cores_ref local_sockets, int socket_id, int flags, size_t * addrlen );
207int tcp_send_message( socket_cores_ref local_sockets, int socket_id, int fragments, size_t * data_fragment_size, int flags );
208int tcp_accept_message( socket_cores_ref local_sockets, int socket_id, int new_socket_id, size_t * data_fragment_size, size_t * addrlen );
209int tcp_close_message( socket_cores_ref local_sockets, int socket_id );
210
211/** TCP global data.
212 */
213tcp_globals_t tcp_globals;
214
215int tcp_initialize( async_client_conn_t client_connection ){
216 ERROR_DECLARE;
217
218 assert( client_connection );
219 fibril_rwlock_initialize( & tcp_globals.lock );
220 fibril_rwlock_write_lock( & tcp_globals.lock );
221 tcp_globals.icmp_phone = icmp_connect_module( SERVICE_ICMP, ICMP_CONNECT_TIMEOUT );
222 tcp_globals.ip_phone = ip_bind_service( SERVICE_IP, IPPROTO_TCP, SERVICE_TCP, client_connection, tcp_received_msg );
223 if( tcp_globals.ip_phone < 0 ){
224 return tcp_globals.ip_phone;
225 }
226 ERROR_PROPAGATE( socket_ports_initialize( & tcp_globals.sockets ));
227 if( ERROR_OCCURRED( packet_dimensions_initialize( & tcp_globals.dimensions ))){
228 socket_ports_destroy( & tcp_globals.sockets );
229 return ERROR_CODE;
230 }
231 tcp_globals.last_used_port = TCP_FREE_PORTS_START - 1;
232 fibril_rwlock_write_unlock( & tcp_globals.lock );
233 return EOK;
234}
235
236int tcp_received_msg( device_id_t device_id, packet_t packet, services_t receiver, services_t error ){
237 ERROR_DECLARE;
238
239 if( receiver != SERVICE_TCP ) return EREFUSED;
240 fibril_rwlock_write_lock( & tcp_globals.lock );
241 if( ERROR_OCCURRED( tcp_process_packet( device_id, packet, error ))){
242 fibril_rwlock_write_unlock( & tcp_globals.lock );
243 }
244 printf( "receive %d \n", ERROR_CODE );
245
246 return ERROR_CODE;
247}
248
249int tcp_process_packet( device_id_t device_id, packet_t packet, services_t error ){
250 ERROR_DECLARE;
251
252 size_t length;
253 size_t offset;
254 int result;
255 tcp_header_ref header;
256 socket_core_ref socket;
257 tcp_socket_data_ref socket_data;
258 packet_t next_packet;
259 size_t total_length;
260 uint32_t checksum;
261 int fragments;
262 icmp_type_t type;
263 icmp_code_t code;
264 struct sockaddr * src;
265 struct sockaddr * dest;
266 size_t addrlen;
267
268 printf( "p1 \n" );
269 if( error ){
270 switch( error ){
271 case SERVICE_ICMP:
272 // process error
273 result = icmp_client_process_packet( packet, & type, & code, NULL, NULL );
274 if( result < 0 ){
275 return tcp_release_and_return( packet, result );
276 }
277 length = ( size_t ) result;
278 if( ERROR_OCCURRED( packet_trim( packet, length, 0 ))){
279 return tcp_release_and_return( packet, ERROR_CODE );
280 }
281 break;
282 default:
283 return tcp_release_and_return( packet, ENOTSUP );
284 }
285 }
286
287 // TODO process received ipopts?
288 result = ip_client_process_packet( packet, NULL, NULL, NULL, NULL, NULL );
289// printf("ip len %d\n", result );
290 if( result < 0 ){
291 return tcp_release_and_return( packet, result );
292 }
293 offset = ( size_t ) result;
294
295 length = packet_get_data_length( packet );
296// printf("packet len %d\n", length );
297 if( length <= 0 ){
298 return tcp_release_and_return( packet, EINVAL );
299 }
300 if( length < TCP_HEADER_SIZE + offset ){
301 return tcp_release_and_return( packet, NO_DATA );
302 }
303
304 // trim all but TCP header
305 if( ERROR_OCCURRED( packet_trim( packet, offset, 0 ))){
306 return tcp_release_and_return( packet, ERROR_CODE );
307 }
308
309 // get tcp header
310 header = ( tcp_header_ref ) packet_get_data( packet );
311 if( ! header ){
312 return tcp_release_and_return( packet, NO_DATA );
313 }
314// printf( "header len %d, port %d \n", TCP_HEADER_LENGTH( header ), ntohs( header->destination_port ));
315
316 result = packet_get_addr( packet, ( uint8_t ** ) & src, ( uint8_t ** ) & dest );
317 if( result <= 0 ){
318 return tcp_release_and_return( packet, result );
319 }
320 addrlen = ( size_t ) result;
321
322 if( ERROR_OCCURRED( tl_set_address_port( src, addrlen, ntohs( header->source_port )))){
323 return tcp_release_and_return( packet, ERROR_CODE );
324 }
325
326 // find the destination socket
327 socket = socket_port_find( & tcp_globals.sockets, ntohs( header->destination_port ), ( const char * ) src, addrlen );
328 if( ! socket ){
329// printf("listening?\n");
330 // find the listening destination socket
331 socket = socket_port_find( & tcp_globals.sockets, ntohs( header->destination_port ), SOCKET_MAP_KEY_LISTENING, 0 );
332 if( ! socket ){
333 if( tl_prepare_icmp_packet( tcp_globals.net_phone, tcp_globals.icmp_phone, packet, error ) == EOK ){
334 icmp_destination_unreachable_msg( tcp_globals.icmp_phone, ICMP_PORT_UNREACH, 0, packet );
335 }
336 return EADDRNOTAVAIL;
337 }
338 }
339 printf("socket id %d\n", socket->socket_id );
340 socket_data = ( tcp_socket_data_ref ) socket->specific_data;
341 assert( socket_data );
342
343 // some data received, clear the timeout counter
344 socket_data->timeout_count = 0;
345
346 // count the received packet fragments
347 next_packet = packet;
348 fragments = 0;
349 checksum = 0;
350 total_length = 0;
351 do{
352 ++ fragments;
353 length = packet_get_data_length( next_packet );
354 if( length <= 0 ){
355 return tcp_release_and_return( packet, NO_DATA );
356 }
357 total_length += length;
358 // add partial checksum if set
359 if( ! error ){
360 checksum = compute_checksum( checksum, packet_get_data( packet ), packet_get_data_length( packet ));
361 }
362 }while(( next_packet = pq_next( next_packet )));
363// printf( "fragments %d of %d bytes\n", fragments, total_length );
364
365// printf("lock?\n");
366 fibril_rwlock_write_lock( socket_data->local_lock );
367// printf("locked\n");
368 if( ! error ){
369 if( socket_data->state == TCP_SOCKET_LISTEN ){
370 if( socket_data->pseudo_header ){
371 free( socket_data->pseudo_header );
372 socket_data->pseudo_header = NULL;
373 socket_data->headerlen = 0;
374 }
375 if( ERROR_OCCURRED( ip_client_get_pseudo_header( IPPROTO_TCP, src, addrlen, dest, addrlen, total_length, & socket_data->pseudo_header, & socket_data->headerlen ))){
376 fibril_rwlock_write_unlock( socket_data->local_lock );
377 return tcp_release_and_return( packet, ERROR_CODE );
378 }
379 }else if( ERROR_OCCURRED( ip_client_set_pseudo_header_data_length( socket_data->pseudo_header, socket_data->headerlen, total_length ))){
380 fibril_rwlock_write_unlock( socket_data->local_lock );
381 return tcp_release_and_return( packet, ERROR_CODE );
382 }
383 checksum = compute_checksum( checksum, socket_data->pseudo_header, socket_data->headerlen );
384 if( flip_checksum( compact_checksum( checksum ))){
385 printf( "checksum err %x -> %x\n", header->checksum, flip_checksum( compact_checksum( checksum )));
386 fibril_rwlock_write_unlock( socket_data->local_lock );
387 if( ! ERROR_OCCURRED( tl_prepare_icmp_packet( tcp_globals.net_phone, tcp_globals.icmp_phone, packet, error ))){
388 // checksum error ICMP
389 icmp_parameter_problem_msg( tcp_globals.icmp_phone, ICMP_PARAM_POINTER, (( size_t ) (( void * ) & header->checksum )) - (( size_t ) (( void * ) header )), packet );
390 }
391 return EINVAL;
392 }
393 }
394
395 fibril_rwlock_read_unlock( & tcp_globals.lock );
396
397 // TODO error reporting/handling
398// printf( "st %d\n", socket_data->state );
399 switch( socket_data->state ){
400 case TCP_SOCKET_LISTEN:
401 ERROR_CODE = tcp_process_listen( socket, socket_data, header, packet, src, dest, addrlen );
402 break;
403 case TCP_SOCKET_SYN_RECEIVED:
404 ERROR_CODE = tcp_process_syn_received( socket, socket_data, header, packet );
405 break;
406 case TCP_SOCKET_SYN_SENT:
407 ERROR_CODE = tcp_process_syn_sent( socket, socket_data, header, packet );
408 break;
409 case TCP_SOCKET_FIN_WAIT_1:
410 // ack changing the state to FIN_WAIT_2 gets processed later
411 case TCP_SOCKET_FIN_WAIT_2:
412 // fin changing state to LAST_ACK gets processed later
413 case TCP_SOCKET_LAST_ACK:
414 // ack releasing the socket get processed later
415 case TCP_SOCKET_CLOSING:
416 // ack releasing the socket gets processed later
417 case TCP_SOCKET_ESTABLISHED:
418 ERROR_CODE = tcp_process_established( socket, socket_data, header, packet, fragments, total_length );
419 break;
420 default:
421 pq_release( tcp_globals.net_phone, packet_get_id( packet ));
422 }
423
424 if( ERROR_CODE != EOK ){
425 printf( "process %d\n", ERROR_CODE );
426 fibril_rwlock_write_unlock( socket_data->local_lock );
427 }
428 return EOK;
429}
430
431int tcp_process_established( socket_core_ref socket, tcp_socket_data_ref socket_data, tcp_header_ref header, packet_t packet, int fragments, size_t total_length ){
432 ERROR_DECLARE;
433
434 packet_t next_packet;
435 packet_t tmp_packet;
436 uint32_t old_incoming;
437 size_t order;
438 uint32_t sequence_number;
439 size_t length;
440 size_t offset;
441 uint32_t new_sequence_number;
442
443 assert( socket );
444 assert( socket_data );
445 assert( socket->specific_data == socket_data );
446 assert( header );
447 assert( packet );
448
449 new_sequence_number = ntohl( header->sequence_number );
450 old_incoming = socket_data->next_incoming;
451
452 if( header->finalize ){
453 socket_data->fin_incoming = new_sequence_number;
454 }
455
456// printf( "pe %d < %d <= %d\n", new_sequence_number, socket_data->next_incoming, new_sequence_number + total_length );
457 // trim begining if containing expected data
458 if( IS_IN_INTERVAL_OVERFLOW( new_sequence_number, socket_data->next_incoming, new_sequence_number + total_length )){
459 // get the acknowledged offset
460 if( socket_data->next_incoming < new_sequence_number ){
461 offset = new_sequence_number - socket_data->next_incoming;
462 }else{
463 offset = socket_data->next_incoming - new_sequence_number;
464 }
465// printf( "offset %d\n", offset );
466 new_sequence_number += offset;
467 total_length -= offset;
468 length = packet_get_data_length( packet );
469 // trim the acknowledged data
470 while( length <= offset ){
471 // release the acknowledged packets
472 next_packet = pq_next( packet );
473 pq_release( tcp_globals.net_phone, packet_get_id( packet ));
474 packet = next_packet;
475 offset -= length;
476 length = packet_get_data_length( packet );
477 }
478 if(( offset > 0 )
479 && ( ERROR_OCCURRED( packet_trim( packet, offset, 0 )))){
480 return tcp_release_and_return( packet, ERROR_CODE );
481 }
482 assert( new_sequence_number == socket_data->next_incoming );
483 }
484
485 // release if overflowing the window
486// if( IS_IN_INTERVAL_OVERFLOW( socket_data->next_incoming + socket_data->window, new_sequence_number, new_sequence_number + total_length )){
487// return tcp_release_and_return( packet, EOVERFLOW );
488// }
489
490/*
491 // trim end if overflowing the window
492 if( IS_IN_INTERVAL_OVERFLOW( new_sequence_number, socket_data->next_incoming + socket_data->window, new_sequence_number + total_length )){
493 // get the allowed data length
494 if( socket_data->next_incoming + socket_data->window < new_sequence_number ){
495 offset = new_sequence_number - socket_data->next_incoming + socket_data->window;
496 }else{
497 offset = socket_data->next_incoming + socket_data->window - new_sequence_number;
498 }
499 next_packet = packet;
500 // trim the overflowing data
501 while( next_packet && ( offset > 0 )){
502 length = packet_get_data_length( packet );
503 if( length <= offset ){
504 next_packet = pq_next( next_packet );
505 }else if( ERROR_OCCURRED( packet_trim( next_packet, 0, length - offset ))){
506 return tcp_release_and_return( packet, ERROR_CODE );
507 }
508 offset -= length;
509 total_length -= length - offset;
510 }
511 // release the overflowing packets
512 next_packet = pq_next( next_packet );
513 if( next_packet ){
514 tmp_packet = next_packet;
515 next_packet = pq_next( next_packet );
516 pq_insert_after( tmp_packet, next_packet );
517 pq_release( tcp_globals.net_phone, packet_get_id( tmp_packet ));
518 }
519 assert( new_sequence_number + total_length == socket_data->next_incoming + socket_data->window );
520 }
521*/
522 // the expected one arrived?
523 if( new_sequence_number == socket_data->next_incoming ){
524 printf("expected\n");
525 // process acknowledgement
526 tcp_process_acknowledgement( socket, socket_data, header );
527
528 // remove the header
529 total_length -= TCP_HEADER_LENGTH( header );
530 if( ERROR_OCCURRED( packet_trim( packet, TCP_HEADER_LENGTH( header ), 0 ))){
531 return tcp_release_and_return( packet, ERROR_CODE );
532 }
533
534 if( total_length ){
535 ERROR_PROPAGATE( tcp_queue_received_packet( socket, socket_data, packet, fragments, total_length ));
536 }else{
537 total_length = 1;
538 }
539 socket_data->next_incoming = old_incoming + total_length;
540 packet = socket_data->incoming;
541 while( packet ){
542 if( ERROR_OCCURRED( pq_get_order( socket_data->incoming, & order, NULL ))){
543 // remove the corrupted packet
544 next_packet = pq_detach( packet );
545 if( packet == socket_data->incoming ){
546 socket_data->incoming = next_packet;
547 }
548 pq_release( tcp_globals.net_phone, packet_get_id( packet ));
549 packet = next_packet;
550 continue;
551 }
552 sequence_number = ( uint32_t ) order;
553 if( IS_IN_INTERVAL_OVERFLOW( sequence_number, old_incoming, socket_data->next_incoming )){
554 // move to the next
555 packet = pq_next( packet );
556 // coninual data?
557 }else if( IS_IN_INTERVAL_OVERFLOW( old_incoming, sequence_number, socket_data->next_incoming )){
558 // detach the packet
559 next_packet = pq_detach( packet );
560 if( packet == socket_data->incoming ){
561 socket_data->incoming = next_packet;
562 }
563 // get data length
564 length = packet_get_data_length( packet );
565 new_sequence_number = sequence_number + length;
566 if( length <= 0 ){
567 // remove the empty packet
568 pq_release( tcp_globals.net_phone, packet_get_id( packet ));
569 packet = next_packet;
570 continue;
571 }
572 // exactly following
573 if( sequence_number == socket_data->next_incoming ){
574 // queue received data
575 ERROR_PROPAGATE( tcp_queue_received_packet( socket, socket_data, packet, 1, packet_get_data_length( packet )));
576 socket_data->next_incoming = new_sequence_number;
577 packet = next_packet;
578 continue;
579 // at least partly following data?
580 }else if( IS_IN_INTERVAL_OVERFLOW( sequence_number, socket_data->next_incoming, new_sequence_number )){
581 if( socket_data->next_incoming < new_sequence_number ){
582 length = new_sequence_number - socket_data->next_incoming;
583 }else{
584 length = socket_data->next_incoming - new_sequence_number;
585 }
586 if( ! ERROR_OCCURRED( packet_trim( packet, length, 0 ))){
587 // queue received data
588 ERROR_PROPAGATE( tcp_queue_received_packet( socket, socket_data, packet, 1, packet_get_data_length( packet )));
589 socket_data->next_incoming = new_sequence_number;
590 packet = next_packet;
591 continue;
592 }
593 }
594 // remove the duplicit or corrupted packet
595 pq_release( tcp_globals.net_phone, packet_get_id( packet ));
596 packet = next_packet;
597 continue;
598 }else{
599 break;
600 }
601 }
602 }else if( IS_IN_INTERVAL( socket_data->next_incoming, new_sequence_number, socket_data->next_incoming + socket_data->window )){
603 printf("in window\n");
604 // process acknowledgement
605 tcp_process_acknowledgement( socket, socket_data, header );
606
607 // remove the header
608 total_length -= TCP_HEADER_LENGTH( header );
609 if( ERROR_OCCURRED( packet_trim( packet, TCP_HEADER_LENGTH( header ), 0 ))){
610 return tcp_release_and_return( packet, ERROR_CODE );
611 }
612
613 next_packet = pq_detach( packet );
614 length = packet_get_data_length( packet );
615 tmp_packet = pq_add( socket_data->incoming, packet, new_sequence_number, length );
616 if( ! tmp_packet ){
617 // remove the corrupted packets
618 pq_release( tcp_globals.net_phone, packet_get_id( packet ));
619 pq_release( tcp_globals.net_phone, packet_get_id( next_packet ));
620 }else{
621 socket_data->incoming = tmp_packet;
622 while( next_packet ){
623 new_sequence_number += length;
624 tmp_packet = pq_detach( next_packet );
625 length = packet_get_data_length( next_packet );
626 if( ERROR_OCCURRED( pq_set_order( next_packet, new_sequence_number, length ))
627 || ERROR_OCCURRED( pq_insert_after( packet, next_packet ))){
628 pq_release( tcp_globals.net_phone, packet_get_id( next_packet ));
629 }
630 next_packet = tmp_packet;
631 }
632 }
633 }else{
634 printf("unexpected\n");
635 // release duplicite or restricted
636 pq_release( tcp_globals.net_phone, packet_get_id( packet ));
637 }
638
639 // change state according to the acknowledging incoming fin
640 if( IS_IN_INTERVAL_OVERFLOW( old_incoming, socket_data->fin_incoming, socket_data->next_incoming )){
641 switch( socket_data->state ){
642 case TCP_SOCKET_FIN_WAIT_1:
643 case TCP_SOCKET_FIN_WAIT_2:
644 case TCP_SOCKET_CLOSING:
645 socket_data->state = TCP_SOCKET_CLOSING;
646 break;
647 //case TCP_ESTABLISHED:
648 default:
649 socket_data->state = TCP_SOCKET_CLOSE_WAIT;
650 break;
651 }
652 }
653
654 packet = tcp_get_packets_to_send( socket, socket_data );
655 if( ! packet ){
656 // create the notification packet
657 ERROR_PROPAGATE( tcp_create_notification_packet( & packet, socket, socket_data, 0, 0 ));
658 ERROR_PROPAGATE( tcp_queue_prepare_packet( socket, socket_data, packet, 1 ));
659 packet = tcp_send_prepare_packet( socket, socket_data, packet, 1, socket_data->last_outgoing + 1 );
660 }
661 fibril_rwlock_write_unlock( socket_data->local_lock );
662 // send the packet
663 tcp_send_packets( socket_data->device_id, packet );
664 return EOK;
665}
666
667int tcp_queue_received_packet( socket_core_ref socket, tcp_socket_data_ref socket_data, packet_t packet, int fragments, size_t total_length ){
668 ERROR_DECLARE;
669
670 packet_dimension_ref packet_dimension;
671
672 assert( socket );
673 assert( socket_data );
674 assert( socket->specific_data == socket_data );
675 assert( packet );
676 assert( fragments >= 1 );
677 assert( socket_data->window > total_length );
678
679 // queue the received packet
680 if( ERROR_OCCURRED( dyn_fifo_push( & socket->received, packet_get_id( packet ), SOCKET_MAX_RECEIVED_SIZE ))
681 || ERROR_OCCURRED( tl_get_ip_packet_dimension( tcp_globals.ip_phone, & tcp_globals.dimensions, socket_data->device_id, & packet_dimension ))){
682 return tcp_release_and_return( packet, ERROR_CODE );
683 }
684
685 // decrease the window size
686 socket_data->window -= total_length;
687
688 // notify the destination socket
689 async_msg_5( socket->phone, NET_SOCKET_RECEIVED, ( ipcarg_t ) socket->socket_id, (( packet_dimension->content < socket_data->data_fragment_size ) ? packet_dimension->content : socket_data->data_fragment_size ), 0, 0, ( ipcarg_t ) fragments );
690 return EOK;
691}
692
693int tcp_process_syn_sent( socket_core_ref socket, tcp_socket_data_ref socket_data, tcp_header_ref header, packet_t packet ){
694 ERROR_DECLARE;
695
696 packet_t next_packet;
697
698 assert( socket );
699 assert( socket_data );
700 assert( socket->specific_data == socket_data );
701 assert( header );
702 assert( packet );
703
704 if( header->synchronize ){
705 // process acknowledgement
706 tcp_process_acknowledgement( socket, socket_data, header );
707
708 socket_data->next_incoming = ntohl( header->sequence_number ) + 1;
709 // release additional packets
710 next_packet = pq_detach( packet );
711 if( next_packet ){
712 pq_release( tcp_globals.net_phone, packet_get_id( next_packet ));
713 }
714 // trim if longer than the header
715 if(( packet_get_data_length( packet ) > sizeof( * header ))
716 && ERROR_OCCURRED( packet_trim( packet, 0, packet_get_data_length( packet ) - sizeof( * header )))){
717 return tcp_release_and_return( packet, ERROR_CODE );
718 }
719 tcp_prepare_operation_header( socket, socket_data, header, 0, 0 );
720 fibril_mutex_lock( & socket_data->operation.mutex );
721 socket_data->operation.result = tcp_queue_packet( socket, socket_data, packet, 1 );
722 if( socket_data->operation.result == EOK ){
723 socket_data->state = TCP_SOCKET_ESTABLISHED;
724 packet = tcp_get_packets_to_send( socket, socket_data );
725 if( packet ){
726 fibril_rwlock_write_unlock( socket_data->local_lock );
727 // send the packet
728 tcp_send_packets( socket_data->device_id, packet );
729 // signal the result
730 fibril_condvar_signal( & socket_data->operation.condvar );
731 fibril_mutex_unlock( & socket_data->operation.mutex );
732 return EOK;
733 }
734 }
735 fibril_mutex_unlock( & socket_data->operation.mutex );
736 }
737 return tcp_release_and_return( packet, EINVAL );
738}
739
740int tcp_process_listen( socket_core_ref listening_socket, tcp_socket_data_ref listening_socket_data, tcp_header_ref header, packet_t packet, struct sockaddr * src, struct sockaddr * dest, size_t addrlen ){
741 ERROR_DECLARE;
742
743 packet_t next_packet;
744 socket_core_ref socket;
745 tcp_socket_data_ref socket_data;
746 int socket_id;
747 int listening_socket_id = listening_socket->socket_id;
748 int listening_port = listening_socket->port;
749
750 assert( listening_socket );
751 assert( listening_socket_data );
752 assert( listening_socket->specific_data == listening_socket_data );
753 assert( header );
754 assert( packet );
755
756// printf( "syn %d\n", header->synchronize );
757 if( header->synchronize ){
758 socket_data = ( tcp_socket_data_ref ) malloc( sizeof( * socket_data ));
759 if( ! socket_data ){
760 return tcp_release_and_return( packet, ENOMEM );
761 }else{
762 tcp_initialize_socket_data( socket_data );
763 socket_data->local_lock = listening_socket_data->local_lock;
764 socket_data->local_sockets = listening_socket_data->local_sockets;
765 socket_data->listening_socket_id = listening_socket->socket_id;
766
767 socket_data->next_incoming = ntohl( header->sequence_number );
768 socket_data->treshold = socket_data->next_incoming + ntohs( header->window );
769
770 socket_data->addrlen = addrlen;
771 socket_data->addr = malloc( socket_data->addrlen );
772 if( ! socket_data->addr ){
773 free( socket_data );
774 return tcp_release_and_return( packet, ENOMEM );
775 }
776 memcpy( socket_data->addr, src, socket_data->addrlen );
777
778 socket_data->dest_port = ntohs( header->source_port );
779 if( ERROR_OCCURRED( tl_set_address_port( socket_data->addr, socket_data->addrlen, socket_data->dest_port ))){
780 free( socket_data->addr );
781 free( socket_data );
782 pq_release( tcp_globals.net_phone, packet_get_id( packet ));
783 return ERROR_CODE;
784 }
785
786// printf( "addr %p\n", socket_data->addr, socket_data->addrlen );
787 // create a socket
788 socket_id = -1;
789 if( ERROR_OCCURRED( socket_create( socket_data->local_sockets, listening_socket->phone, socket_data, & socket_id ))){
790 free( socket_data->addr );
791 free( socket_data );
792 return tcp_release_and_return( packet, ERROR_CODE );
793 }
794
795 socket_id *= -1;
796 printf("new_sock %d\n", socket_id);
797 socket_data->pseudo_header = listening_socket_data->pseudo_header;
798 socket_data->headerlen = listening_socket_data->headerlen;
799 listening_socket_data->pseudo_header = NULL;
800 listening_socket_data->headerlen = 0;
801
802 fibril_rwlock_write_unlock( socket_data->local_lock );
803// printf("list lg\n");
804 fibril_rwlock_write_lock( & tcp_globals.lock );
805// printf("list locked\n");
806 // find the destination socket
807 listening_socket = socket_port_find( & tcp_globals.sockets, listening_port, SOCKET_MAP_KEY_LISTENING, 0 );
808 if(( ! listening_socket ) || ( listening_socket->socket_id != listening_socket_id )){
809 fibril_rwlock_write_unlock( & tcp_globals.lock );
810 // a shadow may remain until app hangs up
811 return tcp_release_and_return( packet, EOK/*ENOTSOCK*/ );
812 }
813// printf("port %d\n", listening_socket->port );
814 listening_socket_data = ( tcp_socket_data_ref ) listening_socket->specific_data;
815 assert( listening_socket_data );
816
817// printf("list ll\n");
818 fibril_rwlock_write_lock( listening_socket_data->local_lock );
819// printf("list locked\n");
820
821 socket = socket_cores_find( listening_socket_data->local_sockets, socket_id );
822 if( ! socket ){
823 // where is the socket?!?
824 fibril_rwlock_write_unlock( & tcp_globals.lock );
825 return ENOTSOCK;
826 }
827 socket_data = ( tcp_socket_data_ref ) socket->specific_data;
828 assert( socket_data );
829
830// uint8_t * data = socket_data->addr;
831// printf( "addr %d of %x %x %x %x-%x %x %x %x-%x %x %x %x-%x %x %x %x\n", socket_data->addrlen, 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 ] );
832
833 ERROR_CODE = socket_port_add( & tcp_globals.sockets, listening_port, socket, ( const char * ) socket_data->addr, socket_data->addrlen );
834 assert( socket == socket_port_find( & tcp_globals.sockets, listening_port, ( const char * ) socket_data->addr, socket_data->addrlen ));
835 //ERROR_CODE = socket_bind_free_port( & tcp_globals.sockets, socket, TCP_FREE_PORTS_START, TCP_FREE_PORTS_END, tcp_globals.last_used_port );
836 //tcp_globals.last_used_port = socket->port;
837// printf("bound %d\n", socket->port );
838 fibril_rwlock_write_unlock( & tcp_globals.lock );
839 if( ERROR_CODE != EOK ){
840 socket_destroy( tcp_globals.net_phone, socket->socket_id, socket_data->local_sockets, & tcp_globals.sockets, tcp_free_socket_data );
841 return tcp_release_and_return( packet, ERROR_CODE );
842 }
843
844 socket_data->state = TCP_SOCKET_LISTEN;
845 socket_data->next_incoming = ntohl( header->sequence_number ) + 1;
846 // release additional packets
847 next_packet = pq_detach( packet );
848 if( next_packet ){
849 pq_release( tcp_globals.net_phone, packet_get_id( next_packet ));
850 }
851 // trim if longer than the header
852 if(( packet_get_data_length( packet ) > sizeof( * header ))
853 && ERROR_OCCURRED( packet_trim( packet, 0, packet_get_data_length( packet ) - sizeof( * header )))){
854 socket_destroy( tcp_globals.net_phone, socket->socket_id, socket_data->local_sockets, & tcp_globals.sockets, tcp_free_socket_data );
855 return tcp_release_and_return( packet, ERROR_CODE );
856 }
857 tcp_prepare_operation_header( socket, socket_data, header, 1, 0 );
858 if( ERROR_OCCURRED( tcp_queue_packet( socket, socket_data, packet, 1 ))){
859 socket_destroy( tcp_globals.net_phone, socket->socket_id, socket_data->local_sockets, & tcp_globals.sockets, tcp_free_socket_data );
860 return ERROR_CODE;
861 }
862 packet = tcp_get_packets_to_send( socket, socket_data );
863// printf("send %d\n", packet_get_id( packet ));
864 if( ! packet ){
865 socket_destroy( tcp_globals.net_phone, socket->socket_id, socket_data->local_sockets, & tcp_globals.sockets, tcp_free_socket_data );
866 return EINVAL;
867 }else{
868 socket_data->state = TCP_SOCKET_SYN_RECEIVED;
869// printf("unlock\n");
870 fibril_rwlock_write_unlock( socket_data->local_lock );
871 // send the packet
872 tcp_send_packets( socket_data->device_id, packet );
873 return EOK;
874 }
875 }
876 }
877 return tcp_release_and_return( packet, EINVAL );
878}
879
880int tcp_process_syn_received( socket_core_ref socket, tcp_socket_data_ref socket_data, tcp_header_ref header, packet_t packet ){
881 ERROR_DECLARE;
882
883 socket_core_ref listening_socket;
884 tcp_socket_data_ref listening_socket_data;
885
886 assert( socket );
887 assert( socket_data );
888 assert( socket->specific_data == socket_data );
889 assert( header );
890 assert( packet );
891
892 printf("syn_rec\n");
893 if( header->acknowledge ){
894 // process acknowledgement
895 tcp_process_acknowledgement( socket, socket_data, header );
896
897 socket_data->next_incoming = ntohl( header->sequence_number );// + 1;
898 pq_release( tcp_globals.net_phone, packet_get_id( packet ));
899 socket_data->state = TCP_SOCKET_ESTABLISHED;
900 listening_socket = socket_cores_find( socket_data->local_sockets, socket_data->listening_socket_id );
901 if( listening_socket ){
902 listening_socket_data = ( tcp_socket_data_ref ) listening_socket->specific_data;
903 assert( listening_socket_data );
904
905 // queue the received packet
906 if( ! ERROR_OCCURRED( dyn_fifo_push( & listening_socket->accepted, socket->socket_id, listening_socket_data->backlog ))){
907 // notify the destination socket
908 async_msg_5( socket->phone, NET_SOCKET_ACCEPTED, ( ipcarg_t ) listening_socket->socket_id, socket_data->data_fragment_size, TCP_HEADER_SIZE, 0, ( ipcarg_t ) socket->socket_id );
909 fibril_rwlock_write_unlock( socket_data->local_lock );
910 return EOK;
911 }
912 }
913 // send FIN
914 socket_data->state = TCP_SOCKET_FIN_WAIT_1;
915
916 // create the notification packet
917 ERROR_PROPAGATE( tcp_create_notification_packet( & packet, socket, socket_data, 0, 1 ));
918
919 // send the packet
920 ERROR_PROPAGATE( tcp_queue_packet( socket, socket_data, packet, 1 ));
921
922 // flush packets
923 packet = tcp_get_packets_to_send( socket, socket_data );
924 fibril_rwlock_write_unlock( socket_data->local_lock );
925 if( packet ){
926 // send the packet
927 tcp_send_packets( socket_data->device_id, packet );
928 }
929 return EOK;
930 }else{
931 return tcp_release_and_return( packet, EINVAL );
932 }
933 return EINVAL;
934}
935
936void tcp_process_acknowledgement( socket_core_ref socket, tcp_socket_data_ref socket_data, tcp_header_ref header ){
937 size_t number;
938 size_t length;
939 packet_t packet;
940 packet_t next;
941 packet_t acknowledged = NULL;
942 packet_t first;
943 uint32_t old;
944
945 assert( socket );
946 assert( socket_data );
947 assert( socket->specific_data == socket_data );
948 assert( header );
949
950 if( header->acknowledge ){
951 number = ntohl( header->acknowledgement_number );
952 // if more data acknowledged
953 if( number != socket_data->expected ){
954 old = socket_data->expected;
955 if( IS_IN_INTERVAL_OVERFLOW( old, socket_data->fin_outgoing, number )){
956 switch( socket_data->state ){
957 case TCP_SOCKET_FIN_WAIT_1:
958 socket_data->state = TCP_SOCKET_FIN_WAIT_2;
959 break;
960 case TCP_SOCKET_LAST_ACK:
961 case TCP_SOCKET_CLOSING:
962 // fin acknowledged - release the socket in another fibril
963 tcp_prepare_timeout( tcp_release_after_timeout, socket, socket_data, 0, TCP_SOCKET_TIME_WAIT, NET_DEFAULT_TCP_TIME_WAIT_TIMEOUT, true );
964 break;
965 default:
966 break;
967 }
968 }
969 // update the treshold if higher than set
970 if( number + ntohs( header->window ) > socket_data->expected + socket_data->treshold ){
971 socket_data->treshold = number + ntohs( header->window ) - socket_data->expected;
972 }
973 // set new expected sequence number
974 socket_data->expected = number;
975 socket_data->expected_count = 1;
976 packet = socket_data->outgoing;
977 while( pq_get_order( packet, & number, & length ) == EOK ){
978 if( IS_IN_INTERVAL_OVERFLOW(( uint32_t ) old, ( uint32_t )( number + length ), ( uint32_t ) socket_data->expected )){
979 next = pq_detach( packet );
980 if( packet == socket_data->outgoing ){
981 socket_data->outgoing = next;
982 }
983 // add to acknowledged or release
984 first = pq_add( acknowledged, packet, 0, 0 );
985 if( first ){
986 acknowledged = first;
987 }else{
988 pq_release( tcp_globals.net_phone, packet_get_id( packet ));
989 }
990 packet = next;
991 }else if( old < socket_data->expected ){
992 break;
993 }
994 }
995 // release acknowledged
996 if( acknowledged ){
997 pq_release( tcp_globals.net_phone, packet_get_id( acknowledged ));
998 }
999 return;
1000 // if the same as the previous time
1001 }else if( number == socket_data->expected ){
1002 // increase the counter
1003 ++ socket_data->expected_count;
1004 if( socket_data->expected_count == TCP_FAST_RETRANSMIT_COUNT ){
1005 socket_data->expected_count = 1;
1006 // TODO retransmit lock
1007 //tcp_retransmit_packet( socket, socket_data, number );
1008 }
1009 }
1010 }
1011}
1012
1013int tcp_message( ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count ){
1014 ERROR_DECLARE;
1015
1016 packet_t packet;
1017
1018 assert( call );
1019 assert( answer );
1020 assert( answer_count );
1021
1022 * answer_count = 0;
1023 switch( IPC_GET_METHOD( * call )){
1024 case NET_TL_RECEIVED:
1025 //fibril_rwlock_read_lock( & tcp_globals.lock );
1026 if( ! ERROR_OCCURRED( packet_translate( tcp_globals.net_phone, & packet, IPC_GET_PACKET( call )))){
1027 ERROR_CODE = tcp_received_msg( IPC_GET_DEVICE( call ), packet, SERVICE_TCP, IPC_GET_ERROR( call ));
1028 }
1029 //fibril_rwlock_read_unlock( & tcp_globals.lock );
1030 return ERROR_CODE;
1031 case IPC_M_CONNECT_TO_ME:
1032 return tcp_process_client_messages( callid, * call );
1033 }
1034 return ENOTSUP;
1035}
1036
1037void tcp_refresh_socket_data( tcp_socket_data_ref socket_data ){
1038 assert( socket_data );
1039
1040 bzero( socket_data, sizeof( * socket_data ));
1041 socket_data->state = TCP_SOCKET_INITIAL;
1042 socket_data->device_id = DEVICE_INVALID_ID;
1043 socket_data->window = NET_DEFAULT_TCP_WINDOW;
1044 socket_data->treshold = socket_data->window;
1045 socket_data->last_outgoing = TCP_INITIAL_SEQUENCE_NUMBER;
1046 socket_data->timeout = NET_DEFAULT_TCP_INITIAL_TIMEOUT;
1047 socket_data->acknowledged = socket_data->last_outgoing;
1048 socket_data->next_outgoing = socket_data->last_outgoing + 1;
1049 socket_data->expected = socket_data->next_outgoing;
1050}
1051
1052void tcp_initialize_socket_data( tcp_socket_data_ref socket_data ){
1053 assert( socket_data );
1054
1055 tcp_refresh_socket_data( socket_data );
1056 fibril_mutex_initialize( & socket_data->operation.mutex );
1057 fibril_condvar_initialize( & socket_data->operation.condvar );
1058 socket_data->data_fragment_size = MAX_TCP_FRAGMENT_SIZE;
1059}
1060
1061int tcp_process_client_messages( ipc_callid_t callid, ipc_call_t call ){
1062 int res;
1063 bool keep_on_going = true;
1064 socket_cores_t local_sockets;
1065 int app_phone = IPC_GET_PHONE( & call );
1066 struct sockaddr * addr;
1067 size_t addrlen;
1068 fibril_rwlock_t lock;
1069 ipc_call_t answer;
1070 int answer_count;
1071 tcp_socket_data_ref socket_data;
1072 socket_core_ref socket;
1073 packet_dimension_ref packet_dimension;
1074
1075 /*
1076 * Accept the connection
1077 * - Answer the first IPC_M_CONNECT_ME_TO call.
1078 */
1079 ipc_answer_0( callid, EOK );
1080
1081 socket_cores_initialize( & local_sockets );
1082 fibril_rwlock_initialize( & lock );
1083
1084 while( keep_on_going ){
1085 // refresh data
1086 refresh_answer( & answer, & answer_count );
1087
1088 callid = async_get_call( & call );
1089// printf( "message %d\n", IPC_GET_METHOD( * call ));
1090
1091 switch( IPC_GET_METHOD( call )){
1092 case IPC_M_PHONE_HUNGUP:
1093 keep_on_going = false;
1094 res = EOK;
1095 break;
1096 case NET_SOCKET:
1097 socket_data = ( tcp_socket_data_ref ) malloc( sizeof( * socket_data ));
1098 if( ! socket_data ){
1099 res = ENOMEM;
1100 }else{
1101 tcp_initialize_socket_data( socket_data );
1102 socket_data->local_lock = & lock;
1103 socket_data->local_sockets = & local_sockets;
1104 fibril_rwlock_write_lock( & lock );
1105 * SOCKET_SET_SOCKET_ID( answer ) = SOCKET_GET_SOCKET_ID( call );
1106 res = socket_create( & local_sockets, app_phone, socket_data, SOCKET_SET_SOCKET_ID( answer ));
1107 fibril_rwlock_write_unlock( & lock );
1108 if( res == EOK ){
1109 if( tl_get_ip_packet_dimension( tcp_globals.ip_phone, & tcp_globals.dimensions, DEVICE_INVALID_ID, & packet_dimension ) == EOK ){
1110 * SOCKET_SET_DATA_FRAGMENT_SIZE( answer ) = (( packet_dimension->content < socket_data->data_fragment_size ) ? packet_dimension->content : socket_data->data_fragment_size );
1111 }
1112// * SOCKET_SET_DATA_FRAGMENT_SIZE( answer ) = MAX_TCP_FRAGMENT_SIZE;
1113 * SOCKET_SET_HEADER_SIZE( answer ) = TCP_HEADER_SIZE;
1114 answer_count = 3;
1115 }else{
1116 free( socket_data );
1117 }
1118 }
1119 break;
1120 case NET_SOCKET_BIND:
1121 res = data_receive(( void ** ) & addr, & addrlen );
1122 if( res == EOK ){
1123 fibril_rwlock_write_lock( & tcp_globals.lock );
1124 fibril_rwlock_write_lock( & lock );
1125 res = socket_bind( & local_sockets, & tcp_globals.sockets, SOCKET_GET_SOCKET_ID( call ), addr, addrlen, TCP_FREE_PORTS_START, TCP_FREE_PORTS_END, tcp_globals.last_used_port );
1126 if( res == EOK ){
1127 socket = socket_cores_find( & local_sockets, SOCKET_GET_SOCKET_ID( call ));
1128 if( socket ){
1129 socket_data = ( tcp_socket_data_ref ) socket->specific_data;
1130 assert( socket_data );
1131 socket_data->state = TCP_SOCKET_LISTEN;
1132 }
1133 }
1134 fibril_rwlock_write_unlock( & lock );
1135 fibril_rwlock_write_unlock( & tcp_globals.lock );
1136 free( addr );
1137 }
1138 break;
1139 case NET_SOCKET_LISTEN:
1140 fibril_rwlock_read_lock( & tcp_globals.lock );
1141// fibril_rwlock_write_lock( & tcp_globals.lock );
1142 fibril_rwlock_write_lock( & lock );
1143 res = tcp_listen_message( & local_sockets, SOCKET_GET_SOCKET_ID( call ), SOCKET_GET_BACKLOG( call ));
1144 fibril_rwlock_write_unlock( & lock );
1145// fibril_rwlock_write_unlock( & tcp_globals.lock );
1146 fibril_rwlock_read_unlock( & tcp_globals.lock );
1147 break;
1148 case NET_SOCKET_CONNECT:
1149 res = data_receive(( void ** ) & addr, & addrlen );
1150 if( res == EOK ){
1151 // the global lock may be released in the tcp_connect_message() function
1152 fibril_rwlock_write_lock( & tcp_globals.lock );
1153 fibril_rwlock_write_lock( & lock );
1154 res = tcp_connect_message( & local_sockets, SOCKET_GET_SOCKET_ID( call ), addr, addrlen );
1155 if( res != EOK ){
1156 fibril_rwlock_write_unlock( & lock );
1157 fibril_rwlock_write_unlock( & tcp_globals.lock );
1158 free( addr );
1159 }
1160 }
1161 break;
1162 case NET_SOCKET_ACCEPT:
1163 fibril_rwlock_read_lock( & tcp_globals.lock );
1164 fibril_rwlock_write_lock( & lock );
1165 res = tcp_accept_message( & local_sockets, SOCKET_GET_SOCKET_ID( call ), SOCKET_GET_NEW_SOCKET_ID( call ), SOCKET_SET_DATA_FRAGMENT_SIZE( answer ), & addrlen );
1166 fibril_rwlock_write_unlock( & lock );
1167 fibril_rwlock_read_unlock( & tcp_globals.lock );
1168 if( res > 0 ){
1169 * SOCKET_SET_SOCKET_ID( answer ) = res;
1170 * SOCKET_SET_ADDRESS_LENGTH( answer ) = addrlen;
1171 answer_count = 3;
1172 }
1173 break;
1174 case NET_SOCKET_SEND:
1175 fibril_rwlock_read_lock( & tcp_globals.lock );
1176 fibril_rwlock_write_lock( & lock );
1177 res = tcp_send_message( & local_sockets, SOCKET_GET_SOCKET_ID( call ), SOCKET_GET_DATA_FRAGMENTS( call ), SOCKET_SET_DATA_FRAGMENT_SIZE( answer ), SOCKET_GET_FLAGS( call ));
1178 if( res != EOK ){
1179 fibril_rwlock_write_unlock( & lock );
1180 fibril_rwlock_read_unlock( & tcp_globals.lock );
1181 }else{
1182 answer_count = 2;
1183 }
1184 break;
1185 case NET_SOCKET_SENDTO:
1186 res = data_receive(( void ** ) & addr, & addrlen );
1187 if( res == EOK ){
1188 fibril_rwlock_read_lock( & tcp_globals.lock );
1189 fibril_rwlock_write_lock( & lock );
1190 res = tcp_send_message( & local_sockets, SOCKET_GET_SOCKET_ID( call ), SOCKET_GET_DATA_FRAGMENTS( call ), SOCKET_SET_DATA_FRAGMENT_SIZE( answer ), SOCKET_GET_FLAGS( call ));
1191 if( res != EOK ){
1192 fibril_rwlock_write_unlock( & lock );
1193 fibril_rwlock_read_unlock( & tcp_globals.lock );
1194 }else{
1195 answer_count = 2;
1196 }
1197 free( addr );
1198 }
1199 break;
1200 case NET_SOCKET_RECV:
1201 fibril_rwlock_read_lock( & tcp_globals.lock );
1202 fibril_rwlock_write_lock( & lock );
1203 res = tcp_recvfrom_message( & local_sockets, SOCKET_GET_SOCKET_ID( call ), SOCKET_GET_FLAGS( call ), NULL );
1204 fibril_rwlock_write_unlock( & lock );
1205 fibril_rwlock_read_unlock( & tcp_globals.lock );
1206 if( res > 0 ){
1207 * SOCKET_SET_READ_DATA_LENGTH( answer ) = res;
1208 answer_count = 1;
1209 res = EOK;
1210 }
1211 break;
1212 case NET_SOCKET_RECVFROM:
1213 fibril_rwlock_read_lock( & tcp_globals.lock );
1214 fibril_rwlock_write_lock( & lock );
1215 res = tcp_recvfrom_message( & local_sockets, SOCKET_GET_SOCKET_ID( call ), SOCKET_GET_FLAGS( call ), & addrlen );
1216 fibril_rwlock_write_unlock( & lock );
1217 fibril_rwlock_read_unlock( & tcp_globals.lock );
1218 if( res > 0 ){
1219 * SOCKET_SET_READ_DATA_LENGTH( answer ) = res;
1220 * SOCKET_SET_ADDRESS_LENGTH( answer ) = addrlen;
1221 answer_count = 3;
1222 res = EOK;
1223 }
1224 break;
1225 case NET_SOCKET_CLOSE:
1226 fibril_rwlock_write_lock( & tcp_globals.lock );
1227 fibril_rwlock_write_lock( & lock );
1228 res = tcp_close_message( & local_sockets, SOCKET_GET_SOCKET_ID( call ));
1229 if( res != EOK ){
1230 fibril_rwlock_write_unlock( & lock );
1231 fibril_rwlock_write_unlock( & tcp_globals.lock );
1232 }
1233 break;
1234 case NET_SOCKET_GETSOCKOPT:
1235 case NET_SOCKET_SETSOCKOPT:
1236 default:
1237 res = ENOTSUP;
1238 break;
1239 }
1240
1241// printf( "res = %d\n", res );
1242
1243 answer_call( callid, res, & answer, answer_count );
1244 }
1245
1246 printf("release\n");
1247 // release all local sockets
1248 socket_cores_release( tcp_globals.net_phone, & local_sockets, & tcp_globals.sockets, tcp_free_socket_data );
1249
1250 return EOK;
1251}
1252
1253int tcp_timeout( void * data ){
1254 tcp_timeout_ref timeout = data;
1255 int keep_write_lock = false;
1256 socket_core_ref socket;
1257 tcp_socket_data_ref socket_data;
1258
1259 assert( timeout );
1260
1261 // sleep the given timeout
1262 async_usleep( timeout->timeout );
1263 // lock the globals
1264 if( timeout->globals_read_only ){
1265 fibril_rwlock_read_lock( & tcp_globals.lock );
1266 }else{
1267 fibril_rwlock_write_lock( & tcp_globals.lock );
1268 }
1269 // find the pending operation socket
1270 socket = socket_port_find( & tcp_globals.sockets, timeout->port, timeout->key, timeout->key_length );
1271 if( socket && ( socket->socket_id == timeout->socket_id )){
1272 socket_data = ( tcp_socket_data_ref ) socket->specific_data;
1273 assert( socket_data );
1274 if( socket_data->local_sockets == timeout->local_sockets ){
1275 fibril_rwlock_write_lock( socket_data->local_lock );
1276 if( timeout->sequence_number ){
1277 // increase the timeout counter;
1278 ++ socket_data->timeout_count;
1279 if( socket_data->timeout_count == TCP_MAX_TIMEOUTS ){
1280 // TODO release as connection lost
1281 //tcp_refresh_socket_data( socket_data );
1282 }
1283 // retransmit
1284 // TODO enable retransmit
1285 //tcp_retransmit_packet( socket, socket_data, timeout->sequence_number );
1286 fibril_rwlock_write_unlock( socket_data->local_lock );
1287 }else{
1288 fibril_mutex_lock( & socket_data->operation.mutex );
1289 // set the timeout operation result if state not changed
1290 if( socket_data->state == timeout->state ){
1291 socket_data->operation.result = ETIMEOUT;
1292 // notify the main fibril
1293 fibril_condvar_signal( & socket_data->operation.condvar );
1294 // keep the global write lock
1295 keep_write_lock = true;
1296 }else{
1297 // operation is ok, do nothing
1298 // unlocking from now on, so the unlock order does not matter...
1299 fibril_rwlock_write_unlock( socket_data->local_lock );
1300 }
1301 fibril_mutex_unlock( & socket_data->operation.mutex );
1302 }
1303 }
1304 }
1305 // unlock only if no socket
1306 if( timeout->globals_read_only ){
1307 fibril_rwlock_read_unlock( & tcp_globals.lock );
1308 }else if( ! keep_write_lock ){
1309 // release if not desired
1310 fibril_rwlock_write_unlock( & tcp_globals.lock );
1311 }
1312 // release the timeout structure
1313 free( timeout );
1314 return EOK;
1315}
1316
1317int tcp_release_after_timeout( void * data ){
1318 tcp_timeout_ref timeout = data;
1319 socket_core_ref socket;
1320 tcp_socket_data_ref socket_data;
1321 fibril_rwlock_t * local_lock;
1322
1323 assert( timeout );
1324
1325 // sleep the given timeout
1326 async_usleep( timeout->timeout );
1327 // lock the globals
1328 fibril_rwlock_write_lock( & tcp_globals.lock );
1329 // find the pending operation socket
1330 socket = socket_port_find( & tcp_globals.sockets, timeout->port, timeout->key, timeout->key_length );
1331 if( socket && ( socket->socket_id == timeout->socket_id )){
1332 socket_data = ( tcp_socket_data_ref ) socket->specific_data;
1333 assert( socket_data );
1334 if( socket_data->local_sockets == timeout->local_sockets ){
1335 local_lock = socket_data->local_lock;
1336 fibril_rwlock_write_lock( local_lock );
1337 socket_destroy( tcp_globals.net_phone, timeout->socket_id, timeout->local_sockets, & tcp_globals.sockets, tcp_free_socket_data );
1338 fibril_rwlock_write_unlock( local_lock );
1339 }
1340 }
1341 // unlock the globals
1342 fibril_rwlock_write_unlock( & tcp_globals.lock );
1343 // release the timeout structure
1344 free( timeout );
1345 return EOK;
1346}
1347
1348void tcp_retransmit_packet( socket_core_ref socket, tcp_socket_data_ref socket_data, size_t sequence_number ){
1349 packet_t packet;
1350 packet_t copy;
1351 size_t data_length;
1352
1353 assert( socket );
1354 assert( socket_data );
1355 assert( socket->specific_data == socket_data );
1356
1357 // sent packet?
1358 packet = pq_find( socket_data->outgoing, sequence_number );
1359 printf("retransmit %d\n", packet_get_id( packet ));
1360 if( packet ){
1361 pq_get_order( packet, NULL, & data_length );
1362 copy = tcp_prepare_copy( socket, socket_data, packet, data_length, sequence_number );
1363 fibril_rwlock_write_unlock( socket_data->local_lock );
1364// printf( "r send %d\n", packet_get_id( packet ));
1365 if( copy ){
1366 tcp_send_packets( socket_data->device_id, copy );
1367 }
1368 }else{
1369 fibril_rwlock_write_unlock( socket_data->local_lock );
1370 }
1371}
1372
1373int tcp_listen_message( socket_cores_ref local_sockets, int socket_id, int backlog ){
1374 socket_core_ref socket;
1375 tcp_socket_data_ref socket_data;
1376
1377 assert( local_sockets );
1378
1379 if( backlog < 0 ) return EINVAL;
1380 // find the socket
1381 socket = socket_cores_find( local_sockets, socket_id );
1382 if( ! socket ) return ENOTSOCK;
1383 // get the socket specific data
1384 socket_data = ( tcp_socket_data_ref ) socket->specific_data;
1385 assert( socket_data );
1386 // set the backlog
1387 socket_data->backlog = backlog;
1388 return EOK;
1389}
1390
1391int tcp_connect_message( socket_cores_ref local_sockets, int socket_id, struct sockaddr * addr, socklen_t addrlen ){
1392 ERROR_DECLARE;
1393
1394 socket_core_ref socket;
1395
1396 assert( local_sockets );
1397 assert( addr );
1398 assert( addrlen > 0 );
1399
1400 // find the socket
1401 socket = socket_cores_find( local_sockets, socket_id );
1402 if( ! socket ) return ENOTSOCK;
1403 if( ERROR_OCCURRED( tcp_connect_core( socket, local_sockets, addr, addrlen ))){
1404 tcp_free_socket_data( socket );
1405 // unbind if bound
1406 if( socket->port > 0 ){
1407 socket_ports_exclude( & tcp_globals.sockets, socket->port );
1408 socket->port = 0;
1409 }
1410 }
1411 return ERROR_CODE;
1412}
1413
1414int tcp_connect_core( socket_core_ref socket, socket_cores_ref local_sockets, struct sockaddr * addr, socklen_t addrlen ){
1415 ERROR_DECLARE;
1416
1417 tcp_socket_data_ref socket_data;
1418 packet_t packet;
1419
1420 assert( socket );
1421 assert( addr );
1422 assert( addrlen > 0 );
1423
1424 // get the socket specific data
1425 socket_data = ( tcp_socket_data_ref ) socket->specific_data;
1426 assert( socket_data );
1427 assert( socket->specific_data == socket_data );
1428 if(( socket_data->state != TCP_SOCKET_INITIAL )
1429 && (( socket_data->state != TCP_SOCKET_LISTEN ) || ( socket->port <= 0 ))){
1430 return EINVAL;
1431 }
1432 // get the destination port
1433 ERROR_PROPAGATE( tl_get_address_port( addr, addrlen, & socket_data->dest_port ));
1434 if( socket->port <= 0 ){
1435 // try to find a free port
1436 ERROR_PROPAGATE( socket_bind_free_port( & tcp_globals.sockets, socket, TCP_FREE_PORTS_START, TCP_FREE_PORTS_END, tcp_globals.last_used_port ));
1437 // set the next port as the search starting port number
1438 tcp_globals.last_used_port = socket->port;
1439 }
1440 ERROR_PROPAGATE( ip_get_route_req( tcp_globals.ip_phone, IPPROTO_TCP, addr, addrlen, & socket_data->device_id, & socket_data->pseudo_header, & socket_data->headerlen ));
1441
1442 // create the notification packet
1443 ERROR_PROPAGATE( tcp_create_notification_packet( & packet, socket, socket_data, 1, 0 ));
1444
1445 // unlock the globals and wait for an operation
1446 fibril_rwlock_write_unlock( & tcp_globals.lock );
1447
1448 socket_data->addr = addr;
1449 socket_data->addrlen = addrlen;
1450 // send the packet
1451 if( ERROR_OCCURRED( tcp_queue_packet( socket, socket_data, packet, 1 ))
1452 || ERROR_OCCURRED( tcp_prepare_timeout( tcp_timeout, socket, socket_data, 0, TCP_SOCKET_INITIAL, NET_DEFAULT_TCP_INITIAL_TIMEOUT, false ))){
1453 socket_data->addr = NULL;
1454 socket_data->addrlen = 0;
1455 fibril_rwlock_write_lock( & tcp_globals.lock );
1456 }else{
1457 packet = tcp_get_packets_to_send( socket, socket_data );
1458 if( packet ){
1459 fibril_mutex_lock( & socket_data->operation.mutex );
1460 fibril_rwlock_write_unlock( socket_data->local_lock );
1461 // send the packet
1462 printf( "connecting %d\n", packet_get_id( packet ));
1463 tcp_send_packets( socket_data->device_id, packet );
1464 // wait for a reply
1465 fibril_condvar_wait( & socket_data->operation.condvar, & socket_data->operation.mutex );
1466 ERROR_CODE = socket_data->operation.result;
1467 if( ERROR_CODE != EOK ){
1468 socket_data->addr = NULL;
1469 socket_data->addrlen = 0;
1470 }
1471 }else{
1472 socket_data->addr = NULL;
1473 socket_data->addrlen = 0;
1474 ERROR_CODE = EINTR;
1475 }
1476 }
1477
1478 fibril_mutex_unlock( & socket_data->operation.mutex );
1479
1480 // return the result
1481 return ERROR_CODE;
1482}
1483
1484int tcp_queue_prepare_packet( socket_core_ref socket, tcp_socket_data_ref socket_data, packet_t packet, size_t data_length ){
1485 ERROR_DECLARE;
1486
1487 tcp_header_ref header;
1488
1489 assert( socket );
1490 assert( socket_data );
1491 assert( socket->specific_data == socket_data );
1492
1493 // get tcp header
1494 header = ( tcp_header_ref ) packet_get_data( packet );
1495 if( ! header ) return NO_DATA;
1496 header->destination_port = htons( socket_data->dest_port );
1497 header->source_port = htons( socket->port );
1498 header->sequence_number = htonl( socket_data->next_outgoing );
1499 if( ERROR_OCCURRED( packet_set_addr( packet, NULL, ( uint8_t * ) socket_data->addr, socket_data->addrlen ))){
1500 return tcp_release_and_return( packet, EINVAL );
1501 }
1502 // remember the outgoing FIN
1503 if( header->finalize ){
1504 socket_data->fin_outgoing = socket_data->next_outgoing;
1505 }
1506 return EOK;
1507}
1508
1509int tcp_queue_packet( socket_core_ref socket, tcp_socket_data_ref socket_data, packet_t packet, size_t data_length ){
1510 ERROR_DECLARE;
1511 packet_t first;
1512
1513 assert( socket );
1514 assert( socket_data );
1515 assert( socket->specific_data == socket_data );
1516
1517 ERROR_PROPAGATE( tcp_queue_prepare_packet( socket, socket_data, packet, data_length ));
1518
1519 first = pq_add( socket_data->outgoing, packet, socket_data->next_outgoing, data_length );
1520 if( ! first ){
1521 return tcp_release_and_return( packet, EINVAL );
1522 }
1523 socket_data->outgoing = first;
1524 socket_data->next_outgoing += data_length;
1525 return EOK;
1526}
1527
1528packet_t tcp_get_packets_to_send( socket_core_ref socket, tcp_socket_data_ref socket_data ){
1529 ERROR_DECLARE;
1530
1531 packet_t packet;
1532 packet_t copy;
1533 packet_t sending = NULL;
1534 packet_t previous = NULL;
1535 size_t data_length;
1536
1537 assert( socket );
1538 assert( socket_data );
1539 assert( socket->specific_data == socket_data );
1540
1541 packet = pq_find( socket_data->outgoing, socket_data->last_outgoing + 1 );
1542 while( packet ){
1543 pq_get_order( packet, NULL, & data_length );
1544 // send only if fits into the window
1545 // respecting the possible overflow
1546 if( IS_IN_INTERVAL_OVERFLOW(( uint32_t ) socket_data->last_outgoing, ( uint32_t )( socket_data->last_outgoing + data_length ), ( uint32_t )( socket_data->expected + socket_data->treshold ))){
1547 copy = tcp_prepare_copy( socket, socket_data, packet, data_length, socket_data->last_outgoing + 1 );
1548 if( ! copy ){
1549 return sending;
1550 }
1551 if( ! sending ){
1552 sending = copy;
1553 }else{
1554 if( ERROR_OCCURRED( pq_insert_after( previous, copy ))){
1555 pq_release( tcp_globals.net_phone, packet_get_id( copy ));
1556 return sending;
1557 }
1558 }
1559 previous = copy;
1560 packet = pq_next( packet );
1561 // overflow occurred ?
1562 if(( ! packet ) && ( socket_data->last_outgoing > socket_data->next_outgoing )){
1563 printf("gpts overflow\n");
1564 // continue from the beginning
1565 packet = socket_data->outgoing;
1566 }
1567 socket_data->last_outgoing += data_length;
1568 }else{
1569 break;
1570 }
1571 }
1572 return sending;
1573}
1574
1575packet_t tcp_send_prepare_packet( socket_core_ref socket, tcp_socket_data_ref socket_data, packet_t packet, size_t data_length, size_t sequence_number ){
1576 ERROR_DECLARE;
1577
1578 tcp_header_ref header;
1579 uint32_t checksum;
1580
1581 assert( socket );
1582 assert( socket_data );
1583 assert( socket->specific_data == socket_data );
1584
1585 // adjust the pseudo header
1586 if( ERROR_OCCURRED( ip_client_set_pseudo_header_data_length( socket_data->pseudo_header, socket_data->headerlen, packet_get_data_length( packet )))){
1587 pq_release( tcp_globals.net_phone, packet_get_id( packet ));
1588 return NULL;
1589 }
1590
1591 // get the header
1592 header = ( tcp_header_ref ) packet_get_data( packet );
1593 if( ! header ){
1594 pq_release( tcp_globals.net_phone, packet_get_id( packet ));
1595 return NULL;
1596 }
1597 assert( ntohl( header->sequence_number ) == sequence_number );
1598
1599 // adjust the header
1600 if( socket_data->next_incoming ){
1601 header->acknowledgement_number = htonl( socket_data->next_incoming );
1602 header->acknowledge = 1;
1603 }
1604 header->window = htons( socket_data->window );
1605
1606 // checksum
1607 header->checksum = 0;
1608 checksum = compute_checksum( 0, socket_data->pseudo_header, socket_data->headerlen );
1609 checksum = compute_checksum( checksum, ( uint8_t * ) packet_get_data( packet ), packet_get_data_length( packet ));
1610 header->checksum = htons( flip_checksum( compact_checksum( checksum )));
1611 // prepare the packet
1612 if( ERROR_OCCURRED( ip_client_prepare_packet( packet, IPPROTO_TCP, 0, 0, 0, 0 ))
1613 // prepare the timeout
1614 || ERROR_OCCURRED( tcp_prepare_timeout( tcp_timeout, socket, socket_data, sequence_number, socket_data->state, socket_data->timeout, true ))){
1615 pq_release( tcp_globals.net_phone, packet_get_id( packet ));
1616 return NULL;
1617 }
1618 return packet;
1619}
1620
1621packet_t tcp_prepare_copy( socket_core_ref socket, tcp_socket_data_ref socket_data, packet_t packet, size_t data_length, size_t sequence_number ){
1622 packet_t copy;
1623
1624 assert( socket );
1625 assert( socket_data );
1626 assert( socket->specific_data == socket_data );
1627
1628 // make a copy of the packet
1629 copy = packet_get_copy( tcp_globals.net_phone, packet );
1630 if( ! copy ) return NULL;
1631
1632 return tcp_send_prepare_packet( socket, socket_data, copy, data_length, sequence_number );
1633}
1634
1635void tcp_send_packets( device_id_t device_id, packet_t packet ){
1636 packet_t next;
1637
1638 while( packet ){
1639 next = pq_detach( packet );
1640 ip_send_msg( tcp_globals.ip_phone, device_id, packet, SERVICE_TCP, 0 );
1641 packet = next;
1642 }
1643}
1644
1645void tcp_prepare_operation_header( socket_core_ref socket, tcp_socket_data_ref socket_data, tcp_header_ref header, int synchronize, int finalize ){
1646 assert( socket );
1647 assert( socket_data );
1648 assert( socket->specific_data == socket_data );
1649 assert( header );
1650
1651 bzero( header, sizeof( * header ));
1652 header->source_port = htons( socket->port );
1653 header->source_port = htons( socket_data->dest_port );
1654 header->header_length = TCP_COMPUTE_HEADER_LENGTH( sizeof( * header ));
1655 header->synchronize = synchronize;
1656 header->finalize = finalize;
1657}
1658
1659int tcp_prepare_timeout( int ( * timeout_function )( void * tcp_timeout_t ), socket_core_ref socket, tcp_socket_data_ref socket_data, size_t sequence_number, tcp_socket_state_t state, suseconds_t timeout, int globals_read_only ){
1660 tcp_timeout_ref operation_timeout;
1661 fid_t fibril;
1662
1663 assert( socket );
1664 assert( socket_data );
1665 assert( socket->specific_data == socket_data );
1666
1667 // prepare the timeout with key bundle structure
1668 operation_timeout = malloc( sizeof( * operation_timeout ) + socket->key_length + 1 );
1669 if( ! operation_timeout ) return ENOMEM;
1670 bzero( operation_timeout, sizeof( * operation_timeout ));
1671 operation_timeout->globals_read_only = globals_read_only;
1672 operation_timeout->port = socket->port;
1673 operation_timeout->local_sockets = socket_data->local_sockets;
1674 operation_timeout->socket_id = socket->socket_id;
1675 operation_timeout->timeout = timeout;
1676 operation_timeout->sequence_number = sequence_number;
1677 operation_timeout->state = state;
1678
1679 // copy the key
1680 operation_timeout->key = (( char * ) operation_timeout ) + sizeof( * operation_timeout );
1681 operation_timeout->key_length = socket->key_length;
1682 memcpy( operation_timeout->key, socket->key, socket->key_length );
1683 operation_timeout->key[ operation_timeout->key_length ] = '\0';
1684
1685 // prepare the timeouting thread
1686 fibril = fibril_create( timeout_function, operation_timeout );
1687 if( ! fibril ){
1688 free( operation_timeout );
1689 return EPARTY;
1690 }
1691// fibril_mutex_lock( & socket_data->operation.mutex );
1692 // start the timeouting fibril
1693 fibril_add_ready( fibril );
1694 //socket_data->state = state;
1695 return EOK;
1696}
1697
1698int tcp_recvfrom_message( socket_cores_ref local_sockets, int socket_id, int flags, size_t * addrlen ){
1699 ERROR_DECLARE;
1700
1701 socket_core_ref socket;
1702 tcp_socket_data_ref socket_data;
1703 int packet_id;
1704 packet_t packet;
1705 size_t length;
1706
1707 assert( local_sockets );
1708
1709 // find the socket
1710 socket = socket_cores_find( local_sockets, socket_id );
1711 if( ! socket ) return ENOTSOCK;
1712 // get the socket specific data
1713 if( ! socket->specific_data ) return NO_DATA;
1714 socket_data = ( tcp_socket_data_ref ) socket->specific_data;
1715
1716 // check state
1717 if(( socket_data->state != TCP_SOCKET_ESTABLISHED ) && ( socket_data->state != TCP_SOCKET_CLOSE_WAIT )){
1718 return ENOTCONN;
1719 }
1720
1721 // send the source address if desired
1722 if( addrlen ){
1723 ERROR_PROPAGATE( data_reply( socket_data->addr, socket_data->addrlen ));
1724 * addrlen = socket_data->addrlen;
1725 }
1726
1727 // get the next received packet
1728 packet_id = dyn_fifo_value( & socket->received );
1729 if( packet_id < 0 ) return NO_DATA;
1730 ERROR_PROPAGATE( packet_translate( tcp_globals.net_phone, & packet, packet_id ));
1731
1732 // reply the packets
1733 ERROR_PROPAGATE( socket_reply_packets( packet, & length ));
1734
1735 // release the packet
1736 dyn_fifo_pop( & socket->received );
1737 pq_release( tcp_globals.net_phone, packet_get_id( packet ));
1738 // return the total length
1739 return ( int ) length;
1740}
1741
1742int tcp_send_message( socket_cores_ref local_sockets, int socket_id, int fragments, size_t * data_fragment_size, int flags ){
1743 ERROR_DECLARE;
1744
1745 socket_core_ref socket;
1746 tcp_socket_data_ref socket_data;
1747 packet_dimension_ref packet_dimension;
1748 packet_t packet;
1749 size_t total_length;
1750 tcp_header_ref header;
1751 int index;
1752 int result;
1753
1754 assert( local_sockets );
1755 assert( data_fragment_size );
1756
1757 // find the socket
1758 socket = socket_cores_find( local_sockets, socket_id );
1759 if( ! socket ) return ENOTSOCK;
1760 // get the socket specific data
1761 if( ! socket->specific_data ) return NO_DATA;
1762 socket_data = ( tcp_socket_data_ref ) socket->specific_data;
1763
1764 // check state
1765 if(( socket_data->state != TCP_SOCKET_ESTABLISHED ) && ( socket_data->state != TCP_SOCKET_CLOSE_WAIT )){
1766 return ENOTCONN;
1767 }
1768
1769 ERROR_PROPAGATE( tl_get_ip_packet_dimension( tcp_globals.ip_phone, & tcp_globals.dimensions, socket_data->device_id, & packet_dimension ));
1770
1771 * data_fragment_size = (( packet_dimension->content < socket_data->data_fragment_size ) ? packet_dimension->content : socket_data->data_fragment_size );
1772
1773 for( index = 0; index < fragments; ++ index ){
1774 // read the data fragment
1775 result = tl_socket_read_packet_data( tcp_globals.net_phone, & packet, TCP_HEADER_SIZE, packet_dimension, socket_data->addr, socket_data->addrlen );
1776 if( result < 0 ) return result;
1777 total_length = ( size_t ) result;
1778 // prefix the tcp header
1779 header = PACKET_PREFIX( packet, tcp_header_t );
1780 if( ! header ){
1781 return tcp_release_and_return( packet, ENOMEM );
1782 }
1783 tcp_prepare_operation_header( socket, socket_data, header, 0, 0 );
1784 ERROR_PROPAGATE( tcp_queue_packet( socket, socket_data, packet, 0 ));
1785 }
1786
1787 // flush packets
1788 packet = tcp_get_packets_to_send( socket, socket_data );
1789 fibril_rwlock_write_unlock( socket_data->local_lock );
1790 fibril_rwlock_read_unlock( & tcp_globals.lock );
1791 if( packet ){
1792 // send the packet
1793 tcp_send_packets( socket_data->device_id, packet );
1794 }
1795
1796 return EOK;
1797}
1798
1799int tcp_close_message( socket_cores_ref local_sockets, int socket_id ){
1800 ERROR_DECLARE;
1801
1802 socket_core_ref socket;
1803 tcp_socket_data_ref socket_data;
1804 packet_t packet;
1805
1806 // find the socket
1807 socket = socket_cores_find( local_sockets, socket_id );
1808 if( ! socket ) return ENOTSOCK;
1809 // get the socket specific data
1810 socket_data = ( tcp_socket_data_ref ) socket->specific_data;
1811 assert( socket_data );
1812
1813 // check state
1814 switch( socket_data->state ){
1815 case TCP_SOCKET_ESTABLISHED:
1816 socket_data->state = TCP_SOCKET_FIN_WAIT_1;
1817 break;
1818 case TCP_SOCKET_CLOSE_WAIT:
1819 socket_data->state = TCP_SOCKET_LAST_ACK;
1820 break;
1821// case TCP_SOCKET_LISTEN:
1822 default:
1823 // just destroy
1824 if( ! ERROR_OCCURRED( socket_destroy( tcp_globals.net_phone, socket_id, local_sockets, & tcp_globals.sockets, tcp_free_socket_data ))){
1825 fibril_rwlock_write_unlock( socket_data->local_lock );
1826 fibril_rwlock_write_unlock( & tcp_globals.lock );
1827 }
1828 return ERROR_CODE;
1829 }
1830 // send FIN
1831 // TODO should I wait to complete?
1832
1833 // create the notification packet
1834 ERROR_PROPAGATE( tcp_create_notification_packet( & packet, socket, socket_data, 0, 1 ));
1835
1836 // send the packet
1837 ERROR_PROPAGATE( tcp_queue_packet( socket, socket_data, packet, 1 ));
1838
1839 // flush packets
1840 packet = tcp_get_packets_to_send( socket, socket_data );
1841 fibril_rwlock_write_unlock( socket_data->local_lock );
1842 fibril_rwlock_write_unlock( & tcp_globals.lock );
1843 if( packet ){
1844 // send the packet
1845 tcp_send_packets( socket_data->device_id, packet );
1846 }
1847 return EOK;
1848}
1849
1850int tcp_create_notification_packet( packet_t * packet, socket_core_ref socket, tcp_socket_data_ref socket_data, int synchronize, int finalize ){
1851 ERROR_DECLARE;
1852
1853 packet_dimension_ref packet_dimension;
1854 tcp_header_ref header;
1855
1856 assert( packet );
1857
1858 // get the device packet dimension
1859 ERROR_PROPAGATE( tl_get_ip_packet_dimension( tcp_globals.ip_phone, & tcp_globals.dimensions, socket_data->device_id, & packet_dimension ));
1860 // get a new packet
1861 * packet = packet_get_4( tcp_globals.net_phone, TCP_HEADER_SIZE, packet_dimension->addr_len, packet_dimension->prefix, packet_dimension->suffix );
1862 if( ! * packet ) return ENOMEM;
1863 // allocate space in the packet
1864 header = PACKET_SUFFIX( * packet, tcp_header_t );
1865 if( ! header ){
1866 tcp_release_and_return( * packet, ENOMEM );
1867 }
1868
1869 tcp_prepare_operation_header( socket, socket_data, header, synchronize, finalize );
1870 return EOK;
1871}
1872
1873int tcp_accept_message( socket_cores_ref local_sockets, int socket_id, int new_socket_id, size_t * data_fragment_size, size_t * addrlen ){
1874 ERROR_DECLARE;
1875
1876 socket_core_ref accepted;
1877 socket_core_ref socket;
1878 tcp_socket_data_ref socket_data;
1879 packet_dimension_ref packet_dimension;
1880
1881 assert( local_sockets );
1882 assert( data_fragment_size );
1883 assert( addrlen );
1884
1885 // find the socket
1886 socket = socket_cores_find( local_sockets, socket_id );
1887 if( ! socket ) return ENOTSOCK;
1888 // get the socket specific data
1889 socket_data = ( tcp_socket_data_ref ) socket->specific_data;
1890 assert( socket_data );
1891
1892 // check state
1893 if( socket_data->state != TCP_SOCKET_LISTEN ){
1894 return EINVAL;
1895 }
1896
1897 do{
1898 socket_id = dyn_fifo_value( & socket->accepted );
1899 if( socket_id < 0 ) return ENOTSOCK;
1900
1901 accepted = socket_cores_find( local_sockets, socket_id );
1902 if( ! accepted ) return ENOTSOCK;
1903 // get the socket specific data
1904 socket_data = ( tcp_socket_data_ref ) accepted->specific_data;
1905 assert( socket_data );
1906 // TODO can it be in another state?
1907 if( socket_data->state == TCP_SOCKET_ESTABLISHED ){
1908 ERROR_PROPAGATE( data_reply( socket_data->addr, socket_data->addrlen ));
1909 ERROR_PROPAGATE( tl_get_ip_packet_dimension( tcp_globals.ip_phone, & tcp_globals.dimensions, socket_data->device_id, & packet_dimension ));
1910 * addrlen = socket_data->addrlen;
1911 * data_fragment_size = (( packet_dimension->content < socket_data->data_fragment_size ) ? packet_dimension->content : socket_data->data_fragment_size );
1912 if( new_socket_id > 0 ){
1913 ERROR_PROPAGATE( socket_cores_update( local_sockets, accepted->socket_id, new_socket_id ));
1914 accepted->socket_id = new_socket_id;
1915 }
1916 }
1917 dyn_fifo_pop( & socket->accepted );
1918 }while( socket_data->state != TCP_SOCKET_ESTABLISHED );
1919 printf("ret accept %d\n", accepted->socket_id );
1920 return accepted->socket_id;
1921}
1922
1923void tcp_free_socket_data( socket_core_ref socket ){
1924 tcp_socket_data_ref socket_data;
1925
1926 assert( socket );
1927
1928 printf( "destroy_socket %d\n", socket->socket_id );
1929
1930 // get the socket specific data
1931 socket_data = ( tcp_socket_data_ref ) socket->specific_data;
1932 assert( socket_data );
1933 //free the pseudo header
1934 if( socket_data->pseudo_header ){
1935 if( socket_data->headerlen ){
1936 printf("d pseudo\n");
1937 free( socket_data->pseudo_header );
1938 socket_data->headerlen = 0;
1939 }
1940 socket_data->pseudo_header = NULL;
1941 }
1942 socket_data->headerlen = 0;
1943 // free the address
1944 if( socket_data->addr ){
1945 if( socket_data->addrlen ){
1946 printf("d addr\n");
1947 free( socket_data->addr );
1948 socket_data->addrlen = 0;
1949 }
1950 socket_data->addr = NULL;
1951 }
1952 socket_data->addrlen = 0;
1953}
1954
1955int tcp_release_and_return( packet_t packet, int result ){
1956 pq_release( tcp_globals.net_phone, packet_get_id( packet ));
1957 return result;
1958}
1959
1960/** @}
1961 */
Note: See TracBrowser for help on using the repository browser.