Subversion Repositories HelenOS

Rev

Rev 4731 | Rev 4743 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 4731 Rev 4738
Line 228... Line 228...
228
}
228
}
229
 
229
 
230
int udp_received_msg( device_id_t device_id, packet_t packet, services_t receiver, services_t error ){
230
int udp_received_msg( device_id_t device_id, packet_t packet, services_t receiver, services_t error ){
231
    int result;
231
    int result;
232
 
232
 
233
    fibril_rwlock_read_lock( & udp_globals.lock );
233
    fibril_rwlock_write_lock( & udp_globals.lock );
234
    result = udp_process_packet( packet, error );
234
    result = udp_process_packet( packet, error );
235
    fibril_rwlock_read_unlock( & udp_globals.lock );
235
    fibril_rwlock_write_unlock( & udp_globals.lock );
236
 
236
 
237
    return result;
237
    return result;
238
}
238
}
239
 
239
 
240
int udp_process_packet( packet_t packet, services_t error ){
240
int udp_process_packet( packet_t packet, services_t error ){
Line 242... Line 242...
242
 
242
 
243
    size_t          length;
243
    size_t          length;
244
    size_t          offset;
244
    size_t          offset;
245
    int             result;
245
    int             result;
246
    udp_header_ref  header;
246
    udp_header_ref  header;
247
    socket_core_ref *   socket;
247
    socket_core_ref socket;
248
    packet_t        next_packet;
248
    packet_t        next_packet;
249
    size_t          total_length;
249
    size_t          total_length;
250
    uint32_t        checksum;
250
    uint32_t        checksum;
251
    int             fragments;
251
    int             fragments;
252
    packet_t        tmp_packet;
252
    packet_t        tmp_packet;
Line 299... Line 299...
299
    header = ( udp_header_ref ) packet_get_data( packet );
299
    header = ( udp_header_ref ) packet_get_data( packet );
300
    if( ! header ){
300
    if( ! header ){
301
        return udp_release_and_return( packet, NO_DATA );
301
        return udp_release_and_return( packet, NO_DATA );
302
    }
302
    }
303
    // find the destination socket
303
    // find the destination socket
304
    socket = socket_ports_find( & udp_globals.sockets, ntohs( header->destination_port ));
304
    socket = socket_port_find( & udp_globals.sockets, ntohs( header->destination_port ), SOCKET_MAP_KEY_LISTENING, 0 );
305
    if( ! socket ){
305
    if( ! socket ){
306
        if( tl_prepare_icmp_packet( udp_globals.net_phone, udp_globals.icmp_phone, packet, error ) == EOK ){
306
        if( tl_prepare_icmp_packet( udp_globals.net_phone, udp_globals.icmp_phone, packet, error ) == EOK ){
307
            icmp_destination_unreachable_msg( udp_globals.icmp_phone, ICMP_PORT_UNREACH, 0, packet );
307
            icmp_destination_unreachable_msg( udp_globals.icmp_phone, ICMP_PORT_UNREACH, 0, packet );
308
        }
308
        }
309
        return EADDRNOTAVAIL;
309
        return EADDRNOTAVAIL;
Line 372... Line 372...
372
            return EINVAL;
372
            return EINVAL;
373
        }
373
        }
374
    }
374
    }
375
 
375
 
376
    // queue the received packet
376
    // queue the received packet
377
    if( ERROR_OCCURRED( dyn_fifo_push( &( ** socket ).received, packet_get_id( packet ), SOCKET_MAX_RECEIVED_SIZE ))){
377
    if( ERROR_OCCURRED( dyn_fifo_push( & socket->received, packet_get_id( packet ), SOCKET_MAX_RECEIVED_SIZE ))){
378
        return udp_release_and_return( packet, ERROR_CODE );
378
        return udp_release_and_return( packet, ERROR_CODE );
379
    }
379
    }
380
 
380
 
381
    // notify the destination socket
381
    // notify the destination socket
382
    async_msg_5(( ** socket ).phone, NET_SOCKET_RECEIVED, ( ipcarg_t ) ( ** socket ).socket_id, 0, 0, 0, ( ipcarg_t ) fragments );
382
    async_msg_5( socket->phone, NET_SOCKET_RECEIVED, ( ipcarg_t ) socket->socket_id, 0, 0, 0, ( ipcarg_t ) fragments );
