File indexing completed on 2025-05-11 08:24:31
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
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 );
0070 int __real_close( int fd );
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
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
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
0526
0527
0528
0529
0530
0531
0532
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
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
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
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
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,
0727 TFTP_KNOWN_IPV4_ADDR0_ARRAY
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
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
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
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
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 }