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 network interaction
0009  *   functions related to the UDP network fake for tftpfs testing.
0010  *
0011  * The UDP Network Fake requires *interactions* between TFTP client and test
0012  * (which emulates a TFTP server).  The idea is that each test defines a
0013  * sequence of interactions.  In a successful test run all interactions must
0014  * be carried out one-by-one till the *last* interaction is reached.
0015  *
0016  * Interactions appear when the TFTP client calls functions like
0017  * sendto(), recvfrom(), or socket().  Here functions are defined
0018  * which
0019  *
0020  *   * handle such interactions and
0021  *   * permit the tests to easily defined the sequence of interactions.
0022  */
0023 
0024 /*
0025  * Copyright (C) 2022 embedded brains GmbH & Co. KG
0026  *
0027  * Redistribution and use in source and binary forms, with or without
0028  * modification, are permitted provided that the following conditions
0029  * are met:
0030  * 1. Redistributions of source code must retain the above copyright
0031  *    notice, this list of conditions and the following disclaimer.
0032  * 2. Redistributions in binary form must reproduce the above copyright
0033  *    notice, this list of conditions and the following disclaimer in the
0034  *    documentation and/or other materials provided with the distribution.
0035  *
0036  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0037  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0038  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0039  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0040  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0041  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0042  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0043  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0044  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0045  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0046  * POSSIBILITY OF SUCH DAMAGE.
0047  */
0048 
0049 #ifdef HAVE_CONFIG_H
0050 #include "config.h"
0051 #endif
0052 
0053 #include <stdio.h> /* sprintf() */
0054 #include <inttypes.h> /* printf() macros like PRId8 */
0055 #include <arpa/inet.h> /* ntohs() */
0056 #include <rtems/test.h>
0057 
0058 
0059 #include "tftpfs_interactions.h"
0060 #include "tftpfs_udp_network_fake.h"
0061 
0062 /*
0063  * Interaction: socket()
0064  */
0065 
0066 typedef struct interaction_data_socket {
0067   int domain;
0068   int type;
0069   int protocol;
0070   int result;
0071 } interaction_data_socket;
0072 
0073 static bool interact_socket( Tftp_Action *act, void *data )
0074 {
0075   interaction_data_socket *d = data;
0076   T_eq_int( act->data.socket.domain,   d->domain );
0077   T_eq_int( act->data.socket.type,     d->type );
0078   T_eq_int( act->data.socket.protocol, d->protocol );
0079   if (
0080     act->data.socket.domain   != d->domain ||
0081     act->data.socket.type     != d->type ||
0082     act->data.socket.protocol != d->protocol
0083   ) {
0084     return false;
0085   }
0086 
0087   act->data.socket.result = d->result;
0088   return true;
0089 }
0090 
0091 void _Tftp_Add_interaction_socket(
0092   int domain,
0093   int type,
0094   int protocol,
0095   int result
0096 )
0097 {
0098   interaction_data_socket *d;
0099 
0100   d = _Tftp_Append_interaction(
0101     TFTP_IA_KIND_SOCKET,
0102     interact_socket,
0103     sizeof( interaction_data_socket )
0104   );
0105 
0106   d->domain   = domain;
0107   d->type     = type;
0108   d->protocol = protocol;
0109   d->result   = result;
0110 }
0111 
0112 /*
0113  * Interaction: close()
0114  */
0115 
0116 typedef struct interaction_data_close {
0117   int fd;
0118   int result;
0119 } interaction_data_close;
0120 
0121 static bool interact_close( Tftp_Action *act, void *data )
0122 {
0123   interaction_data_close *d = data;
0124   T_eq_int( act->data.close.fd, d->fd );
0125   if ( act->data.close.fd != d->fd ) {
0126     return false;
0127   }
0128 
0129   act->data.close.result = d->result;
0130   return true;
0131 }
0132 
0133 void _Tftp_Add_interaction_close( int fd, int result )
0134 {
0135   interaction_data_close *d;
0136 
0137   d = _Tftp_Append_interaction(
0138     TFTP_IA_KIND_CLOSE,
0139     interact_close,
0140     sizeof( interaction_data_close )
0141   );
0142 
0143   d->fd     = fd;
0144   d->result = result;
0145 }
0146 
0147 /*
0148  * Interaction: bind()
0149  */
0150 
0151 typedef struct interaction_data_bind {
0152   int fd;
0153   int family;
0154   int result;
0155 } interaction_data_bind;
0156 
0157 static bool interact_bind( Tftp_Action *act, void *data )
0158 {
0159   interaction_data_bind *d = data;
0160   T_eq_int( act->data.bind.fd, d->fd );
0161   T_eq_int( act->data.bind.family, d->family );
0162   if (
0163     act->data.bind.fd     != d->fd     ||
0164     act->data.bind.family != d->family
0165   ) {
0166     return false;
0167   }
0168 
0169   act->data.bind.result = d->result;
0170   return true;
0171 }
0172 
0173 void _Tftp_Add_interaction_bind( int fd, int family, int result )
0174 {
0175   interaction_data_bind *d;
0176 
0177   d = _Tftp_Append_interaction(
0178     TFTP_IA_KIND_BIND,
0179     interact_bind,
0180     sizeof( interaction_data_bind )
0181   );
0182 
0183   d->fd     = fd;
0184   d->family = family;
0185   d->result = result;
0186 }
0187 
0188 /*
0189  * Interaction: sendto()
0190  */
0191 
0192 #define TFTP_MAX_FILENAME_STRLEN 12
0193 
0194 typedef struct interaction_data_sendto {
0195   int fd;
0196   uint16_t dest_port;
0197   char dest_addr_str[TFTP_MAX_IP_ADDR_STRLEN];
0198   bool result;
0199   union {
0200     struct {
0201       uint16_t opcode;
0202       char filename[TFTP_MAX_FILENAME_STRLEN];
0203       uint16_t block_size;
0204       uint16_t window_size;
0205     } rwrq;
0206     struct {
0207       uint16_t block_num;
0208     } ack;
0209     struct {
0210       uint16_t block_num;
0211       size_t start;
0212       size_t len;
0213       uint8_t (*get_data)( size_t pos );
0214     } data;
0215     struct {
0216       uint16_t error_code;
0217     } error;
0218   } content;
0219 } interaction_data_sendto;
0220 
0221 static bool check_filename_and_mode(
0222   const char **buf,
0223   size_t *max_len,
0224   const char *filename
0225 )
0226 {
0227   const char *str;
0228   size_t len;
0229 
0230   /* Make sure there is a 0 byte in the end before comparing strings */
0231   if ( *max_len <= 0 ) { return false; };
0232   T_quiet_eq_u8( *( *buf + *max_len - 1 ), '\0' );
0233 
0234   str = *buf;
0235   len = strlen( *buf ) + 1;
0236   *buf += len;
0237   *max_len -= len;
0238   if ( strcmp( str, filename ) != 0 ) {
0239     T_true( false, "Filename '%s' does not match '%s'", str, filename );
0240     return false;
0241   }
0242   if ( *max_len <= 0 ) {
0243     T_true( false, "Mode string missing." );
0244     return false;
0245   }
0246 
0247   str = *buf;
0248   len = strlen( *buf ) + 1;
0249   *buf += len;
0250   *max_len -= len;
0251   if ( strcasecmp( str, TFTP_MODE_OCTET ) != 0 ) {
0252     T_true( false, "Mode '%s' does not match '%s'", str, TFTP_MODE_OCTET );
0253     return false;
0254   }
0255 
0256   return true;
0257 }
0258 
0259 static bool check_for_option(
0260   const char **buf,
0261   size_t *max_len,
0262   const char *option_name,
0263   const char *option_value
0264 )
0265 {
0266   const char *str;
0267   size_t len;
0268 
0269   /* Make sure there is a 0 byte in the end before comparing strings */
0270   if ( *max_len <= 0 ) { return false; };
0271   T_quiet_eq_u8( *( *buf + *max_len - 1 ), '\0' );
0272 
0273   str = *buf;
0274   len = strlen( *buf ) + 1;
0275   if ( strcasecmp( str, option_name ) != 0 ) {
0276     return false;
0277   }
0278   *buf += len;
0279   *max_len -= len;
0280 
0281   if ( *max_len <= 0 ) {
0282     T_true( false, "Option value for '%s' missing.", option_name );
0283     return false;
0284   }
0285 
0286   str = *buf;
0287   len = strlen( *buf ) + 1;
0288   *buf += len;
0289   *max_len -= len;
0290   if ( strcmp( str, option_value ) != 0 ) {
0291     T_true(
0292       false,
0293       "Option '%s': Actual value '%s' does not match '%s'",
0294       option_name,
0295       str,
0296       option_value
0297     );
0298     return false;
0299   }
0300 
0301   return true;
0302 }
0303 
0304 static bool interact_sendto_common( Tftp_Action *act, void *data )
0305 {
0306   interaction_data_sendto *d = data;
0307   const Tftp_Packet *pkt = act->data.sendto.buf;
0308 
0309   T_eq_int( act->data.sendto.fd,            d->fd );
0310   T_eq_int( act->data.sendto.flags,         0 );
0311   T_eq_u16( act->data.sendto.dest_port,     d->dest_port );
0312   T_eq_str( act->data.sendto.dest_addr_str, d->dest_addr_str );
0313   T_gt_sz(  act->data.sendto.len,           sizeof( pkt->opcode ) );
0314   if (
0315     act->data.sendto.fd        != d->fd ||
0316     act->data.sendto.flags     != 0 ||
0317     act->data.sendto.dest_port != d->dest_port ||
0318     strcmp( act->data.sendto.dest_addr_str, d->dest_addr_str ) != 0 ||
0319     act->data.sendto.len       <= sizeof( pkt->opcode )
0320   ) {
0321     return false;
0322   }
0323 
0324   act->data.sendto.result = d->result ? act->data.sendto.len : -1;
0325   return true;
0326 }
0327 
0328 static bool interact_sendto_rwrq( Tftp_Action *act, void *data )
0329 {
0330   interaction_data_sendto *d = data;
0331   const Tftp_Packet *pkt = act->data.sendto.buf;
0332   size_t len = act->data.sendto.len - sizeof( pkt->opcode );
0333   const char *buf = pkt->content.rrq.opts;
0334   const char *tmp;
0335   char block_size_buffer[6];
0336   char window_size_buffer[6];
0337 
0338   if ( !interact_sendto_common( act, data ) ) {
0339     return false;
0340   }
0341 
0342   T_eq_u16( ntohs( pkt->opcode ), d->content.rwrq.opcode );
0343   if ( ntohs( pkt->opcode ) != d->content.rwrq.opcode ) { return false; }
0344   if ( !check_filename_and_mode( &buf, &len, d->content.rwrq.filename ) ) {
0345     return false;
0346   }
0347 
0348   snprintf(
0349     block_size_buffer,
0350     sizeof( block_size_buffer ),
0351     "%"PRIu16,
0352     d->content.rwrq.block_size
0353   );
0354   snprintf(
0355     window_size_buffer,
0356     sizeof( window_size_buffer ),
0357     "%"PRIu16,
0358     d->content.rwrq.window_size
0359   );
0360 
0361   for ( tmp = buf; len > 0; ) {
0362     if ( d->content.rwrq.block_size != NO_BLOCK_SIZE_OPTION &&
0363       check_for_option(
0364         &buf,
0365         &len,
0366         TFTP_OPTION_BLKSIZE,
0367         block_size_buffer )) {
0368         d->content.rwrq.block_size = NO_BLOCK_SIZE_OPTION;
0369     } else if ( d->content.rwrq.window_size != NO_WINDOW_SIZE_OPTION &&
0370       check_for_option(
0371         &buf,
0372         &len,
0373         TFTP_OPTION_WINDOWSIZE,
0374         window_size_buffer )) {
0375         d->content.rwrq.window_size = NO_WINDOW_SIZE_OPTION;
0376     } else {
0377       T_true( false, "Error at option '%s'", tmp );
0378       return false;
0379     }
0380   }
0381 
0382   T_eq_sz( len, 0 ); /* Check that all data till the end has been read */
0383 
0384   return true;
0385 }
0386 
0387 static bool interact_sendto_ack( Tftp_Action *act, void *data )
0388 {
0389   interaction_data_sendto *d = data;
0390   const Tftp_Packet *pkt = act->data.sendto.buf;
0391   size_t pkt_size = sizeof( pkt->opcode ) + sizeof( pkt->content.ack );
0392 
0393   if ( !interact_sendto_common( act, data ) ) {
0394     return false;
0395   }
0396 
0397   T_eq_u16( ntohs( pkt->opcode ), TFTP_OPCODE_ACK );
0398   T_eq_sz( act->data.sendto.len, pkt_size );
0399   if ( ntohs( pkt->opcode ) != TFTP_OPCODE_ACK ||
0400     act->data.sendto.len != pkt_size
0401   ) {
0402     return false;
0403   }
0404 
0405   T_eq_u16( ntohs( pkt->content.ack.block_num ), d->content.ack.block_num );
0406   if ( ntohs( pkt->content.ack.block_num ) != d->content.ack.block_num ) {
0407     return false;
0408   }
0409 
0410   return true;
0411 }
0412 
0413 static bool interact_sendto_data( Tftp_Action *act, void *data )
0414 {
0415   interaction_data_sendto *d = data;
0416   const Tftp_Packet *pkt = act->data.sendto.buf;
0417   size_t pkt_size = sizeof( pkt->opcode ) +
0418     sizeof( pkt->content.data.block_num ) + d->content.data.len;
0419   size_t i;
0420 
0421   if ( !interact_sendto_common( act, data ) ) {
0422     return false;
0423   }
0424 
0425   T_eq_u16( ntohs( pkt->opcode ), TFTP_OPCODE_DATA );
0426   T_eq_sz( act->data.sendto.len, pkt_size );
0427   if ( ntohs( pkt->opcode ) != TFTP_OPCODE_DATA ||
0428     act->data.sendto.len != pkt_size
0429   ) {
0430     return false;
0431   }
0432 
0433   T_eq_u16( ntohs( pkt->content.ack.block_num ), d->content.ack.block_num );
0434   if ( ntohs( pkt->content.ack.block_num ) != d->content.ack.block_num ) {
0435     return false;
0436   }
0437 
0438   for ( i = 0; i < d->content.data.len; ++i ) {
0439     if ( pkt->content.data.bytes[i] !=
0440       d->content.data.get_data( d->content.data.start + i ) ) {
0441     T_true(
0442       false,
0443       "Expected byte %02"PRIx8" but TFTP client sent %02"PRIx8
0444         " at position %zu",
0445       d->content.data.get_data( d->content.data.start + i ),
0446       pkt->content.data.bytes[i],
0447       d->content.data.start + i
0448       );
0449       return false;
0450     }
0451   }
0452 
0453   return true;
0454 }
0455 
0456 static bool interact_sendto_error( Tftp_Action *act, void *data )
0457 {
0458   interaction_data_sendto *d = data;
0459   const Tftp_Packet *pkt = act->data.sendto.buf;
0460   size_t pkt_size = sizeof( pkt->opcode ) + sizeof( pkt->content.error );
0461 
0462   if ( !interact_sendto_common( act, data ) ) {
0463     return false;
0464   }
0465 
0466   T_eq_u16( ntohs( pkt->opcode ), TFTP_OPCODE_ERROR );
0467   T_gt_sz( act->data.sendto.len, pkt_size );
0468   if ( ntohs( pkt->opcode ) != TFTP_OPCODE_ERROR ||
0469     act->data.sendto.len <= pkt_size
0470   ) {
0471     return false;
0472   }
0473 
0474   T_eq_u16(
0475     ntohs( pkt->content.error.error_code ),
0476     d->content.error.error_code
0477   );
0478   if ( ntohs( pkt->content.error.error_code ) != d->content.error.error_code ) {
0479     return false;
0480   }
0481 
0482   return true;
0483 }
0484 
0485 static void add_interaction_send_rwrq(
0486   int fd,
0487   const char *filename,
0488   uint16_t dest_port,
0489   const char *dest_addr_str,
0490   uint16_t block_size,
0491   uint16_t window_size,
0492   bool result,
0493   uint16_t opcode
0494 )
0495 {
0496   interaction_data_sendto *d;
0497 
0498   d = _Tftp_Append_interaction(
0499     TFTP_IA_KIND_SENDTO,
0500     interact_sendto_rwrq,
0501     sizeof( interaction_data_sendto )
0502   );
0503 
0504   T_assert_lt_sz( strlen( filename ), TFTP_MAX_FILENAME_STRLEN );
0505   T_assert_lt_sz( strlen( dest_addr_str ), TFTP_MAX_IP_ADDR_STRLEN );
0506   strcpy( d->content.rwrq.filename, filename );
0507   strcpy( d->dest_addr_str, dest_addr_str );
0508   d->fd                       = fd;
0509   d->dest_port                = dest_port;
0510   d->content.rwrq.opcode      = opcode;
0511   d->content.rwrq.block_size  = block_size;
0512   d->content.rwrq.window_size = window_size;
0513   d->result                   = result;
0514 }
0515 
0516 void _Tftp_Add_interaction_send_rrq(
0517   int fd,
0518   const char *filename,
0519   uint16_t dest_port,
0520   const char *dest_addr_str,
0521   uint16_t block_size,
0522   uint16_t window_size,
0523   bool result
0524 )
0525 {
0526   add_interaction_send_rwrq(
0527     fd,
0528     filename,
0529     dest_port,
0530     dest_addr_str,
0531     block_size,
0532     window_size,
0533     result,
0534     TFTP_OPCODE_RRQ
0535   );
0536 }
0537 
0538 void _Tftp_Add_interaction_send_wrq(
0539   int fd,
0540   const char *filename,
0541   uint16_t dest_port,
0542   const char *dest_addr_str,
0543   uint16_t block_size,
0544   uint16_t window_size,
0545   bool result
0546 )
0547 {
0548   add_interaction_send_rwrq(
0549     fd,
0550     filename,
0551     dest_port,
0552     dest_addr_str,
0553     block_size,
0554     window_size,
0555     result,
0556     TFTP_OPCODE_WRQ
0557   );
0558 }
0559 
0560 void _Tftp_Add_interaction_send_ack(
0561   int fd,
0562   uint16_t block_num,
0563   uint16_t dest_port,
0564   const char *dest_addr_str,
0565   bool result
0566 )
0567 {
0568   interaction_data_sendto *d;
0569 
0570   d = _Tftp_Append_interaction(
0571     TFTP_IA_KIND_SENDTO,
0572     interact_sendto_ack,
0573     sizeof( interaction_data_sendto )
0574   );
0575 
0576   T_assert_lt_sz( strlen( dest_addr_str ), TFTP_MAX_IP_ADDR_STRLEN );
0577   strcpy( d->dest_addr_str, dest_addr_str );
0578   d->fd                    = fd;
0579   d->dest_port             = dest_port;
0580   d->result                = result;
0581   d->content.ack.block_num = block_num;
0582 }
0583 
0584 void _Tftp_Add_interaction_send_data(
0585   int fd,
0586   uint16_t block_num,
0587   size_t start,
0588   size_t len,
0589   uint8_t (*get_data)( size_t pos ),
0590   uint16_t dest_port,
0591   const char *dest_addr_str,
0592   bool result
0593 )
0594 {
0595   interaction_data_sendto *d;
0596 
0597   d = _Tftp_Append_interaction(
0598     TFTP_IA_KIND_SENDTO,
0599     interact_sendto_data,
0600     sizeof( interaction_data_sendto )
0601   );
0602 
0603   T_assert_lt_sz( strlen( dest_addr_str ), TFTP_MAX_IP_ADDR_STRLEN );
0604   strcpy( d->dest_addr_str, dest_addr_str );
0605   d->fd                     = fd;
0606   d->dest_port              = dest_port;
0607   d->result                 = result;
0608   d->content.data.block_num = block_num;
0609   d->content.data.start     = start;
0610   d->content.data.len       = len;
0611   d->content.data.get_data  = get_data;
0612 }
0613 
0614 void _Tftp_Add_interaction_send_error(
0615   int fd,
0616   uint16_t error_code,
0617   uint16_t dest_port,
0618   const char *dest_addr_str,
0619   bool result
0620 )
0621 {
0622   interaction_data_sendto *d;
0623 
0624   d = _Tftp_Append_interaction(
0625     TFTP_IA_KIND_SENDTO,
0626     interact_sendto_error,
0627     sizeof( interaction_data_sendto )
0628   );
0629 
0630   T_assert_lt_sz( strlen( dest_addr_str ), TFTP_MAX_IP_ADDR_STRLEN );
0631   strcpy( d->dest_addr_str, dest_addr_str );
0632   d->fd                       = fd;
0633   d->dest_port                = dest_port;
0634   d->result                   = result;
0635   d->content.error.error_code = error_code;
0636 }
0637 
0638 /*
0639  * Interaction: recvfrom()
0640  */
0641 
0642 typedef struct interaction_data_recvfrom {
0643   int fd;
0644   uint32_t timeout_ms;
0645   uint16_t src_port;
0646   char src_addr_str[TFTP_MAX_IP_ADDR_STRLEN];
0647   bool result;
0648   union {
0649     struct {
0650       uint16_t block_num;
0651     } ack;
0652     struct {
0653       size_t options_size;
0654       char options[TFTP_MAX_OPTIONS_SIZE];
0655     } oack;
0656     struct {
0657       uint16_t block_num;
0658       size_t start;
0659       size_t len;
0660       uint8_t (*get_data)( size_t pos );
0661     } data;
0662     struct {
0663       uint16_t error_code;
0664       char err_msg[TFTP_MAX_ERROR_STRLEN];
0665     } error;
0666     struct {
0667       size_t len;
0668       uint8_t bytes[0];
0669     } raw;
0670   } content;
0671 } interaction_data_recvfrom;
0672 
0673 static bool interact_recvfrom_common(
0674   Tftp_Action *act,
0675   void *data,
0676   size_t actual_size
0677 )
0678 {
0679   interaction_data_recvfrom *d = data;
0680 
0681   T_eq_int( act->data.recvfrom.fd, d->fd );
0682   T_quiet_ge_sz( act->data.recvfrom.len, actual_size );
0683   if (
0684     act->data.recvfrom.fd != d->fd ||
0685     act->data.recvfrom.len < actual_size
0686   ) {
0687     return false;
0688   }
0689   if ( d->timeout_ms == DO_NOT_WAIT_FOR_ANY_TIMEOUT ) {
0690     T_ne_int( act->data.recvfrom.flags, 0 );
0691     if ( act->data.recvfrom.flags == 0 ) {
0692       return false;
0693     }
0694   } else {
0695     T_eq_int( act->data.recvfrom.flags, 0 );
0696     T_eq_u32( act->data.recvfrom.timeout_ms, d->timeout_ms );
0697     if (
0698       act->data.recvfrom.flags != 0 ||
0699       act->data.recvfrom.timeout_ms != d->timeout_ms
0700     ) {
0701       return false;
0702     }
0703   }
0704 
0705   strncpy(
0706     act->data.recvfrom.src_addr_str,
0707     d->src_addr_str,
0708     sizeof( act->data.recvfrom.src_addr_str )
0709   );
0710   act->data.recvfrom.src_addr_str[
0711     sizeof( act->data.recvfrom.src_addr_str ) - 1] = '\0';
0712   act->data.recvfrom.src_port = d->src_port;
0713   act->data.recvfrom.result = d->result ? actual_size : -1;
0714   return true;
0715 }
0716 
0717 static bool interact_recvfrom_data( Tftp_Action *act, void *data )
0718 {
0719   interaction_data_recvfrom *d = data;
0720   Tftp_Packet *pkt = act->data.recvfrom.buf;
0721   size_t actual_size;
0722   size_t i;
0723 
0724   actual_size = sizeof( pkt->opcode ) +
0725     sizeof( pkt->content.data.block_num ) + d->content.data.len;
0726   if ( !interact_recvfrom_common( act, data, actual_size ) ) {
0727     return false;
0728   }
0729 
0730   pkt->opcode = htons( TFTP_OPCODE_DATA );
0731   pkt->content.data.block_num = htons( d->content.data.block_num );
0732   for ( i = 0; i < d->content.data.len; ++i ) {
0733     pkt->content.data.bytes[i] =
0734       d->content.data.get_data( d->content.data.start + i );
0735   }
0736 
0737   return true;
0738 }
0739 
0740 static bool interact_recvfrom_ack( Tftp_Action *act, void *data )
0741 {
0742   interaction_data_recvfrom *d = data;
0743   Tftp_Packet *pkt = act->data.recvfrom.buf;
0744   size_t actual_size;
0745 
0746   actual_size = sizeof( pkt->opcode ) + sizeof( pkt->content.ack.block_num );
0747   if ( !interact_recvfrom_common( act, data, actual_size ) ) {
0748     return false;
0749   }
0750 
0751   pkt->opcode = htons( TFTP_OPCODE_ACK );
0752   pkt->content.ack.block_num = htons( d->content.ack.block_num );
0753 
0754   return true;
0755 }
0756 
0757 static bool interact_recvfrom_oack( Tftp_Action *act, void *data )
0758 {
0759   interaction_data_recvfrom *d = data;
0760   Tftp_Packet *pkt = act->data.recvfrom.buf;
0761   size_t actual_size;
0762 
0763   actual_size = sizeof( pkt->opcode ) + d->content.oack.options_size;
0764   if ( !interact_recvfrom_common( act, data, actual_size ) ) {
0765     return false;
0766   }
0767 
0768   pkt->opcode = htons( TFTP_OPCODE_OACK );
0769   memcpy(
0770     pkt->content.oack.opts,
0771     d->content.oack.options,
0772     d->content.oack.options_size
0773   );
0774 
0775   return true;
0776 }
0777 
0778 static bool interact_recvfrom_error( Tftp_Action *act, void *data )
0779 {
0780   interaction_data_recvfrom *d = data;
0781   Tftp_Packet *pkt = act->data.recvfrom.buf;
0782   size_t actual_size;
0783 
0784   actual_size = sizeof( pkt->opcode ) +
0785     sizeof( pkt->content.error.error_code ) +
0786     strlen( d->content.error.err_msg ) + 1;
0787   if ( !interact_recvfrom_common( act, data, actual_size ) ) {
0788     return false;
0789   }
0790 
0791   pkt->opcode = htons( TFTP_OPCODE_ERROR );
0792   pkt->content.error.error_code = htons( d->content.error.error_code );
0793   strncpy(
0794     pkt->content.error.err_msg,
0795     d->content.error.err_msg,
0796     act->data.recvfrom.len - sizeof( pkt->opcode ) -
0797       sizeof( pkt->content.error.error_code ) - 1
0798   );
0799 
0800   return true;
0801 }
0802 
0803 static bool interact_recvfrom_raw( Tftp_Action *act, void *data )
0804 {
0805   interaction_data_recvfrom *d = data;
0806   uint8_t *pkt = act->data.recvfrom.buf;
0807   size_t actual_size = d->content.raw.len;
0808 
0809   if ( !interact_recvfrom_common( act, data, actual_size ) ) {
0810     return false;
0811   }
0812 
0813   memcpy( pkt, d->content.raw.bytes, actual_size );
0814 
0815   return true;
0816 }
0817 
0818 void _Tftp_Add_interaction_recv_data(
0819   int fd,
0820   uint32_t timeout_ms,
0821   uint16_t src_port,
0822   const char *src_addr_str,
0823   uint16_t block_num,
0824   size_t start,
0825   size_t len,
0826   uint8_t (*get_data)( size_t pos ),
0827   bool result
0828 )
0829 {
0830   interaction_data_recvfrom *d;
0831 
0832   d = _Tftp_Append_interaction(
0833     TFTP_IA_KIND_RECVFROM,
0834     interact_recvfrom_data,
0835     sizeof( interaction_data_recvfrom )
0836   );
0837 
0838   T_assert_lt_sz( strlen( src_addr_str ), sizeof( d->src_addr_str ) - 1 );
0839   strcpy( d->src_addr_str, src_addr_str );
0840   d->fd                     = fd;
0841   d->timeout_ms             = timeout_ms;
0842   d->src_port               = src_port;
0843   d->content.data.block_num = block_num;
0844   d->content.data.start     = start;
0845   d->content.data.len       = len;
0846   d->content.data.get_data  = get_data;
0847   d->result                 = result;
0848 }
0849 
0850 void _Tftp_Add_interaction_recv_ack(
0851   int fd,
0852   uint32_t timeout_ms,
0853   uint16_t src_port,
0854   const char *src_addr_str,
0855   uint16_t block_num,
0856   bool result
0857 )
0858 {
0859   interaction_data_recvfrom *d;
0860 
0861   d = _Tftp_Append_interaction(
0862     TFTP_IA_KIND_RECVFROM,
0863     interact_recvfrom_ack,
0864     sizeof( interaction_data_recvfrom )
0865   );
0866 
0867   T_assert_lt_sz( strlen( src_addr_str ), sizeof( d->src_addr_str ) - 1 );
0868   strcpy( d->src_addr_str, src_addr_str );
0869   d->fd                     = fd;
0870   d->timeout_ms             = timeout_ms;
0871   d->src_port               = src_port;
0872   d->content.ack.block_num  = block_num;
0873   d->result                 = result;
0874 }
0875 
0876 void _Tftp_Add_interaction_recv_oack(
0877   int fd,
0878   uint32_t timeout_ms,
0879   uint16_t src_port,
0880   const char *src_addr_str,
0881   const char *options,
0882   size_t options_size,
0883   bool result
0884 )
0885 {
0886   interaction_data_recvfrom *d;
0887 
0888   d = _Tftp_Append_interaction(
0889     TFTP_IA_KIND_RECVFROM,
0890     interact_recvfrom_oack,
0891     sizeof( interaction_data_recvfrom )
0892   );
0893 
0894   T_assert_lt_sz( strlen( src_addr_str ), sizeof( d->src_addr_str ) - 1 );
0895   strcpy( d->src_addr_str, src_addr_str );
0896   T_assert_lt_sz( options_size, sizeof( d->content.oack.options ) );
0897   memcpy( d->content.oack.options, options, options_size );
0898   d->fd                        = fd;
0899   d->timeout_ms                = timeout_ms;
0900   d->src_port                  = src_port;
0901   d->content.oack.options_size = options_size;
0902   d->result                    = result;
0903 }
0904 
0905 void _Tftp_Add_interaction_recv_error(
0906   int fd,
0907   uint32_t timeout_ms,
0908   uint16_t src_port,
0909   const char *src_addr_str,
0910   uint16_t error_code,
0911   const char *err_msg,
0912   bool result
0913 )
0914 {
0915   interaction_data_recvfrom *d;
0916 
0917   d = _Tftp_Append_interaction(
0918     TFTP_IA_KIND_RECVFROM,
0919     interact_recvfrom_error,
0920     sizeof( interaction_data_recvfrom )
0921   );
0922 
0923   T_assert_lt_sz( strlen( src_addr_str ), sizeof( d->src_addr_str ) - 1 );
0924   strcpy( d->src_addr_str, src_addr_str );
0925   T_assert_lt_sz( strlen( src_addr_str ), sizeof( d->src_addr_str ) - 1 );
0926   strcpy( d->content.error.err_msg, err_msg );
0927   d->fd                       = fd;
0928   d->timeout_ms               = timeout_ms;
0929   d->src_port                 = src_port;
0930   d->content.error.error_code = error_code;
0931   d->result                   = result;
0932 }
0933 
0934 void _Tftp_Add_interaction_recv_raw(
0935   int fd,
0936   uint32_t timeout_ms,
0937   uint16_t src_port,
0938   const char *src_addr_str,
0939   size_t len,
0940   const uint8_t *bytes,
0941   bool result
0942 )
0943 {
0944   interaction_data_recvfrom *d;
0945 
0946   d = _Tftp_Append_interaction(
0947     TFTP_IA_KIND_RECVFROM,
0948     interact_recvfrom_raw,
0949     sizeof( interaction_data_recvfrom ) + len
0950   );
0951 
0952   T_assert_lt_sz( strlen( src_addr_str ), sizeof( d->src_addr_str ) - 1 );
0953   strcpy( d->src_addr_str, src_addr_str );
0954   memcpy( d->content.raw.bytes, bytes, len );
0955   d->fd              = fd;
0956   d->timeout_ms      = timeout_ms;
0957   d->src_port        = src_port;
0958   d->content.raw.len = len;
0959   d->result          = result;
0960 }
0961 
0962 void _Tftp_Add_interaction_recv_nothing(
0963   int fd,
0964   uint32_t timeout_ms
0965 )
0966 {
0967   static const char *dummy_ip = "0.0.0.0";
0968   interaction_data_recvfrom *d;
0969 
0970   d = _Tftp_Append_interaction(
0971     TFTP_IA_KIND_RECVFROM,
0972     interact_recvfrom_ack,
0973     sizeof( interaction_data_recvfrom )
0974   );
0975 
0976 
0977   T_assert_lt_sz( strlen( dummy_ip ), sizeof( d->src_addr_str ) - 1 );
0978   strcpy( d->src_addr_str, dummy_ip );
0979   d->fd                     = fd;
0980   d->timeout_ms             = timeout_ms;
0981   d->src_port               = 0;
0982   d->content.ack.block_num  = 0;
0983   d->result                 = false;
0984 }