383
    return EOK;
383
    return EOK;
384
}
384
}
385
 
385
 
386
int udp_message( ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count ){
386
int udp_message( ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count ){
387
    ERROR_DECLARE;
387
    ERROR_DECLARE;
Line 406... Line 406...
406
    bool                    keep_on_going = true;
406
    bool                    keep_on_going = true;
407
    socket_cores_t          local_sockets;
407
    socket_cores_t          local_sockets;
408
    int                     app_phone = IPC_GET_PHONE( & call );
408
    int                     app_phone = IPC_GET_PHONE( & call );
409
    struct sockaddr *       addr;
409
    struct sockaddr *       addr;
410
    size_t                  addrlen;
410
    size_t                  addrlen;
411
//  fibril_rwlock_t         lock;
411
    fibril_rwlock_t         lock;
412
    ipc_call_t              answer;
412
    ipc_call_t              answer;
413
    int                     answer_count;
413
    int                     answer_count;
414
 
414
 
415
    /*
415
    /*
416
     * Accept the connection
416
     * Accept the connection
Line 419... Line 419...
419
    ipc_answer_0( callid, EOK );
419
    ipc_answer_0( callid, EOK );
420
 
420
 
421
    // The client connection is only in one fibril and therefore no additional locks are needed.
421
    // The client connection is only in one fibril and therefore no additional locks are needed.
422
 
422
 
423
    socket_cores_initialize( & local_sockets );
423
    socket_cores_initialize( & local_sockets );
424
//  fibril_rwlock_initialize( & lock );
424
    fibril_rwlock_initialize( & lock );
425
 
425
 
426
    while( keep_on_going ){
426
    while( keep_on_going ){
427
        // refresh data
427
        // refresh data
428
        refresh_answer( & answer, & answer_count );
428
        refresh_answer( & answer, & answer_count );
429
 
429
 
Line 434... Line 434...
434
            case IPC_M_PHONE_HUNGUP:
434
            case IPC_M_PHONE_HUNGUP:
435
                keep_on_going = false;
435
                keep_on_going = false;
436
                res = EOK;
436
                res = EOK;
437
                break;
437
                break;
438
            case NET_SOCKET:
438
            case NET_SOCKET:
439
//              fibril_rwlock_write_lock( & lock );
439
                fibril_rwlock_write_lock( & lock );
440
                res = socket_create( & local_sockets, app_phone, NULL, SOCKET_SET_SOCKET_ID( answer ));
440
                res = socket_create( & local_sockets, app_phone, NULL, SOCKET_SET_SOCKET_ID( answer ));
441
//              fibril_rwlock_write_unlock( & lock );
441
                fibril_rwlock_write_unlock( & lock );
442
                // TODO max fragment size
442
                // TODO max fragment size
443
                * SOCKET_SET_DATA_FRAGMENT_SIZE( answer ) = MAX_UDP_FRAGMENT_SIZE;
443
                * SOCKET_SET_DATA_FRAGMENT_SIZE( answer ) = MAX_UDP_FRAGMENT_SIZE;
444
                * SOCKET_SET_HEADER_SIZE( answer ) = sizeof( udp_header_t );
444
                * SOCKET_SET_HEADER_SIZE( answer ) = sizeof( udp_header_t );
445
                answer_count = 3;
445
                answer_count = 3;
446
                break;
446
                break;
447
            case NET_SOCKET_BIND:
447
            case NET_SOCKET_BIND:
448
                res = data_receive(( void ** ) & addr, & addrlen );
448
                res = data_receive(( void ** ) & addr, & addrlen );
449
                if( res == EOK ){
449
                if( res == EOK ){
450
//                  fibril_rwlock_write_lock( & lock );
450
                    fibril_rwlock_read_lock( & lock );
451
                    fibril_rwlock_write_lock( & udp_globals.lock );
451
                    fibril_rwlock_write_lock( & udp_globals.lock );
452
                    res = socket_bind( & local_sockets, & udp_globals.sockets, SOCKET_GET_SOCKET_ID( call ), addr, addrlen, UDP_FREE_PORTS_START, UDP_FREE_PORTS_END, udp_globals.last_used_port );
452
                    res = socket_bind( & local_sockets, & udp_globals.sockets, SOCKET_GET_SOCKET_ID( call ), addr, addrlen, UDP_FREE_PORTS_START, UDP_FREE_PORTS_END, udp_globals.last_used_port );
453
                    fibril_rwlock_write_unlock( & udp_globals.lock );
453
                    fibril_rwlock_write_unlock( & udp_globals.lock );
454
//                  fibril_rwlock_write_unlock( & lock );
454
                    fibril_rwlock_read_unlock( & lock );
455
                    free( addr );
455
                    free( addr );
456
                }
456
                }
457
                break;
457
                break;
458
            case NET_SOCKET_SENDTO:
458
            case NET_SOCKET_SENDTO:
459
                res = data_receive(( void ** ) & addr, & addrlen );
459
                res = data_receive(( void ** ) & addr, & addrlen );
460
                if( res == EOK ){
460
                if( res == EOK ){
461
//                  fibril_rwlock_read_lock( & lock );
461
                    fibril_rwlock_read_lock( & lock );
462
                    fibril_rwlock_read_lock( & udp_globals.lock );
462
                    fibril_rwlock_write_lock( & udp_globals.lock );
463
                    res = udp_sendto_message( & local_sockets, SOCKET_GET_SOCKET_ID( call ), addr, addrlen, SOCKET_GET_DATA_FRAGMENTS( call ), SOCKET_GET_DATA_FRAGMENT_SIZE( call ), SOCKET_GET_FLAGS( call ));
463
                    res = udp_sendto_message( & local_sockets, SOCKET_GET_SOCKET_ID( call ), addr, addrlen, SOCKET_GET_DATA_FRAGMENTS( call ), SOCKET_GET_DATA_FRAGMENT_SIZE( call ), SOCKET_GET_FLAGS( call ));
464
                    fibril_rwlock_read_unlock( & udp_globals.lock );
464
                    fibril_rwlock_write_unlock( & udp_globals.lock );
465
//                  fibril_rwlock_read_unlock( & lock );
465
                    fibril_rwlock_read_unlock( & lock );
466
                    free( addr );
466
                    free( addr );
467
                }
467
                }
468
                break;
468
                break;
469
            case NET_SOCKET_RECVFROM:
469
            case NET_SOCKET_RECVFROM:
470
//              fibril_rwlock_read_lock( & lock );
470
                fibril_rwlock_read_lock( & lock );
471
                fibril_rwlock_read_lock( & udp_globals.lock );
471
                fibril_rwlock_write_lock( & udp_globals.lock );
472
                res = udp_recvfrom_message( & local_sockets, SOCKET_GET_SOCKET_ID( call ), SOCKET_GET_FLAGS( call ), & addrlen );
472
                res = udp_recvfrom_message( & local_sockets, SOCKET_GET_SOCKET_ID( call ), SOCKET_GET_FLAGS( call ), & addrlen );
473
                fibril_rwlock_read_unlock( & udp_globals.lock );
473
                fibril_rwlock_write_unlock( & udp_globals.lock );
474
//              fibril_rwlock_read_unlock( & lock );
474
                fibril_rwlock_read_unlock( & lock );
475
                if( res > 0 ){
475
                if( res > 0 ){
476
                    * SOCKET_SET_READ_DATA_LENGTH( answer ) = res;
476
                    * SOCKET_SET_READ_DATA_LENGTH( answer ) = res;
477
                    * SOCKET_SET_ADDRESS_LENGTH( answer ) = addrlen;
477
                    * SOCKET_SET_ADDRESS_LENGTH( answer ) = addrlen;
478
                    answer_count = 2;
478
                    answer_count = 2;
479
                    res = EOK;
479
                    res = EOK;
480
                }
480
                }
481
                break;
481
                break;
482
            case NET_SOCKET_CLOSE:
482
            case NET_SOCKET_CLOSE:
483
//              fibril_rwlock_write_lock( & lock );
483
                fibril_rwlock_write_lock( & lock );
484
                fibril_rwlock_write_lock( & udp_globals.lock );
484
                fibril_rwlock_write_lock( & udp_globals.lock );
485
                res = socket_destroy( udp_globals.net_phone, SOCKET_GET_SOCKET_ID( call ), & local_sockets, & udp_globals.sockets );
485
                res = socket_destroy( udp_globals.net_phone, SOCKET_GET_SOCKET_ID( call ), & local_sockets, & udp_globals.sockets, NULL );
486
                fibril_rwlock_write_unlock( & udp_globals.lock );
486
                fibril_rwlock_write_unlock( & udp_globals.lock );
487
//              fibril_rwlock_write_unlock( & lock );
487
                fibril_rwlock_write_unlock( & lock );
488
                break;
488
                break;
489
            case NET_SOCKET_GETSOCKOPT:
489
            case NET_SOCKET_GETSOCKOPT:
490
            case NET_SOCKET_SETSOCKOPT:
490
            case NET_SOCKET_SETSOCKOPT:
491
            default:
491
            default:
492
                res = ENOTSUP;
492
                res = ENOTSUP;
Line 496... Line 496...
496
//      printf( "res = %d\n", res );
496
//      printf( "res = %d\n", res );
497
 
497
 
498
        answer_call( callid, res, & answer, answer_count );
498
        answer_call( callid, res, & answer, answer_count );
499
    }
499
    }
500
 
500
 
501
    // TODO call socket_destroy() on all bound!
501
    // release all local sockets
502
    socket_cores_destroy( & local_sockets );
502
    socket_cores_release( udp_globals.net_phone, & local_sockets, & udp_globals.sockets, NULL );
503
 
503
 
504
    return EOK;
504
    return EOK;
505
}
505
}
506
 
506
 
507
int udp_sendto_message( socket_cores_ref local_sockets, int socket_id, const struct sockaddr * addr, socklen_t addrlen, int fragments, size_t data_fragment_size, int flags ){
507
int udp_sendto_message( socket_cores_ref local_sockets, int socket_id, const struct sockaddr * addr, socklen_t addrlen, int fragments, size_t data_fragment_size, int flags ){
Line 527... Line 527...
527
 
527
 
528
    if(( socket->port <= 0 ) && udp_globals.autobinding ){
528
    if(( socket->port <= 0 ) && udp_globals.autobinding ){
529
        // bind the socket to a random free port if not bound
529
        // bind the socket to a random free port if not bound
530
        do{
530
        do{
531
            // try to find a free port
531
            // try to find a free port
532
            fibril_rwlock_read_unlock( & udp_globals.lock );
532
//          fibril_rwlock_read_unlock( & udp_globals.lock );
533
            fibril_rwlock_write_lock( & udp_globals.lock );
533
//          fibril_rwlock_write_lock( & udp_globals.lock );
534
            // might be changed in the meantime
534
            // might be changed in the meantime
535
            if( socket->port <= 0 ){
535
            if( socket->port <= 0 ){
536
                ERROR_PROPAGATE( socket_bind_free_port( & udp_globals.sockets, socket, UDP_FREE_PORTS_START, UDP_FREE_PORTS_END, udp_globals.last_used_port ));
536
                if( ERROR_OCCURRED( socket_bind_free_port( & udp_globals.sockets, socket, UDP_FREE_PORTS_START, UDP_FREE_PORTS_END, udp_globals.last_used_port ))){
-
 
537
                    fibril_rwlock_write_unlock( & udp_globals.lock );
-
 
538
                    fibril_rwlock_read_lock( & udp_globals.lock );
-
 
539
                    return ERROR_CODE;
-
 
540
                }
537
                // set the next port as the search starting port number
541
                // set the next port as the search starting port number
538
                udp_globals.last_used_port = socket->port;
542
                udp_globals.last_used_port = socket->port;
539
            }
543
            }
540
            fibril_rwlock_write_unlock( & udp_globals.lock );
544
//          fibril_rwlock_write_unlock( & udp_globals.lock );
541
            fibril_rwlock_read_lock( & udp_globals.lock );
545
//          fibril_rwlock_read_lock( & udp_globals.lock );
542
            // might be changed in the meantime
546
            // might be changed in the meantime
543
        }while( socket->port <= 0 );
547
        }while( socket->port <= 0 );
544
    }
548
    }
545
 
549
 
546
    // TODO do not ask all the time
550
    // TODO do not ask all the time
Line 608... Line 612...
608
    int             packet_id;
612
    int             packet_id;
609
    packet_t        packet;
613
    packet_t        packet;
610
    udp_header_ref  header;
614
    udp_header_ref  header;
611
    struct sockaddr *   addr;
615
    struct sockaddr *   addr;
612
    size_t          length;
616
    size_t          length;
613
    packet_t        next_packet;
-
 
614
    uint8_t *       data;
617
    uint8_t *       data;
615
    size_t          fragments;
-
 
616
    size_t *        lengths;
-
 
617
    size_t          index;
-
 
618
    int             result;
618
    int             result;
619
 
619
 
620
    // find the socket
620
    // find the socket
621
    socket = socket_cores_find( local_sockets, socket_id );
621
    socket = socket_cores_find( local_sockets, socket_id );
622
    if( ! socket ) return ENOTSOCK;
622
    if( ! socket ) return ENOTSOCK;
Line 640... Line 640...
640
    }
640
    }
641
    * addrlen = ( size_t ) result;
641
    * addrlen = ( size_t ) result;
642
    // send the source address
642
    // send the source address
643
    ERROR_PROPAGATE( data_reply( addr, * addrlen ));
643
    ERROR_PROPAGATE( data_reply( addr, * addrlen ));
644
 
644
 
645
    next_packet = pq_next( packet );
-
 
646
    if( ! next_packet ){
-
 
647
        // write all if only one fragment
-
 
648
        ERROR_PROPAGATE( data_reply( data + sizeof( udp_header_t ), packet_get_data_length( packet ) - sizeof( udp_header_t )));
-
 
649
        // store the total length
645
    // trim the header
650
        length = packet_get_data_length( packet ) - sizeof( udp_header_t );
646
    ERROR_PROPAGATE( packet_trim( packet, sizeof( udp_header_t ), 0 ));
651
    }else{
-
 
652
        // count the packet fragments
-
 
653
        fragments = 1;
-
 
654
        next_packet = pq_next( packet );
-
 
655
        while(( next_packet = pq_next( next_packet ))){
-
 
656
            ++ fragments;
-
 
657
        }
647
 
658
        // compute and store the fragment lengths
-
 
659
        lengths = ( size_t * ) malloc( sizeof( size_t ) * fragments + sizeof( size_t ));
-
 
660
        if( ! lengths ) return ENOMEM;
-
 
661
        lengths[ 0 ] = packet_get_data_length( packet ) - sizeof( udp_header_t );
-
 
662
        lengths[ fragments ] = lengths[ 0 ];
-
 
663
        next_packet = pq_next( packet );
-
 
664
        for( index = 1; index < fragments; ++ index ){
-
 
665
            lengths[ index ] = packet_get_data_length( next_packet );
-
 
666
            lengths[ fragments ] += lengths[ index ];
-
 
667
            next_packet = pq_next( packet );
-
 
668
        }while( next_packet );
-
 
669
        // write the fragment lengths
648
    // reply the packets
670
        ERROR_PROPAGATE( data_reply( lengths, sizeof( int ) * ( fragments + 1 )));
-
 
671
        // write the first fragment
-
 
672
        ERROR_PROPAGATE( data_reply( data + sizeof( udp_header_t ), lengths[ 0 ] ));
-
 
673
        next_packet = pq_next( packet );
-
 
674
        // write the rest of the fragments
-
 
675
        for( index = 1; index < fragments; ++ index ){
-
 
676
            ERROR_PROPAGATE( data_reply( packet_get_data( next_packet ), lengths[ index ] ));
649
    ERROR_PROPAGATE( socket_reply_packets( packet, & length ));
677
            next_packet = pq_next( packet );
-
 
678
        }while( next_packet );
-
 
679
        // store the total length
-
 
680
        length = lengths[ fragments ];
-
 
681
        free( lengths );
-
 
682
    }
650
 
683
    // release the packet
651
    // release the packet
684
    dyn_fifo_pop( & socket->received );
652
    dyn_fifo_pop( & socket->received );
685
    pq_release( udp_globals.net_phone, packet_get_id( packet ));
653
    pq_release( udp_globals.net_phone, packet_get_id( packet ));
686
    // return the total length
654
    // return the total length
687
    return ( int ) length;
655
    return ( int ) length;