// SPDX-License-Identifier: BSD-3-Clause OR Apache-2.0 #define _POSIX_C_SOURCE 200809L #include "aap2/aap2_client.h" #include #include #include #include #include #include #include // Default timeout: infinite #define AAP2_CLIENT_TIMEOUT_MS 0 static void usage(void) { const char *usage_text = ( "Usage: aap2sendfile
[port] \n\n" " may be one of the following:\n" " -p - use a POSIX IPC connection (address is a path to an IPC socket)\n" " -t - use a TCP connection (address is an combination)\n" ); fprintf(stderr, "%s", usage_text); } int main(const int argc, char *argv[]) { if (argc >= 2 && strcmp(argv[1], "-h") == 0) { usage(); exit(EXIT_SUCCESS); } // Quick sanity check. if (argc < 6 || strlen(argv[1]) != 2 || argv[1][0] != '-' || strlen(argv[2]) < 1 || strlen(argv[3]) < 1 || strlen(argv[4]) < 1 || strlen(argv[5]) < 1 || (argc == 7 && strlen(argv[6]) < 1) || argc > 7) { usage(); exit(EXIT_FAILURE); } struct aap2_client *client; char *agentid, *dest_eid, *filename; // Parse cmdline args and connect based on socket type. if (argv[1][1] == 'p' && argc == 6) { client = aap2_client_open_socket(argv[2], AAP2_CLIENT_TIMEOUT_MS); agentid = argv[3]; dest_eid = argv[4]; filename = argv[5]; } else if (argv[1][1] == 't' && argc == 7) { client = aap2_client_open_tcp(argv[2], argv[3], AAP2_CLIENT_TIMEOUT_MS); agentid = argv[4]; dest_eid = argv[5]; filename = argv[6]; } else { fprintf(stderr, "Invalid or TCP port not specified!\n"); usage(); exit(EXIT_FAILURE); } if (!client) { fprintf(stderr, "Failed to connect to provided address!\n"); exit(EXIT_FAILURE); } char *const src_eid = aap2_client_get_eid_for_agent( aap2_client_get_node_id(client), agentid ); if (!src_eid) { fprintf(stderr, "Cannot determine source EID (invalid agent ID provided?)\n"); exit(EXIT_FAILURE); } struct aap2_client_spec client_spec = { .eid = src_eid, .secret = NULL, // not supported a.t.m., but not needed for unused agentids .is_subscriber = false, // we only want to send .keepalive_timeout_s = 0, // not needed, we directly terminate when done }; if (aap2_client_register(client, client_spec, AAP2_CLIENT_TIMEOUT_MS) != AAP2_CLIENT_OK) { free(src_eid); aap2_client_close(client); fprintf(stderr, "Registration failed!\n"); exit(EXIT_FAILURE); } free(src_eid); // Read payload to be sent from file (mmap it). const int fd = open(filename, O_RDONLY); struct stat st; if (fd < 0) { perror("open"); exit(EXIT_FAILURE); } if (fstat(fd, &st) != 0) { perror("fstat"); close(fd); aap2_client_close(client); exit(EXIT_FAILURE); } if (!S_ISREG(st.st_mode)) { fprintf(stderr, "Not a regular file!\n"); close(fd); aap2_client_close(client); exit(EXIT_FAILURE); } // Get size and mmap() the file contents. const size_t fsize = (size_t)st.st_size; uint8_t *payload; if (fsize == 0) { fprintf(stderr, "File length is zero, using zero-length payload.\n"); close(fd); payload = (uint8_t *)&fsize; // just some random pointer to 0 (will not be read) } else { fprintf(stderr, "Mapping ADU payload of size %ld byte(s) to memory...\n", fsize); payload = (uint8_t *)mmap(NULL, fsize, PROT_READ, MAP_PRIVATE, fd, 0); close(fd); if (payload == MAP_FAILED) { perror("mmap"); aap2_client_close(client); exit(EXIT_FAILURE); } } // Send the bundle via AAP2. struct aap2_client_bundle_spec bundle_spec = { .source_eid = NULL, // automatically assigned .dest_eid = dest_eid, .report_to_eid = NULL, // unset .creation_timestamp_dtn_ms = 0, // automatically assigned .sequence_number = 0, // automatically assigned .flags = (struct aap2_bundle_adu_flags){false, false, false}, }; bool success; if (aap2_client_send(client, bundle_spec, payload, fsize, AAP2_CLIENT_TIMEOUT_MS, NULL) != AAP2_CLIENT_OK) { success = false; goto cleanup; } success = true; cleanup: aap2_client_close(client); if (fsize != 0 && munmap(payload, fsize) != 0) { perror("munmap"); exit(EXIT_FAILURE); } if (!success) { fprintf(stderr, "Sending failed!\n"); exit(EXIT_FAILURE); } fprintf(stderr, "Sent!\n"); exit(EXIT_SUCCESS); }