Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:31

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSTestSuiteTestsTFTPFS
0007  *
0008  * @brief This source file contains the implementation of UDP network fake
0009  *   functions related to tftpfs testing.
0010  *
0011  * The libtftpfs source code is situated in the RTEMS repository.  For
0012  * testing it, either libbsd or RTEMS legacy networking would be required.
0013  * This implies that the tests for libtftpfs would need to be placed in
0014  * the libbsd repository - a different one than the libtftpfs source code.
0015  *
0016  * Yet, libtftpfs uses only a handful of networking functions.  This
0017  * file provides fake implementations of those functions.  These fake
0018  * functions permit to simulate the exchange of UDP packets
0019  * with the libtftpfs code and thus permits testing libtftpfs without
0020  * the need of a full network stack.
0021  */
0022 
0023 /*
0024  * Copyright (C) 2022 embedded brains GmbH & Co. KG
0025  *
0026  * Redistribution and use in source and binary forms, with or without
0027  * modification, are permitted provided that the following conditions
0028  * are met:
0029  * 1. Redistributions of source code must retain the above copyright
0030  *    notice, this list of conditions and the following disclaimer.
0031  * 2. Redistributions in binary form must reproduce the above copyright
0032  *    notice, this list of conditions and the following disclaimer in the
0033  *    documentation and/or other materials provided with the distribution.
0034  *
0035  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0036  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0037  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0038  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0039  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0040  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0041  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0042  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0043  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0044  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0045  * POSSIBILITY OF SUCH DAMAGE.
0046  */
0047 
0048 #ifdef HAVE_CONFIG_H
0049 #include "config.h"
0050 #endif
0051 
0052 #include <stdio.h> /* snprintf() */
0053 #include <stdlib.h> /* malloc(), free() */
0054 #include <inttypes.h> /* printf() macros like PRId8 */
0055 #include <string.h>
0056 #include <ctype.h> /* isprint() */
0057 #include <netdb.h> /* getnameinfo() */
0058 #include <arpa/inet.h>
0059 #include <sys/types.h>
0060 #include <sys/socket.h>
0061 #include <netinet/in.h> /* struct sockaddr_in, struct sockaddr_in6 */
0062 #include <rtems/test.h>
0063 
0064 #include "tftpfs_udp_network_fake.h"
0065 
0066 #define IPV4_ADDR_SIZE 4
0067 #define MAX_SOCKET_FD 4
0068 
0069 int __wrap_close( int fd ); /* Prevent compiler warnings */
0070 int __real_close( int fd ); /* Prevent compiler warnings */
0071 
0072 /*
0073  * Control data
0074  */
0075 
0076 /*
0077  * A singleton global data object is used to control the network interaction
0078  * with the TFTP client.
0079  *
0080  * A test can exchange UDP packets when the TFTP client calls functions
0081  * sendto() and recvfrom().  Simply put, when the client calls sendto()
0082  * the test must check that the client sends the expected UDP packet
0083  * and when the client calls recvfrom() the test must provide the UDP
0084  * packet it wants to send to the client.
0085  *
0086  * Defining the sequence of sendto() and recvfrom() function calls
0087  * including parameters and return values essentially represents a
0088  * test for the TFTP networking.  To be a bit more complete, a few more
0089  * functions such as socket() and bind() are included in the sequence.
0090  *
0091  * Each of these function calls defines a single *interaction* between
0092  * TFTP client and test (aka TFTP server).  The idea is that each test
0093  * defines a sequence of interactions.  In a successful test run all
0094  * interactions must be carried out one-by-one till the last (normally
0095  * "close()") interaction is reached.
0096  *
0097  * The control_data essentially stores the sequence of interactions
0098  * as well as the current state (e.g. which is the next interaction?).
0099  */
0100 typedef struct control_data {
0101   Tftp_Interaction *interaction_head;
0102   Tftp_Interaction *interaction_tail;
0103   Tftp_Interaction *interaction_cur;
0104   int receive_timeout_socket_fd[MAX_SOCKET_FD];
0105   uint32_t receive_timeout_ms[MAX_SOCKET_FD];
0106 } control_data;
0107 
0108 static control_data *control = NULL;
0109 
0110 void _Tftp_Reset( void )
0111 {
0112   static control_data ctl;
0113   int i;
0114   Tftp_Interaction *iter;
0115   Tftp_Interaction *current;
0116 
0117   if ( control == NULL ) {
0118     control = &ctl;
0119   } else {
0120     for ( iter = control->interaction_head; iter != NULL; ) {
0121       current = iter;
0122       iter = iter->next;
0123       free( current );
0124     }
0125   }
0126 
0127   control->interaction_head = NULL;
0128   control->interaction_tail = (Tftp_Interaction *) &control->interaction_head;
0129   control->interaction_cur = (Tftp_Interaction *) &control->interaction_head;
0130   for ( i = 0; i < MAX_SOCKET_FD; ++i ) {
0131     control->receive_timeout_socket_fd[i] = 0;
0132     control->receive_timeout_ms[i] = 0;
0133   }
0134 }
0135 
0136 void *_Tftp_Append_interaction(
0137   Tftp_Action_kind kind,
0138   Tftp_Interaction_fn fn,
0139   size_t size
0140 )
0141 {
0142   Tftp_Interaction *ia;
0143   T_quiet_not_null( control );
0144   ia = malloc( sizeof( Tftp_Interaction ) + size );
0145   T_quiet_not_null( ia );
0146   ia->next = NULL;
0147   ia->kind = kind;
0148   ia->fn = fn;
0149   control->interaction_tail->next = ia;
0150   control->interaction_tail = ia;
0151   return ia->data;
0152 }
0153 
0154 bool _Tftp_Has_no_more_interactions( void )
0155 {
0156   return control == NULL || control->interaction_cur != NULL;
0157 }
0158 
0159 static Tftp_Interaction *get_next_interaction( control_data *control )
0160 {
0161   if ( control == NULL ) {
0162     return NULL;
0163   }
0164   if ( control->interaction_cur != NULL ) {
0165     control->interaction_cur = control->interaction_cur->next;
0166   }
0167   return control->interaction_cur;
0168 }
0169 
0170 static const char *get_action_kind_as_string( Tftp_Action_kind kind )
0171 {
0172   switch ( kind ) {
0173     case TFTP_IA_KIND_SOCKET:
0174       return "socket";
0175     case TFTP_IA_KIND_CLOSE:
0176       return "close";
0177     case TFTP_IA_KIND_BIND:
0178       return "bind";
0179     case TFTP_IA_KIND_SENDTO:
0180       return "sendto";
0181     case TFTP_IA_KIND_RECVFROM:
0182       return "recvfrom";
0183     default:
0184       break;
0185   }
0186   return "UNKNOWN";
0187 }
0188 
0189 /*
0190  * Parse and log UDP TFTP packet functions
0191  */
0192 
0193 const char *_Tftp_Get_error_str( uint16_t error_code )
0194 {
0195   static const char *unknown_str = "Unknown error code";
0196   static const char *error_str[] = {
0197     "Not defined, see error message (if any)",
0198     "File not found",
0199     "Access violation",
0200     "Disk full or allocation exceeded",
0201     "Illegal TFTP operation",
0202     "Unknown transfer ID",
0203     "File already exists",
0204     "No such user",
0205     "Option negociation failed",
0206   };
0207   const char *result = unknown_str;
0208 
0209   if ( error_code < RTEMS_ARRAY_SIZE( error_str ) ) {
0210     result = error_str[ error_code ];
0211   }
0212 
0213   return result;
0214 }
0215 
0216 static void log_hex_dump( const void *buf, size_t len )
0217 {
0218   const size_t per_line = 16;
0219   size_t pos = 0;
0220   const uint8_t *pkt = buf;
0221   char hex[2 * per_line + 4];
0222   char chars[per_line + 1];
0223   char *hexpos;
0224   int i;
0225 
0226   chars[per_line] = '\0';
0227   do {
0228     for ( i = 0, hexpos = hex; i < per_line; ++i ) {
0229       if ( pos + i < len ) {
0230         hexpos += snprintf( hexpos, 3, "%02"PRIX8, pkt[ pos + i ] );
0231         chars[i] = ( isprint( pkt[ pos + i ] ) ) ? pkt[ pos + i ] : '.';
0232       } else {
0233         hexpos += snprintf( hexpos, 3, "  " );
0234         chars[i] = '\0';
0235       }
0236       if ( i < per_line - 1 && i % 4 == 3 ) {
0237         *(hexpos++) = ' ';
0238       }
0239     }
0240 
0241     T_log( T_VERBOSE, "  %04zX : %s |%s|", pos, hex, chars );
0242     pos += per_line;
0243   } while( len > pos );
0244 }
0245 
0246 static const char *get_next_str(
0247   const char **buf,
0248   size_t *max_len,
0249   bool *has_errors
0250 )
0251 {
0252   const char *result;
0253   size_t len = strnlen( *buf, *max_len );
0254   if ( len < *max_len ) {
0255     result = *buf;
0256     *buf += len + 1;
0257     *max_len -= len + 1;
0258   } else {
0259     result = "MAL_FORMED_STRING";
0260     *max_len = 0;
0261     *has_errors = true;
0262   }
0263   return result;
0264 }
0265 
0266 static void log_tftp_packet( const void *buf, size_t len )
0267 {
0268   int op_code;
0269   const char *buffer = ( (char *) buf ) + sizeof( uint16_t );
0270   size_t remaining_len = len - sizeof( uint16_t );
0271   bool has_errors = false;
0272 
0273   if ( len >= sizeof( uint16_t ) ) {
0274     op_code = ntohs( *((uint16_t *) buf ) );
0275     switch ( op_code ) {
0276     case TFTP_OPCODE_RRQ:
0277     case TFTP_OPCODE_WRQ:
0278       T_log(
0279         T_VERBOSE,
0280         "  %s File: \"%s\" Mode: \"%s\" %s",
0281         ( op_code == TFTP_OPCODE_RRQ ) ? "RRQ" : "WRQ",
0282         get_next_str( &buffer, &remaining_len, &has_errors ),
0283         get_next_str( &buffer, &remaining_len, &has_errors ),
0284         ( remaining_len > 0 ) ? "Options:" : "No options"
0285       );
0286       while ( remaining_len > 0 ) {
0287         T_log(
0288           T_VERBOSE,
0289           "    %s = \"%s\"",
0290           get_next_str( &buffer, &remaining_len, &has_errors ),
0291           get_next_str( &buffer, &remaining_len, &has_errors )
0292         );
0293       }
0294       break;
0295 
0296     case TFTP_OPCODE_DATA:
0297       if ( len >= 2 * sizeof( uint16_t ) ) {
0298         buffer += sizeof( uint16_t );
0299         remaining_len -= sizeof( uint16_t );
0300         T_log(
0301           T_VERBOSE,
0302           "  DATA Block: %"PRIu16" Data (%zu bytes):",
0303           ntohs( *( ( (uint16_t *) buf ) + 1 ) ),
0304           remaining_len
0305         );
0306         log_hex_dump( buffer, remaining_len );
0307       } else {
0308         T_log( T_VERBOSE, "  DATA packet ILLEGAL length" );
0309         has_errors = true;
0310       }
0311       break;
0312 
0313     case TFTP_OPCODE_ACK:
0314       if ( len == 2 * sizeof( uint16_t ) ) {
0315         T_log(
0316           T_VERBOSE,
0317           "  ACK Block: %"PRIu16,
0318           ntohs( *( ( (uint16_t *) buf ) + 1 ) )
0319         );
0320       } else {
0321         T_log( T_VERBOSE, "  ACK packet ILLEGAL length" );
0322         has_errors = true;
0323       }
0324       break;
0325 
0326     case TFTP_OPCODE_ERROR:
0327       if ( len > 2 * sizeof( uint16_t ) ) {
0328         uint16_t err_code = ntohs( *( ( (uint16_t *) buf ) + 1 ) );
0329         T_log(
0330           T_VERBOSE,
0331           "  ERROR Code: %"PRIu16" (%s) ErrMsg:",
0332           err_code,
0333           _Tftp_Get_error_str( err_code )
0334         );
0335         buffer += sizeof( uint16_t );
0336         remaining_len -= sizeof( uint16_t );
0337         T_log(
0338           T_VERBOSE,
0339           "    \"%s\"",
0340           get_next_str( &buffer, &remaining_len, &has_errors )
0341         );
0342       } else {
0343         T_log( T_VERBOSE, "  ERROR packet ILLEGAL length" );
0344         has_errors = true;
0345       }
0346       break;
0347 
0348     case TFTP_OPCODE_OACK:
0349       T_log(
0350         T_VERBOSE,
0351         "  OACK %s",
0352         ( remaining_len > 0 ) ? "Options:" : "No options"
0353       );
0354       while ( remaining_len > 0 ) {
0355         T_log(
0356           T_VERBOSE,
0357           "    %s = \"%s\"",
0358           get_next_str( &buffer, &remaining_len, &has_errors ),
0359           get_next_str( &buffer, &remaining_len, &has_errors )
0360         );
0361       }
0362       break;
0363 
0364     default:
0365       T_log( T_VERBOSE, "  TFTP ILLEGAL OpCode: %d", op_code );
0366       has_errors = true;
0367     }
0368   } else {
0369     has_errors = true;
0370   }
0371 
0372   if ( has_errors ) {
0373     log_hex_dump( buf, len );
0374   }
0375 }
0376 
0377 static void log_interaction(
0378   Tftp_Action *act,
0379   bool has_result,
0380   bool was_success
0381 )
0382 {
0383   char *begin = has_result ? "[" : "";
0384   const char *action_name;
0385   int result;
0386   char result_buffer[20];
0387   result_buffer[0] = '\0';
0388 
0389   if ( act == NULL ) { return; }
0390   action_name = get_action_kind_as_string( act->kind );
0391 
0392   if ( has_result && was_success ) {
0393     switch ( act->kind ) {
0394     case TFTP_IA_KIND_SOCKET:
0395       result = act->data.socket.result;
0396       break;
0397 
0398     case TFTP_IA_KIND_CLOSE:
0399       result = act->data.close.result;
0400       break;
0401 
0402     case TFTP_IA_KIND_BIND:
0403       result = act->data.bind.result;
0404       break;
0405 
0406     case TFTP_IA_KIND_SENDTO:
0407       result = (int) act->data.sendto.result;
0408       break;
0409 
0410     case TFTP_IA_KIND_RECVFROM:
0411       result = (int) act->data.recvfrom.result;
0412       break;
0413 
0414     default:
0415       result = 0;
0416     }
0417     snprintf( result_buffer, sizeof( result_buffer ), "] = %d", result );
0418   } else if ( ! was_success ) {
0419     snprintf( result_buffer, sizeof( result_buffer ), "] = FAILED!" );
0420   }
0421 
0422   switch ( act->kind ) {
0423   case TFTP_IA_KIND_SOCKET:
0424     T_log(
0425       T_VERBOSE,
0426       "%s%s(domain=%d, type=%d, protocol=%d)%s",
0427       begin,
0428       action_name,
0429       act->data.socket.domain,
0430       act->data.socket.type,
0431       act->data.socket.protocol,
0432       result_buffer
0433     );
0434     break;
0435 
0436   case TFTP_IA_KIND_CLOSE:
0437     T_log( T_VERBOSE, "%s%s(%d)%s",
0438       begin,
0439       action_name,
0440       act->data.close.fd,
0441       result_buffer
0442     );
0443     break;
0444 
0445   case TFTP_IA_KIND_BIND:
0446     T_log(
0447       T_VERBOSE,
0448       "%s%s(sockfd=%d, addr.family=%d, addr=%s:%"PRIu16")%s",
0449       begin,
0450       action_name,
0451       act->data.bind.fd,
0452       act->data.bind.family,
0453       act->data.bind.addr_str,
0454       act->data.bind.port,
0455       result_buffer
0456     );
0457     break;
0458 
0459   case TFTP_IA_KIND_SENDTO:
0460     T_log(
0461       T_VERBOSE,
0462       "%s%s(sockfd=%d, buf=%p, len=%zu, flags=%X, "
0463         "addr=%s:%"PRIu16", addrlen=%d)%s",
0464       begin,
0465       action_name,
0466       act->data.sendto.fd,
0467       act->data.sendto.buf,
0468       act->data.sendto.len,
0469       act->data.sendto.flags,
0470       act->data.sendto.dest_addr_str,
0471       act->data.sendto.dest_port,
0472       act->data.sendto.addrlen,
0473       result_buffer
0474     );
0475     if ( !has_result ) {
0476       log_tftp_packet( act->data.sendto.buf, act->data.sendto.len );
0477     }
0478     break;
0479 
0480   case TFTP_IA_KIND_RECVFROM:
0481     if ( !has_result ) {
0482       T_log(
0483         T_VERBOSE,
0484         "%s%s(sockfd=%d, buf=%p, len=%zu, flags=%X, "
0485           "timeout=%"PRIu32"ms, addr=?:?, addrlen=%d)%s",
0486         begin,
0487         action_name,
0488         act->data.recvfrom.fd,
0489         act->data.recvfrom.buf,
0490         act->data.recvfrom.len,
0491         act->data.recvfrom.flags,
0492         act->data.recvfrom.timeout_ms,
0493         act->data.recvfrom.addrlen,
0494         result_buffer
0495       );
0496     } else {
0497       T_log(
0498         T_VERBOSE,
0499         "%s%s(sockfd=%d, buf=%p, len=%zu, flags=%X, "
0500           "timeout=%"PRIu32"ms, addr=%s:%"PRIu16", addrlen=%d)%s",
0501         begin,
0502         action_name,
0503         act->data.recvfrom.fd,
0504         act->data.recvfrom.buf,
0505         act->data.recvfrom.len,
0506         act->data.recvfrom.flags,
0507         act->data.recvfrom.timeout_ms,
0508         act->data.recvfrom.src_addr_str,
0509         act->data.recvfrom.src_port,
0510         act->data.recvfrom.addrlen,
0511         result_buffer
0512       );
0513       if ( act->data.recvfrom.result > 0 && was_success ) {
0514         log_tftp_packet( act->data.recvfrom.buf, act->data.recvfrom.result );
0515       }
0516     }
0517     break;
0518 
0519   default:
0520     T_quiet_true( false, "Unknown interaction: %d", act->kind );
0521   }
0522 }
0523 
0524 /*
0525  * Note: This function *must* return.
0526  *   All the fake network functions (and any functions called from them)
0527  *   must return control to the TFTP client.  Hence, do not use T_assert_*()
0528  *   or similar functions.  Even if the test fails at some point,
0529  *   continue and return an error value to the client.
0530  *   Reason: T_assert_*() does stop the test and invokes teardown()
0531  *   without returning to the client.  teardown() then "hangs" when
0532  *   un-mounting while executing client code.
0533  */
0534 static bool process_interaction( Tftp_Action *act )
0535 {
0536   Tftp_Interaction *ia = get_next_interaction( control );
0537   bool result;
0538 
0539   T_quiet_not_null( act );
0540   if ( act == NULL ) {
0541     return false;
0542   } else {
0543     /* Logging this early helps debugging defect tests */
0544     log_interaction( act, false, true );
0545   }
0546 
0547   T_quiet_not_null( ia );
0548   if( ia == NULL ) {
0549     T_log(
0550     T_NORMAL,
0551       "ERROR: You have not registered any (more) 'interaction' but the TFTP "
0552       "client invoked interaction '%s()'. See 'tftpfs_interactions.h' and use "
0553       "'T_set_verbosity( T_VERBOSE )'.",
0554       get_action_kind_as_string( act->kind )
0555     );
0556     return false;
0557   }
0558 
0559   T_true(
0560     act->kind == ia->kind,
0561     "Expected %s() call but got %s()",
0562     get_action_kind_as_string( ia->kind ),
0563     get_action_kind_as_string( act->kind )
0564   );
0565   if ( act->kind != ia->kind ) {
0566     return false;
0567   }
0568   result = ia->fn( act, ia->data );
0569   log_interaction( act, true, result );
0570 
0571   return result;
0572 }
0573 
0574 static uint16_t get_ip_addr_as_str(
0575   const struct sockaddr *addr,
0576   socklen_t addrlen,
0577   char *buf,
0578   size_t buf_size
0579 )
0580 {
0581   uint16_t port = 0xFFFF;
0582   *buf = '\0';
0583 
0584   switch ( addr->sa_family ) {
0585   case AF_INET:
0586     {
0587       const struct sockaddr_in *ipv4 = (const struct sockaddr_in *) addr;
0588       port = ntohs( ipv4->sin_port );
0589       const uint8_t *bytes = (const uint8_t *) &ipv4->sin_addr.s_addr;
0590       snprintf(
0591         buf,
0592         buf_size,
0593         "%"PRIu8".%"PRIu8".%"PRIu8".%"PRIu8,
0594         bytes[0],
0595         bytes[1],
0596         bytes[2],
0597         bytes[3]
0598       );
0599       break;
0600     }
0601   case AF_INET6:
0602     {
0603       const struct sockaddr_in6 *ipv6 = (const struct sockaddr_in6 *) addr;
0604       port = ntohs( ipv6->sin6_port );
0605       const uint16_t *words = (const uint16_t *) ipv6->sin6_addr.s6_addr;
0606       snprintf(
0607         buf,
0608         buf_size,
0609         "%"PRIx16":%"PRIx16":%"PRIx16":%"PRIx16":%"PRIx16":%"PRIx16
0610           ":%"PRIx16":%"PRIx16,
0611         ntohs( words[0] ),
0612         ntohs( words[1] ),
0613         ntohs( words[2] ),
0614         ntohs( words[3] ),
0615         ntohs( words[4] ),
0616         ntohs( words[5] ),
0617         ntohs( words[6] ),
0618         ntohs( words[7] )
0619       );
0620       break;
0621     }
0622   }
0623 
0624   return port;
0625 }
0626 
0627 static void set_ip_addr_from_str(
0628   const char *addr_str,
0629   uint16_t port,
0630   struct sockaddr *addr,
0631   socklen_t *addrlen
0632  )
0633 {
0634   socklen_t addr_size;
0635   int res;
0636   int i;
0637 
0638   if ( addr == NULL || addrlen == NULL ) {
0639     return;
0640   }
0641   addr_size = *addrlen;
0642 
0643   if ( strchr( addr_str, ':' ) == NULL ) {
0644     /* IPv4 address */
0645     struct sockaddr_in *ipv4_addr = (struct sockaddr_in *) addr;
0646     uint8_t *bytes = (uint8_t *) &ipv4_addr->sin_addr.s_addr;
0647 
0648     *addrlen = sizeof( struct sockaddr_in );
0649     T_ge_sz( addr_size, *addrlen );
0650     if ( addr_size < *addrlen ) { return; }
0651     ipv4_addr->sin_family = AF_INET;
0652     ipv4_addr->sin_port = htons( port );
0653     res = sscanf(
0654       addr_str,
0655       "%"SCNu8".%"SCNu8".%"SCNu8".%"SCNu8,
0656       bytes,
0657       bytes + 1,
0658       bytes + 2,
0659       bytes + 3
0660     );
0661     T_quiet_true( res == 4, "Connot parse IPv4 address: \"%s\"", addr_str );
0662   } else {
0663     /* IPv6 address */
0664     struct sockaddr_in6 *ipv6_addr = (struct sockaddr_in6 *) addr;
0665     uint16_t *words = (uint16_t *) &ipv6_addr->sin6_addr.s6_addr;
0666 
0667     *addrlen = sizeof( struct sockaddr_in6 );
0668     T_gt_sz( addr_size, *addrlen );
0669     if ( addr_size < *addrlen ) { return; }
0670     ipv6_addr->sin6_family = AF_INET6;
0671     ipv6_addr->sin6_port = htons( port );
0672     ipv6_addr->sin6_flowinfo = 0;
0673     ipv6_addr->sin6_scope_id = 0;
0674     res = sscanf(
0675       addr_str,
0676       "%"SCNx16":%"SCNx16":%"SCNx16":%"SCNx16":%"SCNx16":%"SCNx16
0677         ":%"SCNx16":%"SCNx16,
0678       words,
0679       words + 1,
0680       words + 2,
0681       words + 3,
0682       words + 4,
0683       words + 5,
0684       words + 6,
0685       words + 7
0686     );
0687     T_quiet_true( res == 8, "Connot parse IPv6 address: \"%s\"", addr_str );
0688     for ( i = 0; i < 8; ++i ) {
0689       words[i] = htons( words[i] );
0690     }
0691   }
0692 }
0693 
0694 /*
0695  * Fake networking functions
0696  */
0697 
0698 int inet_aton( const char *cp, struct in_addr *inp )
0699 {
0700   int result = 0;
0701   uint8_t *ipv4_addr = (uint8_t *) inp;
0702   static const char addr0[] = TFTP_KNOWN_IPV4_ADDR0_STR;
0703   static const uint8_t addr0_data[] = { TFTP_KNOWN_IPV4_ADDR0_ARRAY };
0704 
0705   if ( strcmp( addr0, cp ) == 0 ) {
0706     memcpy( ipv4_addr, addr0_data, sizeof( addr0_data ) );
0707     result = 1;
0708   }
0709 
0710   T_log(
0711     T_VERBOSE,
0712     "inet_aton(cp=%s, addr=%"PRIu8".%"PRIu8".%"PRIu8".%"PRIu8") = %d",
0713     cp,
0714     ipv4_addr[0],
0715     ipv4_addr[1],
0716     ipv4_addr[2],
0717     ipv4_addr[3],
0718     result
0719   );
0720   return result;
0721 }
0722 
0723 struct hostent *gethostbyname( const char *name )
0724 {
0725   static char ip_addr_bytes[] = {
0726     TFTP_KNOWN_SERVER0_ARRAY,   /* IPv4: 10.7.0.2 "server.tftp" */
0727     TFTP_KNOWN_IPV4_ADDR0_ARRAY /* IPv4: 127.0.0.1 "127.0.0.1" */
0728   };
0729   static char *ip_addrs[] = {
0730     ip_addr_bytes + 0 * IPV4_ADDR_SIZE, NULL,
0731     ip_addr_bytes + 1 * IPV4_ADDR_SIZE, NULL
0732   };
0733   static struct hostent hosts[] = {
0734     {
0735     .h_name      = TFTP_KNOWN_SERVER0_NAME,
0736     .h_aliases   = NULL,
0737     .h_addrtype  = AF_INET,
0738     .h_length    = IPV4_ADDR_SIZE,
0739     .h_addr_list = ip_addrs + 0,
0740     },
0741     {
0742     .h_name      = TFTP_KNOWN_IPV4_ADDR0_STR,
0743     .h_aliases   = NULL,
0744     .h_addrtype  = AF_INET,
0745     .h_length    = IPV4_ADDR_SIZE,
0746     .h_addr_list = ip_addrs + 2,
0747     }
0748   };
0749   struct hostent *result = NULL;
0750   uint8_t *ipv4_addr;
0751   int i;
0752 
0753   for ( i = 0; i < RTEMS_ARRAY_SIZE( hosts ); ++i ) {
0754     if ( strcmp( hosts[i].h_name, name ) == 0 ) {
0755       result = hosts + i;
0756     }
0757   }
0758   /* Note: `h_errno` not set due to linker issues */
0759 
0760   if ( result != NULL ) {
0761     ipv4_addr = (uint8_t *) result->h_addr_list[0];
0762     T_log(
0763       T_VERBOSE,
0764       "gethostbyname(%s) = %s, %"PRIu8".%"PRIu8".%"PRIu8".%"PRIu8,
0765       name,
0766       result->h_name,
0767       ipv4_addr[0],
0768       ipv4_addr[1],
0769       ipv4_addr[2],
0770       ipv4_addr[3]
0771     );
0772   } else {
0773     T_log( T_NORMAL, "gethostbyname(%s) = %p", name, result );
0774   }
0775   return result;
0776 }
0777 
0778 int socket( int domain, int type, int protocol )
0779 {
0780   Tftp_Action act = {
0781     .kind                 = TFTP_IA_KIND_SOCKET,
0782     .data.socket.domain   = domain,
0783     .data.socket.type     = type,
0784     .data.socket.protocol = protocol
0785   };
0786 
0787   if( !process_interaction( &act ) ) {
0788     return -1;
0789   };
0790 
0791   /* Should never happen but check prevents programming mistakes */
0792   T_quiet_ge_int( act.data.socket.result, TFTP_FIRST_FD );
0793   if( act.data.socket.result < TFTP_FIRST_FD ) {
0794     return -1;
0795   };
0796 
0797   return act.data.socket.result;
0798 }
0799 
0800 int __wrap_close( int fd )
0801 {
0802   if ( fd < TFTP_FIRST_FD ) {
0803     /* Normal file descriptors - i.e. not from fake socket() function above */
0804     return __real_close( fd );
0805   }
0806   Tftp_Action act = {
0807     .kind = TFTP_IA_KIND_CLOSE,
0808     .data.close.fd = fd,
0809   };
0810 
0811   if( !process_interaction( &act ) ) {
0812     return -1;
0813   };
0814 
0815   return act.data.close.result;
0816 }
0817 
0818 int bind( int sockfd, const struct sockaddr *addr, socklen_t addrlen )
0819 {
0820   char addr_buf[INET6_ADDRSTRLEN];
0821   Tftp_Action act = {
0822     .kind                   = TFTP_IA_KIND_BIND,
0823     .data.bind.fd           = sockfd,
0824     .data.bind.family       = addr->sa_family,
0825     .data.bind.addr_str     = addr_buf
0826   };
0827   act.data.bind.port = get_ip_addr_as_str(
0828     addr,
0829     addrlen,
0830     addr_buf,
0831     sizeof( addr_buf )
0832   );
0833 
0834   if( !process_interaction( &act ) ) {
0835     return -1;
0836   };
0837 
0838   return act.data.bind.result;
0839 }
0840 
0841 int setsockopt(
0842   int sockfd,
0843   int level,
0844   int optname,
0845   const void *optval,
0846   socklen_t optlen
0847 )
0848 {
0849   int result = 0;
0850   int i;
0851   const struct timeval *tv = optval;
0852 
0853   T_log(
0854     T_VERBOSE,
0855     "setsockopt(sockfd=%d, level=%s, optname=%s, optval=%dms )",
0856     sockfd,
0857     ( level == SOL_SOCKET    ) ? "SOL_SOCKET"  : "UNKONWN",
0858     ( optname == SO_RCVTIMEO ) ? "SO_RCVTIMEO" : "UNKONWN",
0859     ( optname == SO_RCVTIMEO ) ?
0860       (int) ( tv->tv_sec * 1000 + tv->tv_usec / 1000 ) : -1
0861   );
0862 
0863   T_eq_int( level, SOL_SOCKET );
0864   T_eq_int( optname, SO_RCVTIMEO );
0865   T_eq_int( (int) optlen, sizeof( struct timeval ) );
0866   if (
0867     level != SOL_SOCKET ||
0868     optname != SO_RCVTIMEO ||
0869     optlen != sizeof( struct timeval )
0870   ) {
0871     result = -1;
0872   }
0873 
0874   for ( i = 0; result >= 0; ++i ) {
0875     if ( i >= MAX_SOCKET_FD ) {
0876       T_quiet_true(
0877         false,
0878         "Too few IP ports %d, increase MAX_SOCKET_FD",
0879         MAX_SOCKET_FD
0880       );
0881       result = -1;
0882       break;
0883     }
0884     if ( control->receive_timeout_socket_fd[i] == sockfd ||
0885       control->receive_timeout_socket_fd[i] == 0 ) {
0886       control->receive_timeout_socket_fd[i] = sockfd;
0887       control->receive_timeout_ms[i]   = tv->tv_sec * 1000 + tv->tv_usec / 1000;
0888       break;
0889     }
0890   }
0891 
0892   T_log(
0893     T_VERBOSE,
0894     "[setsockopt(sockfd=%d, level=%s, optname=%s, optval=%"PRIu32"ms )] = %d",
0895     sockfd,
0896     ( level == SOL_SOCKET    ) ? "SOL_SOCKET"  : "UNKONWN",
0897     ( optname == SO_RCVTIMEO ) ? "SO_RCVTIMEO" : "UNKONWN",
0898     ( i < MAX_SOCKET_FD ) ? control->receive_timeout_ms[i] : -1,
0899     result
0900   );
0901 
0902   return result;
0903 }
0904 
0905 ssize_t sendto(
0906   int sockfd,
0907   const void *buf,
0908   size_t len,
0909   int flags,
0910   const struct sockaddr *dest_addr,
0911   socklen_t addrlen
0912 )
0913 {
0914   char addr_buf[INET6_ADDRSTRLEN];
0915   Tftp_Action act = {
0916     .kind                      = TFTP_IA_KIND_SENDTO,
0917     .data.sendto.fd            = sockfd,
0918     .data.sendto.buf           = buf,
0919     .data.sendto.len           = len,
0920     .data.sendto.flags         = flags,
0921     .data.sendto.dest_addr_str = addr_buf,
0922     .data.sendto.addrlen       = (int) addrlen,
0923   };
0924   act.data.sendto.dest_port = get_ip_addr_as_str(
0925     dest_addr,
0926     addrlen,
0927     addr_buf,
0928     sizeof( addr_buf )
0929   );
0930 
0931   if( !process_interaction( &act ) ) {
0932     return -1;
0933   };
0934 
0935   return act.data.sendto.result;
0936 }
0937 
0938 ssize_t recvfrom(
0939   int sockfd,
0940   void *buf,
0941   size_t len,
0942   int flags,
0943   struct sockaddr *src_addr,
0944   socklen_t *addrlen
0945 )
0946 {
0947   int i;
0948   Tftp_Packet *pkt = buf;
0949   Tftp_Action act = {
0950     .kind                       = TFTP_IA_KIND_RECVFROM,
0951     .data.recvfrom.fd           = sockfd,
0952     .data.recvfrom.buf          = buf,
0953     .data.recvfrom.len          = len,
0954     .data.recvfrom.flags        = flags,
0955     .data.recvfrom.timeout_ms   = 0,
0956     .data.recvfrom.addrlen      = (int) *addrlen
0957   };
0958 
0959   for ( i = 0; i < MAX_SOCKET_FD; ++i ) {
0960     if ( control->receive_timeout_socket_fd[i] == sockfd ) {
0961       act.data.recvfrom.timeout_ms = control->receive_timeout_ms[i];
0962       break;
0963     }
0964   }
0965 
0966   /* Make log_tftp_packet() behave sane, if buf is not filled */
0967   if ( len >= sizeof( pkt->opcode ) ) {
0968     pkt->opcode = ntohs( 0xFFFF );
0969   }
0970 
0971   if( !process_interaction( &act ) ) {
0972     return -1;
0973   };
0974 
0975   set_ip_addr_from_str(
0976     act.data.recvfrom.src_addr_str,
0977     act.data.recvfrom.src_port,
0978     src_addr,
0979     addrlen
0980   );
0981 
0982   return act.data.recvfrom.result;
0983 }