Changeset 89e57cee in mainline


Ignore:
Timestamp:
2010-11-02T22:02:45Z (14 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
457a6f5
Parents:
ba1a2fd
Message:

Cleanup tpc.

Location:
uspace/srv/net/tl/tcp
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/net/tl/tcp/tcp.c

    rba1a2fd r89e57cee  
    2828
    2929/** @addtogroup tcp
    30  *  @{
     30 * @{
    3131 */
    3232
    3333/** @file
    34  *  TCP module implementation.
    35  *  @see tcp.h
     34 * TCP module implementation.
     35 * @see tcp.h
    3636 */
     37
     38#include "tcp.h"
     39#include "tcp_header.h"
     40#include "tcp_module.h"
    3741
    3842#include <assert.h>
     
    7276#include <tl_interface.h>
    7377
    74 #include "tcp.h"
    75 #include "tcp_header.h"
    76 #include "tcp_module.h"
    77 
    7878/** TCP module name. */
    7979#define NAME    "TCP protocol"
     
    110110
    111111/** Returns a value indicating whether the value is in the interval respecting
    112  *  the possible overflow.
     112 * the possible overflow.
    113113 *
    114  *  The high end and/or the value may overflow, be lower than the low value.
    115  *  @param[in] lower The last value before the interval.
    116  *  @param[in] value The value to be checked.
    117  *  @param[in] higher_equal The last value in the interval.
     114 * The high end and/or the value may overflow, be lower than the low value.
     115 *
     116 * @param[in] lower     The last value before the interval.
     117 * @param[in] value     The value to be checked.
     118 * @param[in] higher_equal The last value in the interval.
    118119 */
    119120#define IS_IN_INTERVAL_OVERFLOW(lower, value, higher_equal) \
     
    165166};
    166167
    167 /** Releases the packet and returns the result.
    168  *  @param[in] packet The packet queue to be released.
    169  *  @param[in] result The result to be returned.
    170  *  @return The result parameter.
    171  */
    172 int tcp_release_and_return(packet_t packet, int result);
    173 
    174 void tcp_prepare_operation_header(socket_core_ref socket,
    175     tcp_socket_data_ref socket_data, tcp_header_ref header, int synchronize,
    176     int finalize);
    177 int tcp_prepare_timeout(int (*timeout_function)(void *tcp_timeout_t),
    178     socket_core_ref socket, tcp_socket_data_ref socket_data,
    179     size_t sequence_number, tcp_socket_state_t state, suseconds_t timeout,
    180     int globals_read_only);
    181 void tcp_free_socket_data(socket_core_ref socket);
    182 
    183 int tcp_timeout(void *data);
    184 
    185 int tcp_release_after_timeout(void *data);
    186 
    187 int tcp_process_packet(device_id_t device_id, packet_t packet,
    188     services_t error);
    189 int tcp_connect_core(socket_core_ref socket, socket_cores_ref local_sockets,
    190     struct sockaddr *addr, socklen_t addrlen);
    191 int tcp_queue_prepare_packet(socket_core_ref socket,
    192     tcp_socket_data_ref socket_data, packet_t packet, size_t data_length);
    193 int tcp_queue_packet(socket_core_ref socket, tcp_socket_data_ref socket_data,
    194     packet_t packet, size_t data_length);
    195 packet_t tcp_get_packets_to_send(socket_core_ref socket,
    196     tcp_socket_data_ref socket_data);
    197 void tcp_send_packets(device_id_t device_id, packet_t packet);
    198 
    199 void tcp_process_acknowledgement(socket_core_ref socket,
    200     tcp_socket_data_ref socket_data, tcp_header_ref header);
    201 packet_t tcp_send_prepare_packet(socket_core_ref socket,
    202     tcp_socket_data_ref socket_data, packet_t packet, size_t data_length,
    203     size_t sequence_number);
    204 packet_t tcp_prepare_copy(socket_core_ref socket,
    205     tcp_socket_data_ref socket_data, packet_t packet, size_t data_length,
    206     size_t sequence_number);
    207 void tcp_retransmit_packet(socket_core_ref socket,
    208     tcp_socket_data_ref socket_data, size_t sequence_number);
    209 int tcp_create_notification_packet(packet_t * packet, socket_core_ref socket,
    210     tcp_socket_data_ref socket_data, int synchronize, int finalize);
    211 void tcp_refresh_socket_data(tcp_socket_data_ref socket_data);
    212 
    213 void tcp_initialize_socket_data(tcp_socket_data_ref socket_data);
    214 
    215 int tcp_process_listen(socket_core_ref listening_socket,
    216     tcp_socket_data_ref listening_socket_data, tcp_header_ref header,
    217     packet_t packet, struct sockaddr *src, struct sockaddr *dest,
    218     size_t addrlen);
    219 int tcp_process_syn_sent(socket_core_ref socket,
    220     tcp_socket_data_ref socket_data, tcp_header_ref header, packet_t packet);
    221 int tcp_process_syn_received(socket_core_ref socket,
    222     tcp_socket_data_ref socket_data, tcp_header_ref header, packet_t packet);
    223 int tcp_process_established(socket_core_ref socket,
    224     tcp_socket_data_ref socket_data, tcp_header_ref header, packet_t packet,
    225     int fragments, size_t total_length);
    226 int tcp_queue_received_packet(socket_core_ref socket,
    227     tcp_socket_data_ref socket_data, packet_t packet, int fragments,
    228     size_t total_length);
    229 
    230 int tcp_received_msg(device_id_t device_id, packet_t packet,
    231     services_t receiver, services_t error);
    232 int tcp_process_client_messages(ipc_callid_t callid, ipc_call_t call);
    233 
    234 int tcp_listen_message(socket_cores_ref local_sockets, int socket_id,
    235     int backlog);
    236 int tcp_connect_message(socket_cores_ref local_sockets, int socket_id,
    237     struct sockaddr *addr, socklen_t addrlen);
    238 int tcp_recvfrom_message(socket_cores_ref local_sockets, int socket_id,
    239     int flags, size_t * addrlen);
    240 int tcp_send_message(socket_cores_ref local_sockets, int socket_id,
    241     int fragments, size_t * data_fragment_size, int flags);
    242 int tcp_accept_message(socket_cores_ref local_sockets, int socket_id,
    243     int new_socket_id, size_t * data_fragment_size, size_t * addrlen);
    244 int tcp_close_message(socket_cores_ref local_sockets, int socket_id);
     168static int tcp_release_and_return(packet_t, int);
     169static void tcp_prepare_operation_header(socket_core_ref, tcp_socket_data_ref,
     170    tcp_header_ref, int synchronize, int);
     171static int tcp_prepare_timeout(int (*)(void *), socket_core_ref,
     172    tcp_socket_data_ref, size_t, tcp_socket_state_t, suseconds_t, int);
     173static void tcp_free_socket_data(socket_core_ref);
     174
     175static int tcp_timeout(void *);
     176
     177static int tcp_release_after_timeout(void *);
     178
     179static int tcp_process_packet(device_id_t, packet_t, services_t);
     180static int tcp_connect_core(socket_core_ref, socket_cores_ref,
     181    struct sockaddr *, socklen_t);
     182static int tcp_queue_prepare_packet(socket_core_ref, tcp_socket_data_ref,
     183    packet_t, size_t);
     184static int tcp_queue_packet(socket_core_ref, tcp_socket_data_ref, packet_t,
     185    size_t);
     186static packet_t tcp_get_packets_to_send(socket_core_ref, tcp_socket_data_ref);
     187static void tcp_send_packets(device_id_t, packet_t);
     188
     189static void tcp_process_acknowledgement(socket_core_ref, tcp_socket_data_ref,
     190    tcp_header_ref);
     191static packet_t tcp_send_prepare_packet(socket_core_ref, tcp_socket_data_ref,
     192    packet_t, size_t, size_t);
     193static packet_t tcp_prepare_copy(socket_core_ref, tcp_socket_data_ref, packet_t,
     194    size_t, size_t);
     195/* static */ void tcp_retransmit_packet(socket_core_ref, tcp_socket_data_ref,
     196    size_t);
     197static int tcp_create_notification_packet(packet_t *, socket_core_ref,
     198    tcp_socket_data_ref, int, int);
     199static void tcp_refresh_socket_data(tcp_socket_data_ref);
     200
     201static void tcp_initialize_socket_data(tcp_socket_data_ref);
     202
     203static int tcp_process_listen(socket_core_ref, tcp_socket_data_ref,
     204    tcp_header_ref, packet_t, struct sockaddr *, struct sockaddr *, size_t);
     205static int tcp_process_syn_sent(socket_core_ref, tcp_socket_data_ref,
     206    tcp_header_ref, packet_t);
     207static int tcp_process_syn_received(socket_core_ref, tcp_socket_data_ref,
     208    tcp_header_ref, packet_t);
     209static int tcp_process_established(socket_core_ref, tcp_socket_data_ref,
     210    tcp_header_ref, packet_t, int, size_t);
     211static int tcp_queue_received_packet(socket_core_ref, tcp_socket_data_ref,
     212    packet_t, int, size_t);
     213
     214static int tcp_received_msg(device_id_t, packet_t, services_t, services_t);
     215static int tcp_process_client_messages(ipc_callid_t, ipc_call_t);
     216
     217static int tcp_listen_message(socket_cores_ref, int, int);
     218static int tcp_connect_message(socket_cores_ref, int, struct sockaddr *,
     219    socklen_t);
     220static int tcp_recvfrom_message(socket_cores_ref, int, int, size_t *);
     221static int tcp_send_message(socket_cores_ref, int, int, size_t *, int);
     222static int tcp_accept_message(socket_cores_ref, int, int, size_t *, size_t *);
     223static int tcp_close_message(socket_cores_ref, int);
    245224
    246225/** TCP global data. */
    247226tcp_globals_t tcp_globals;
    248227
     228/** Initializes the TCP module.
     229 *
     230 * @param[in] client_connection The client connection processing function. The
     231 *                      module skeleton propagates its own one.
     232 * @returns             EOK on success.
     233 * @returns             ENOMEM if there is not enough memory left.
     234 */
    249235int tcp_initialize(async_client_conn_t client_connection)
    250236{
     
    314300        size_t addrlen;
    315301
    316         if (error) {
    317                 switch (error) {
    318                 case SERVICE_ICMP:
    319                         // process error
    320                         result = icmp_client_process_packet(packet, &type,
    321                             &code, NULL, NULL);
    322                         if (result < 0)
    323                                 return tcp_release_and_return(packet, result);
    324 
    325                         length = (size_t) result;
    326                         if (ERROR_OCCURRED(packet_trim(packet, length, 0))) {
    327                                 return tcp_release_and_return(packet,
    328                                     ERROR_CODE);
    329                         }
    330                         break;
    331 
    332                 default:
    333                         return tcp_release_and_return(packet, ENOTSUP);
    334                 }
     302        switch (error) {
     303        case SERVICE_NONE:
     304                break;
     305        case SERVICE_ICMP:
     306                // process error
     307                result = icmp_client_process_packet(packet, &type, &code, NULL,
     308                    NULL);
     309                if (result < 0)
     310                        return tcp_release_and_return(packet, result);
     311
     312                length = (size_t) result;
     313                if (ERROR_OCCURRED(packet_trim(packet, length, 0)))
     314                        return tcp_release_and_return(packet, ERROR_CODE);
     315                break;
     316        default:
     317                return tcp_release_and_return(packet, ENOTSUP);
    335318        }
    336319
     
    379362                    ntohs(header->destination_port), SOCKET_MAP_KEY_LISTENING,
    380363                    0);
    381                 if (!socket) {
    382                         if (tl_prepare_icmp_packet(tcp_globals.net_phone,
    383                             tcp_globals.icmp_phone, packet, error) == EOK) {
    384                                 icmp_destination_unreachable_msg(
    385                                     tcp_globals.icmp_phone, ICMP_PORT_UNREACH,
    386                                     0, packet);
    387                         }
    388                         return EADDRNOTAVAIL;
    389                 }
    390         }
     364        }
     365        if (!socket) {
     366                if (tl_prepare_icmp_packet(tcp_globals.net_phone,
     367                    tcp_globals.icmp_phone, packet, error) == EOK) {
     368                        icmp_destination_unreachable_msg(tcp_globals.icmp_phone,
     369                            ICMP_PORT_UNREACH, 0, packet);
     370                }
     371                return EADDRNOTAVAIL;
     372        }
     373
    391374        printf("socket id %d\n", socket->socket_id);
    392375        socket_data = (tcp_socket_data_ref) socket->specific_data;
     
    402385        total_length = 0;
    403386        do {
    404                 ++fragments;
     387                fragments++;
    405388                length = packet_get_data_length(next_packet);
    406389                if (length <= 0)
     
    421404
    422405        if (error)
    423                 goto error;
     406                goto has_error_service;
    424407       
    425408        if (socket_data->state == TCP_SOCKET_LISTEN) {
    426 
    427409                if (socket_data->pseudo_header) {
    428410                        free(socket_data->pseudo_header);
     
    464446        }
    465447
    466 error:
     448has_error_service:
    467449        fibril_rwlock_read_unlock(&tcp_globals.lock);
    468450
     
    507489int
    508490tcp_process_established(socket_core_ref socket, tcp_socket_data_ref socket_data,
    509     tcp_header_ref header, packet_t packet, int fragments,
    510     size_t total_length)
     491    tcp_header_ref header, packet_t packet, int fragments, size_t total_length)
    511492{
    512493        ERROR_DECLARE;
     
    684665                                        continue;
    685666                                        // at least partly following data?
    686                                 } else if (IS_IN_INTERVAL_OVERFLOW(
    687                                     sequence_number, socket_data->next_incoming,
    688                                     new_sequence_number)) {
     667                                }
     668                                if (IS_IN_INTERVAL_OVERFLOW(sequence_number,
     669                                    socket_data->next_incoming, new_sequence_number)) {
    689670                                        if (socket_data->next_incoming <
    690671                                            new_sequence_number) {
     
    961942        listening_socket = socket_port_find(&tcp_globals.sockets,
    962943            listening_port, SOCKET_MAP_KEY_LISTENING, 0);
    963         if ((!listening_socket) ||
     944        if (!listening_socket ||
    964945            (listening_socket->socket_id != listening_socket_id)) {
    965946                fibril_rwlock_write_unlock(&tcp_globals.lock);
     
    11911172        if (number == socket_data->expected) {
    11921173                // increase the counter
    1193                 ++socket_data->expected_count;
     1174                socket_data->expected_count++;
    11941175                if (socket_data->expected_count == TCP_FAST_RETRANSMIT_COUNT) {
    11951176                        socket_data->expected_count = 1;
     
    12001181}
    12011182
    1202 int tcp_message_standalone(ipc_callid_t callid, ipc_call_t * call,
    1203     ipc_call_t * answer, int *answer_count)
     1183/** Processes the TCP message.
     1184 *
     1185 * @param[in] callid    The message identifier.
     1186 * @param[in] call      The message parameters.
     1187 * @param[out] answer   The message answer parameters.
     1188 * @param[out] answer_count The last parameter for the actual answer in the
     1189 *                      answer parameter.
     1190 * @returns             EOK on success.
     1191 * @returns             ENOTSUP if the message is not known.
     1192 *
     1193 * @see tcp_interface.h
     1194 * @see IS_NET_TCP_MESSAGE()
     1195 */
     1196int
     1197tcp_message_standalone(ipc_callid_t callid, ipc_call_t *call,
     1198    ipc_call_t *answer, int *answer_count)
    12041199{
    12051200        ERROR_DECLARE;
     
    15211516        socket = socket_port_find(&tcp_globals.sockets, timeout->port,
    15221517            timeout->key, timeout->key_length);
    1523         if (!(socket && (socket->socket_id == timeout->socket_id)))
     1518        if (!socket || (socket->socket_id != timeout->socket_id))
    15241519                goto out;
    15251520       
     
    15321527        if (timeout->sequence_number) {
    15331528                // increase the timeout counter;
    1534                 ++socket_data->timeout_count;
     1529                socket_data->timeout_count++;
    15351530                if (socket_data->timeout_count == TCP_MAX_TIMEOUTS) {
    15361531                        // TODO release as connection lost
     
    17441739            ERROR_OCCURRED(tcp_prepare_timeout(tcp_timeout, socket, socket_data,
    17451740            0, TCP_SOCKET_INITIAL, NET_DEFAULT_TCP_INITIAL_TIMEOUT, false))) {
    1746 
    17471741                socket_data->addr = NULL;
    17481742                socket_data->addrlen = 0;
    17491743                fibril_rwlock_write_lock(&tcp_globals.lock);
    1750 
    17511744        } else {
    1752 
    17531745                packet = tcp_get_packets_to_send(socket, socket_data);
    17541746                if (packet) {
     
    18761868                packet = pq_next(packet);
    18771869                // overflow occurred ?
    1878                 if ((!packet) &&
     1870                if (!packet &&
    18791871                    (socket_data->last_outgoing > socket_data->next_outgoing)) {
    18801872                        printf("gpts overflow\n");
     
    20442036int
    20452037tcp_recvfrom_message(socket_cores_ref local_sockets, int socket_id, int flags,
    2046     size_t * addrlen)
     2038    size_t *addrlen)
    20472039{
    20482040        ERROR_DECLARE;
     
    20992091int
    21002092tcp_send_message(socket_cores_ref local_sockets, int socket_id, int fragments,
    2101     size_t * data_fragment_size, int flags)
     2093    size_t *data_fragment_size, int flags)
    21022094{
    21032095        ERROR_DECLARE;
     
    21382130            packet_dimension->content : socket_data->data_fragment_size);
    21392131
    2140         for (index = 0; index < fragments; ++index) {
     2132        for (index = 0; index < fragments; index++) {
    21412133                // read the data fragment
    21422134                result = tl_socket_read_packet_data(tcp_globals.net_phone,
     
    22352227
    22362228int
    2237 tcp_create_notification_packet(packet_t * packet, socket_core_ref socket,
     2229tcp_create_notification_packet(packet_t *packet, socket_core_ref socket,
    22382230    tcp_socket_data_ref socket_data, int synchronize, int finalize)
    22392231{
     
    22712263int
    22722264tcp_accept_message(socket_cores_ref local_sockets, int socket_id,
    2273     int new_socket_id, size_t * data_fragment_size, size_t * addrlen)
     2265    int new_socket_id, size_t *data_fragment_size, size_t *addrlen)
    22742266{
    22752267        ERROR_DECLARE;
     
    23732365}
    23742366
     2367/** Releases the packet and returns the result.
     2368 *
     2369 * @param[in] packet    The packet queue to be released.
     2370 * @param[in] result    The result to be returned.
     2371 * @return              The result parameter.
     2372 */
    23752373int tcp_release_and_return(packet_t packet, int result)
    23762374{
     
    23812379/** Default thread for new connections.
    23822380 *
    2383  *  @param[in] iid The initial message identifier.
    2384  *  @param[in] icall The initial message call structure.
     2381 * @param[in] iid       The initial message identifier.
     2382 * @param[in] icall     The initial message call structure.
    23852383 *
    23862384 */
     
    23972395                int answer_count;
    23982396
    2399                 /*
    2400                    Clear the answer structure
    2401                  */
     2397                /* Clear the answer structure */
    24022398                refresh_answer(&answer, &answer_count);
    24032399
    2404                 /*
    2405                    Fetch the next message
    2406                  */
     2400                /* Fetch the next message */
    24072401                ipc_call_t call;
    24082402                ipc_callid_t callid = async_get_call(&call);
    24092403
    2410                 /*
    2411                    Process the message
    2412                  */
     2404                /* Process the message */
    24132405                int res = tl_module_message_standalone(callid, &call, &answer,
    24142406                    &answer_count);
    24152407
    24162408                /*
    2417                    End if said to either by the message or the processing result
     2409                 * End if told to either by the message or the processing
     2410                 * result.
    24182411                 */
    24192412                if ((IPC_GET_METHOD(call) == IPC_M_PHONE_HUNGUP) ||
     
    24302423/** Starts the module.
    24312424 *
    2432  *  @param argc The count of the command line arguments. Ignored parameter.
    2433  *  @param argv The command line parameters. Ignored parameter.
    2434  *
    2435  *  @returns EOK on success.
    2436  *  @returns Other error codes as defined for each specific module start function.
    2437  *
     2425 * @returns             EOK on success.
     2426 * @returns             Other error codes as defined for each specific module
     2427 *                      start function.
    24382428 */
    24392429int
  • uspace/srv/net/tl/tcp/tcp.h

    rba1a2fd r89e57cee  
    2828
    2929/** @addtogroup tcp
    30  *  @{
     30 * @{
    3131 */
    3232
    3333/** @file
    34  *  TCP module.
    35  */
    36 
    37 #ifndef __NET_TCP_H__
    38 #define __NET_TCP_H__
     34 * TCP module.
     35 */
     36
     37#ifndef NET_TCP_H_
     38#define NET_TCP_H_
    3939
    4040#include <fibril_synch.h>
     
    4646
    4747/** Type definition of the TCP global data.
    48  *  @see tcp_globals
    49  */
    50 typedef struct tcp_globals      tcp_globals_t;
     48 * @see tcp_globals
     49 */
     50typedef struct tcp_globals tcp_globals_t;
    5151
    5252/** Type definition of the TCP socket specific data.
    53  *  @see tcp_socket_data
    54  */
    55 typedef struct tcp_socket_data  tcp_socket_data_t;
     53 * @see tcp_socket_data
     54 */
     55typedef struct tcp_socket_data tcp_socket_data_t;
    5656
    5757/** Type definition of the TCP socket specific data pointer.
    58  *  @see tcp_socket_data
    59  */
    60 typedef tcp_socket_data_t *     tcp_socket_data_ref;
     58 * @see tcp_socket_data
     59 */
     60typedef tcp_socket_data_t *tcp_socket_data_ref;
    6161
    6262/** Type definition of the TCP operation data.
    63  *  @see tcp_operation
    64  */
    65 typedef struct tcp_operation    tcp_operation_t;
     63 * @see tcp_operation
     64 */
     65typedef struct tcp_operation tcp_operation_t;
    6666
    6767/** Type definition of the TCP operation data pointer.
    68  *  @see tcp_operation
    69  */
    70 typedef tcp_operation_t *       tcp_operation_ref;
     68 * @see tcp_operation
     69 */
     70typedef tcp_operation_t *tcp_operation_ref;
    7171
    7272/** TCP socket state type definition.
    73  *  @see tcp_socket_state
    74  */
    75 typedef enum tcp_socket_state   tcp_socket_state_t;
    76 
    77 /** TCP socket state.
    78  */
    79 enum tcp_socket_state{
     73 * @see tcp_socket_state
     74 */
     75typedef enum tcp_socket_state tcp_socket_state_t;
     76
     77/** TCP socket state. */
     78enum tcp_socket_state {
    8079        /** Initial.
    81          *  Not connected or bound.
     80         *
     81         * Not connected or bound.
    8282         */
    8383        TCP_SOCKET_INITIAL,
     84       
    8485        /** Listening.
    85          *  Awaiting a connection request from another TCP layer.
    86          *  When SYN is received a new bound socket in the TCP_SOCKET_SYN_RECEIVED state should be created.
     86         *
     87         * Awaiting a connection request from another TCP layer.
     88         * When SYN is received a new bound socket in the
     89         * TCP_SOCKET_SYN_RECEIVED state should be created.
    8790         */
    8891        TCP_SOCKET_LISTEN,
     92       
    8993        /** Connecting issued.
    90          *  A~SYN has been sent, and TCP is awaiting the response SYN.
    91          *  Should continue to the TCP_SOCKET_ESTABLISHED state.
     94         *
     95         * A SYN has been sent, and TCP is awaiting the response SYN.
     96         * Should continue to the TCP_SOCKET_ESTABLISHED state.
    9297         */
    9398        TCP_SOCKET_SYN_SENT,
     99       
    94100        /** Connecting received.
    95          *  A~SYN has been received, a~SYN has been sent, and TCP is awaiting an ACK.
    96          *  Should continue to the TCP_SOCKET_ESTABLISHED state.
     101         *
     102         * A SYN has been received, a SYN has been sent, and TCP is awaiting an
     103         * ACK. Should continue to the TCP_SOCKET_ESTABLISHED state.
    97104         */
    98105        TCP_SOCKET_SYN_RECEIVED,
     106       
    99107        /** Connected.
    100          *  The three-way handshake has been completed.
     108         *
     109         * The three-way handshake has been completed.
    101110         */
    102111        TCP_SOCKET_ESTABLISHED,
     112       
    103113        /** Closing started.
    104          *  The local application has issued a~CLOSE.
    105          *  TCP has sent a~FIN, and is awaiting an ACK or a~FIN.
    106          *  Should continue to the TCP_SOCKET_FIN_WAIT_2 state when an ACK is received.
    107          *  Should continue to the TCP_SOCKET_CLOSING state when a~FIN is received.
     114         *
     115         * The local application has issued a CLOSE.
     116         * TCP has sent a FIN, and is awaiting an ACK or a FIN.
     117         * Should continue to the TCP_SOCKET_FIN_WAIT_2 state when an ACK is
     118         * received.
     119         * Should continue to the TCP_SOCKET_CLOSING state when a FIN is
     120         * received.
    108121         */
    109122        TCP_SOCKET_FIN_WAIT_1,
     123       
    110124        /** Closing confirmed.
    111          *  A~FIN has been sent, and an ACK received.
    112          *  TCP is awaiting a~FIN from the remote TCP layer.
    113          *  Should continue to the TCP_SOCKET_CLOSING state.
     125         *
     126         * A FIN has been sent, and an ACK received.
     127         * TCP is awaiting a~FIN from the remote TCP layer.
     128         * Should continue to the TCP_SOCKET_CLOSING state.
    114129         */
    115130        TCP_SOCKET_FIN_WAIT_2,
     131       
    116132        /** Closing.
    117          *  A FIN has been sent, a FIN has been received, and an ACK has been sent.
    118          *  TCP is awaiting an ACK for the FIN that was sent.
    119          *  Should continue to the TCP_SOCKET_TIME_WAIT state.
     133         *
     134         * A FIN has been sent, a FIN has been received, and an ACK has been
     135         * sent.
     136         * TCP is awaiting an ACK for the FIN that was sent.
     137         * Should continue to the TCP_SOCKET_TIME_WAIT state.
    120138         */
    121139        TCP_SOCKET_CLOSING,
     140       
    122141        /** Closing received.
    123          *  TCP has received a~FIN, and has sent an ACK.
    124          *  It is awaiting a~close request from the local application before sending a~FIN.
    125          *  Should continue to the TCP_SOCKET_SOCKET_LAST_ACK state.
     142         *
     143         * TCP has received a FIN, and has sent an ACK.
     144         * It is awaiting a close request from the local application before
     145         * sending a FIN.
     146         * Should continue to the TCP_SOCKET_SOCKET_LAST_ACK state.
    126147         */
    127148        TCP_SOCKET_CLOSE_WAIT,
    128         /**
    129          *  A~FIN has been received, and an ACK and a~FIN have been sent.
    130          *  TCP is awaiting an ACK.
    131          *  Should continue to the TCP_SOCKET_TIME_WAIT state.
     149       
     150        /**
     151         * A FIN has been received, and an ACK and a FIN have been sent.
     152         * TCP is awaiting an ACK.
     153         * Should continue to the TCP_SOCKET_TIME_WAIT state.
    132154         */
    133155        TCP_SOCKET_LAST_ACK,
     156       
    134157        /** Closing finished.
    135          *  FINs have been received and ACK’d, and TCP is waiting two MSLs to remove the connection from the table.
     158         *
     159         * FINs have been received and ACK’d, and TCP is waiting two MSLs to
     160         * remove the connection from the table.
    136161         */
    137162        TCP_SOCKET_TIME_WAIT,
     163       
    138164        /** Closed.
    139          *  Imaginary, this indicates that a~connection has been removed from the connection table.
     165         *
     166         * Imaginary, this indicates that a connection has been removed from
     167         * the connection table.
    140168         */
    141169        TCP_SOCKET_CLOSED
    142170};
    143171
    144 /** TCP operation data.
    145  */
    146 struct tcp_operation{
    147         /** Operation result.
    148          */
     172/** TCP operation data. */
     173struct tcp_operation {
     174        /** Operation result. */
    149175        int result;
    150         /** Safety lock.
    151          */
     176        /** Safety lock. */
    152177        fibril_mutex_t mutex;
    153         /** Operation result signaling.
    154          */
     178        /** Operation result signaling. */
    155179        fibril_condvar_t condvar;
    156180};
    157181
    158 /** TCP socket specific data.
    159  */
    160 struct tcp_socket_data{
    161         /** TCP socket state.
    162          */
     182/** TCP socket specific data. */
     183struct tcp_socket_data {
     184        /** TCP socket state. */
    163185        tcp_socket_state_t state;
    164         /** Data fragment size.
    165          *  Sending optimalization.
     186       
     187        /**
     188         * Data fragment size.
     189         * Sending optimalization.
    166190         */
    167191        size_t data_fragment_size;
    168         /** Device identifier.
    169         */
     192       
     193        /** Device identifier. */
    170194        device_id_t device_id;
    171         /** Listening backlog.
    172          *  The maximal number of connected but not yet accepted sockets.
     195       
     196        /**
     197         * Listening backlog.
     198         * The maximal number of connected but not yet accepted sockets.
    173199         */
    174200        int backlog;
    175 //      /** Segment size.
    176 //       */
    177 //      size_t                  segment_size;
    178         /** Parent listening socket identifier.
    179          *  Set if this socket is an accepted one.
     201       
     202//      /** Segment size. */
     203//      size_t segment_size;
     204
     205        /**
     206         * Parent listening socket identifier.
     207         * Set if this socket is an accepted one.
    180208         */
    181209        int listening_socket_id;
    182         /** Treshold size in bytes.
    183         */
     210       
     211        /** Treshold size in bytes. */
    184212        size_t treshold;
    185         /** Window size in bytes.
    186          */
     213        /** Window size in bytes. */
    187214        size_t window;
    188         /** Acknowledgement timeout.
    189          */
     215        /** Acknowledgement timeout. */
    190216        suseconds_t timeout;
    191         /** Last acknowledged byte.
    192          */
     217        /** Last acknowledged byte. */
    193218        uint32_t acknowledged;
    194         /** Next incoming sequence number.
    195          */
     219        /** Next incoming sequence number. */
    196220        uint32_t next_incoming;
    197         /** Incoming FIN.
    198          */
     221        /** Incoming FIN. */
    199222        uint32_t fin_incoming;
    200         /** Next outgoing sequence number.
    201          */
     223        /** Next outgoing sequence number. */
    202224        uint32_t next_outgoing;
    203         /** Last outgoing sequence number.
    204          */
     225        /** Last outgoing sequence number. */
    205226        uint32_t last_outgoing;
    206         /** Outgoing FIN.
    207          */
     227        /** Outgoing FIN. */
    208228        uint32_t fin_outgoing;
    209         /** Expected sequence number by the remote host.
    210          *  The sequence number the other host expects.
    211          *  The notification is sent only upon a packet reecival.
     229       
     230        /**
     231         * Expected sequence number by the remote host.
     232         * The sequence number the other host expects.
     233         * The notification is sent only upon a packet reecival.
    212234         */
    213235        uint32_t expected;
    214         /** Expected sequence number counter.
    215          *  Counts the number of received notifications for the same sequence number.
     236       
     237        /**
     238         * Expected sequence number counter.
     239         * Counts the number of received notifications for the same sequence
     240         * number.
    216241         */
    217242        int expected_count;
     243       
    218244        /** Incoming packet queue.
    219          *  Packets are buffered until received in the right order.
    220          *  The packets are excluded after successfully read.
    221          *  Packets are sorted by their starting byte.
    222          *  Packets metric is set as their data length.
     245         *
     246         * Packets are buffered until received in the right order.
     247         * The packets are excluded after successfully read.
     248         * Packets are sorted by their starting byte.
     249         * Packets metric is set as their data length.
    223250         */
    224251        packet_t incoming;
     252       
    225253        /** Outgoing packet queue.
    226          *  Packets are buffered until acknowledged by the remote host in the right order.
    227          *  The packets are excluded after acknowledged.
    228          *  Packets are sorted by their starting byte.
    229          *  Packets metric is set as their data length.
     254         *
     255         * Packets are buffered until acknowledged by the remote host in the
     256         * right order.
     257         * The packets are excluded after acknowledged.
     258         * Packets are sorted by their starting byte.
     259         * Packets metric is set as their data length.
    230260         */
    231261        packet_t outgoing;
    232         /** IP pseudo header.
    233         */
     262       
     263        /** IP pseudo header. */
    234264        void *pseudo_header;
    235         /** IP pseudo header length.
    236          */
     265        /** IP pseudo header length. */
    237266        size_t headerlen;
    238         /** Remote host address.
    239          */
    240         struct sockaddr * addr;
    241         /** Remote host address length.
    242          */
     267        /** Remote host address. */
     268        struct sockaddr *addr;
     269        /** Remote host address length. */
    243270        socklen_t addrlen;
    244         /** Remote host port.
    245          */
     271        /** Remote host port. */
    246272        uint16_t dest_port;
    247         /** Parent local sockets.
    248          */
     273        /** Parent local sockets. */
    249274        socket_cores_ref local_sockets;
     275       
    250276        /** Local sockets safety lock.
    251          *  May be locked for writing while holding the global lock for reading when changing the local sockets only.
    252          *  The global lock may to be locked only before locking the local lock.
    253          *  The global lock may be locked more weakly than the local lock.
    254          *  The global lock may be released before releasing the local lock.
    255          *  @see tcp_globals:lock
    256          */
    257         fibril_rwlock_t * local_lock;
    258         /** Pending operation data.
    259          */
     277         *
     278         * May be locked for writing while holding the global lock for reading
     279         * when changing the local sockets only.
     280         * The global lock may be locked only before locking the local lock.
     281         * The global lock may be locked more weakly than the local lock.
     282         * The global lock may be released before releasing the local lock.
     283         * @see tcp_globals:lock
     284         */
     285        fibril_rwlock_t *local_lock;
     286       
     287        /** Pending operation data. */
    260288        tcp_operation_t operation;
    261         /** Timeouts in a row counter.
    262          *  If TCP_MAX_TIMEOUTS is reached, the connection is lost.
     289       
     290        /**
     291         * Timeouts in a row counter.
     292         * If TCP_MAX_TIMEOUTS is reached, the connection is lost.
    263293         */
    264294        int timeout_count;
    265295};
    266296
    267 /** TCP global data.
    268  */
    269 struct  tcp_globals{
    270         /** Networking module phone.
    271          */
     297/** TCP global data. */
     298struct tcp_globals {
     299        /** Networking module phone. */
    272300        int net_phone;
    273         /** IP module phone.
    274          */
     301        /** IP module phone. */
    275302        int ip_phone;
    276         /** ICMP module phone.
    277          */
     303        /** ICMP module phone. */
    278304        int icmp_phone;
    279         /** Last used free port.
    280          */
     305        /** Last used free port. */
    281306        int last_used_port;
    282         /** Active sockets.
    283          */
     307        /** Active sockets. */
    284308        socket_ports_t sockets;
    285         /** Device packet dimensions.
    286          */
     309        /** Device packet dimensions. */
    287310        packet_dimensions_t dimensions;
    288         /** Safety lock.
    289          *  Write lock is used only for adding or removing socket ports.
     311       
     312        /**
     313         * Safety lock.
     314         * Write lock is used only for adding or removing socket ports.
    290315         */
    291316        fibril_rwlock_t lock;
     
    296321/** @}
    297322 */
    298 
  • uspace/srv/net/tl/tcp/tcp_header.h

    rba1a2fd r89e57cee  
    2828
    2929/** @addtogroup tcp
    30  *  @{
     30 * @{
    3131 */
    3232
    3333/** @file
    34  *  TCP header definition.
    35  *  Based on the RFC~793.
     34 * TCP header definition.
     35 * Based on the RFC 793.
    3636 */
    3737
    38 #ifndef __NET_TCP_HEADER_H__
    39 #define __NET_TCP_HEADER_H__
     38#ifndef NET_TCP_HEADER_H_
     39#define NET_TCP_HEADER_H_
    4040
    4141#include <sys/types.h>
    4242
    43 /** TCP header size in bytes.
    44  */
    45 #define TCP_HEADER_SIZE                 sizeof(tcp_header_t)
     43/** TCP header size in bytes. */
     44#define TCP_HEADER_SIZE                         sizeof(tcp_header_t)
    4645
    4746/** Returns the actual TCP header length in bytes.
    48  *  @param[in] header The TCP packet header.
     47 * @param[in] header The TCP packet header.
    4948 */
    50 #define TCP_HEADER_LENGTH(header)               ((header)->header_length * 4u)
     49#define TCP_HEADER_LENGTH(header)               ((header)->header_length * 4U)
    5150
    5251/** Returns the TCP header length.
    53  *  @param[in] length The TCP header length in bytes.
     52 * @param[in] length The TCP header length in bytes.
    5453 */
    55 #define TCP_COMPUTE_HEADER_LENGTH(length)               ((uint8_t) ((length) / 4u))
     54#define TCP_COMPUTE_HEADER_LENGTH(length)       ((uint8_t) ((length) / 4U))
    5655
    5756/** Type definition of the transmission datagram header.
    58  *  @see tcp_header
     57 * @see tcp_header
    5958 */
    60 typedef struct tcp_header       tcp_header_t;
     59typedef struct tcp_header tcp_header_t;
    6160
    6261/** Type definition of the transmission datagram header pointer.
    63  *  @see tcp_header
     62 * @see tcp_header
    6463 */
    65 typedef tcp_header_t *          tcp_header_ref;
     64typedef tcp_header_t *tcp_header_ref;
    6665
    6766/** Type definition of the transmission datagram header option.
    68  *  @see tcp_option
     67 * @see tcp_option
    6968 */
    70 typedef struct tcp_option       tcp_option_t;
     69typedef struct tcp_option tcp_option_t;
    7170
    7271/** Type definition of the transmission datagram header option pointer.
    73  *  @see tcp_option
     72 * @see tcp_option
    7473 */
    75 typedef tcp_option_t *          tcp_option_ref;
     74typedef tcp_option_t *tcp_option_ref;
    7675
    77 /** Type definition of the Maximum segment size TCP option.
    78  *  @see ...
    79  */
    80 typedef struct tcp_max_segment_size_option      tcp_max_segment_size_option_t;
     76/** Type definition of the Maximum segment size TCP option. */
     77typedef struct tcp_max_segment_size_option tcp_max_segment_size_option_t;
    8178
    8279/** Type definition of the Maximum segment size TCP option pointer.
    83  *  @see tcp_max_segment_size_option
     80 * @see tcp_max_segment_size_option
    8481 */
    85 typedef tcp_max_segment_size_option_t *         tcp_max_segment_size_option_ref;
     82typedef tcp_max_segment_size_option_t *tcp_max_segment_size_option_ref;
    8683
    87 /** Transmission datagram header.
    88  */
    89 struct tcp_header{
    90         /** The source port number.
    91          */
     84/** Transmission datagram header. */
     85struct tcp_header {
    9286        uint16_t source_port;
    93         /** The destination port number.
    94          */
    9587        uint16_t destination_port;
    96         /** The sequence number of the first data octet in this segment (except when SYN is present).
    97          *  If SYN is present the sequence number is the initial sequence number (ISN) and the first data octet is ISN+1.
    98          */
    9988        uint32_t sequence_number;
    100         /** If the ACK control bit is set this field contains the value of the next sequence number the sender of the segment is expecting to receive.
    101          *  Once a~connection is established this is always sent.
    102          *  @see acknowledge
    103          */
    10489        uint32_t acknowledgement_number;
     90       
    10591#ifdef ARCH_IS_BIG_ENDIAN
    106         /** The number of 32~bit words in the TCP Header.
    107          *  This indicates where the data begins.
    108          *  The TCP header (even one including options) is an integral number of 32~bits long.
    109          */
    11092        uint8_t header_length:4;
    111         /** Four bits reserved for future use.
    112          *  Must be zero.
    113          */
    11493        uint8_t reserved1:4;
    11594#else
    116         /** Four bits reserved for future use.
    117          *  Must be zero.
    118          */
    11995        uint8_t reserved1:4;
    120         /** The number of 32~bit words in the TCP Header.
    121          *  This indicates where the data begins.
    122          *  The TCP header (even one including options) is an integral number of 32~bits long.
    123          */
    12496        uint8_t header_length:4;
    12597#endif
     98
    12699#ifdef ARCH_IS_BIG_ENDIAN
    127         /** Two bits reserved for future use.
    128          *  Must be zero.
    129          */
    130100        uint8_t reserved2:2;
    131         /** Urgent Pointer field significant.
    132          *  @see tcp_header:urgent_pointer
    133          */
    134101        uint8_t urgent:1;
    135         /** Acknowledgment field significant
    136          *  @see tcp_header:acknowledgement_number
    137          */
    138102        uint8_t acknowledge:1;
    139         /** Push function.
    140          */
    141103        uint8_t push:1;
    142         /** Reset the connection.
    143          */
    144104        uint8_t reset:1;
    145         /** Synchronize the sequence numbers.
    146          */
    147105        uint8_t synchronize:1;
    148         /** No more data from the sender.
    149          */
    150106        uint8_t finalize:1;
    151107#else
    152         /** No more data from the sender.
    153          */
    154108        uint8_t finalize:1;
    155         /** Synchronize the sequence numbers.
    156          */
    157109        uint8_t synchronize:1;
    158         /** Reset the connection.
    159          */
    160110        uint8_t reset:1;
    161         /** Push function.
    162          */
    163111        uint8_t push:1;
    164         /** Acknowledgment field significant.
    165          *  @see tcp_header:acknowledgement_number
    166          */
    167112        uint8_t acknowledge:1;
    168         /** Urgent Pointer field significant.
    169          *  @see tcp_header:urgent_pointer
    170          */
    171113        uint8_t urgent:1;
    172         /** Two bits reserved for future use.
    173          *  Must be zero.
    174          */
    175114        uint8_t reserved2:2;
    176115#endif
    177         /** The number of data octets beginning with the one indicated in the acknowledgment field which the sender of this segment is willing to accept.
    178          *  @see tcp_header:acknowledge
    179          */
     116
    180117        uint16_t window;
    181         /** The checksum field is the 16~bit one's complement of the one's complement sum of all 16~bit words in the header and text.
    182          *  If a~segment contains an odd number of header and text octets to be checksummed, the last octet is padded on the right with zeros to form a~16~bit word for checksum purposes.
    183          *  The pad is not transmitted as part of the segment.
    184          *  While computing the checksum, the checksum field itself is replaced with zeros.
    185          *  The checksum also coves a~pseudo header conceptually.
    186          *  The pseudo header conceptually prefixed to the TCP header contains the source address, the destination address, the protocol, and the TCP length.
    187          *  This information gives protection against misrouted datagrams.
    188          *  If the computed checksum is zero, it is transmitted as all ones (the equivalent in one's complement arithmetic).
    189          */
    190118        uint16_t checksum;
    191         /** This field communicates the current value of the urgent pointer as a~positive offset from the sequence number in this segment.
    192          *  The urgent pointer points to the sequence number of the octet following the urgent data.
    193          *  This field is only be interpreted in segments with the URG control bit set.
    194          *  @see tcp_header:urgent
    195          */
    196119        uint16_t urgent_pointer;
    197120} __attribute__ ((packed));
    198121
    199 /** Transmission datagram header option.
    200  */
    201 struct tcp_option{
    202         /** Option type.
    203          */
     122/** Transmission datagram header option. */
     123struct tcp_option {
     124        /** Option type. */
    204125        uint8_t type;
    205         /** Option length.
    206          */
     126        /** Option length. */
    207127        uint8_t length;
    208128};
    209129
    210 /** Maximum segment size TCP option.
    211  */
    212 struct tcp_max_segment_size_option{
     130/** Maximum segment size TCP option. */
     131struct tcp_max_segment_size_option {
    213132        /** TCP option.
    214          *  @see TCPOPT_MAX_SEGMENT_SIZE
    215          *  @see TCPOPT_MAX_SEGMENT_SIZE_LENGTH
     133         * @see TCPOPT_MAX_SEGMENT_SIZE
     134         * @see TCPOPT_MAX_SEGMENT_SIZE_LENGTH
    216135         */
    217136        tcp_option_t option;
    218         /** Maximum segment size in bytes.
    219         */
     137       
     138        /** Maximum segment size in bytes. */
    220139        uint16_t max_segment_size;
    221140} __attribute__ ((packed));
  • uspace/srv/net/tl/tcp/tcp_module.c

    rba1a2fd r89e57cee  
    2828
    2929/** @addtogroup tcp
    30  *  @{
     30 * @{
    3131 */
    3232
    3333/** @file
    34  *  TCP standalone module implementation.
    35  *  Contains skeleton module functions mapping.
    36  *  The functions are used by the module skeleton as module specific entry points.
    37  *  @see module.c
     34 * TCP standalone module implementation.
     35 * Contains skeleton module functions mapping.
     36 * The functions are used by the module skeleton as module specific entry
     37 * points.
     38 * @see module.c
    3839 */
     40
     41#include "tcp.h"
     42#include "tcp_module.h"
    3943
    4044#include <async.h>
     
    4650#include <net/ip_protocols.h>
    4751#include <net/modules.h>
    48 
    4952#include <net/packet.h>
    5053#include <net_interface.h>
     54
    5155#include <ip_interface.h>
    5256#include <tl_local.h>
    5357
    54 #include "tcp.h"
    55 #include "tcp_module.h"
     58/** TCP module global data. */
     59extern tcp_globals_t tcp_globals;
    5660
    57 /** TCP module global data.
    58  */
    59 extern tcp_globals_t    tcp_globals;
    60 
    61 /** Starts the TCP module.
    62  *  Initializes the client connection serving function, initializes the module, registers the module service and starts the async manager, processing IPC messages in an infinite loop.
    63  *  @param[in] client_connection The client connection processing function. The module skeleton propagates its own one.
    64  *  @returns EOK on successful module termination.
    65  *  @returns Other error codes as defined for the tcp_initialize() function.
    66  *  @returns Other error codes as defined for the REGISTER_ME() macro function.
    67  */
    6861int tl_module_start_standalone(async_client_conn_t client_connection)
    6962{
     
    7568       
    7669        ipcarg_t phonehash;
    77         if (ERROR_OCCURRED(tcp_initialize(client_connection))
    78             || ERROR_OCCURRED(REGISTER_ME(SERVICE_TCP, &phonehash))) {
     70        if (ERROR_OCCURRED(tcp_initialize(client_connection)) ||
     71            ERROR_OCCURRED(REGISTER_ME(SERVICE_TCP, &phonehash))) {
    7972                pm_destroy();
    8073                return ERROR_CODE;
     
    8780}
    8881
    89 /** Processes the TCP message.
    90  *  @param[in] callid The message identifier.
    91  *  @param[in] call The message parameters.
    92  *  @param[out] answer The message answer parameters.
    93  *  @param[out] answer_count The last parameter for the actual answer in the answer parameter.
    94  *  @returns EOK on success.
    95  *  @returns Other error codes as defined for the tcp_message() function.
    96  */
    97 int tl_module_message_standalone(ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count){
     82int
     83tl_module_message_standalone(ipc_callid_t callid, ipc_call_t *call,
     84    ipc_call_t *answer, int *answer_count)
     85{
    9886        return tcp_message_standalone(callid, call, answer, answer_count);
    9987}
  • uspace/srv/net/tl/tcp/tcp_module.h

    rba1a2fd r89e57cee  
    2828
    2929/** @addtogroup tcp
    30  *  @{
     30 * @{
    3131 */
    3232
    3333/** @file
    34  *  TCP module functions.
    35  *  The functions are used as TCP module entry points.
     34 * TCP module functions.
     35 * The functions are used as TCP module entry points.
    3636 */
    3737
    38 #ifndef __NET_TCP_MODULE_H__
    39 #define __NET_TCP_MODULE_H__
     38#ifndef NET_TCP_MODULE_H_
     39#define NET_TCP_MODULE_H_
    4040
    4141#include <async.h>
    4242#include <ipc/ipc.h>
    4343
    44 /** Initializes the TCP module.
    45  *  @param[in] client_connection The client connection processing function. The module skeleton propagates its own one.
    46  *  @returns EOK on success.
    47  *  @returns ENOMEM if there is not enough memory left.
    48  */
    49 extern int tcp_initialize(async_client_conn_t client_connection);
    50 
    51 /** Processes the TCP message.
    52  *  @param[in] callid The message identifier.
    53  *  @param[in] call The message parameters.
    54  *  @param[out] answer The message answer parameters.
    55  *  @param[out] answer_count The last parameter for the actual answer in the answer parameter.
    56  *  @returns EOK on success.
    57  *  @returns ENOTSUP if the message is not known.
    58  *  @see tcp_interface.h
    59  *  @see IS_NET_TCP_MESSAGE()
    60  */
    61 extern int tcp_message_standalone(ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count);
     44extern int tcp_initialize(async_client_conn_t);
     45extern int tcp_message_standalone(ipc_callid_t, ipc_call_t *, ipc_call_t *,
     46    int *);
    6247
    6348#endif
Note: See TracChangeset for help on using the changeset viewer.