// SPDX-License-Identifier: BSD-3-Clause OR Apache-2.0 #include "aap2/aap2_client.h" #include #include #include // Default timeout: infinite #define AAP2_CLIENT_TIMEOUT_MS 0 // Keepalives do not hurt, so we enable them and set the period to 60 seconds. #define AAP2_KEEPALIVE_TIMEOUT_S 60 static void usage(void) { const char *usage_text = ( "Usage: aap2recvfile
[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 < 5 || strlen(argv[1]) != 2 || argv[1][0] != '-' || strlen(argv[2]) < 1 || strlen(argv[3]) < 1 || strlen(argv[4]) < 1 || (argc == 6 && strlen(argv[5]) < 1) || argc > 6) { usage(); exit(EXIT_FAILURE); } struct aap2_client *client; char *agentid, *filename; // Parse cmdline args and connect based on socket type. if (argv[1][1] == 'p' && argc == 5) { client = aap2_client_open_socket(argv[2], AAP2_CLIENT_TIMEOUT_MS); agentid = argv[3]; filename = argv[4]; } else if (argv[1][1] == 't' && argc == 6) { client = aap2_client_open_tcp(argv[2], argv[3], AAP2_CLIENT_TIMEOUT_MS); agentid = argv[4]; filename = argv[5]; } 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 = true, // we only want to receive .keepalive_timeout_s = AAP2_KEEPALIVE_TIMEOUT_S, }; 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); enum aap2_client_error rv; struct aap2_client_bundle_spec out_spec; uint8_t *out_payload; size_t out_payload_length; // Invoke aap2_client_recv until we got exactly one bundle or an error. do { rv = aap2_client_recv( client, &out_spec, &out_payload, &out_payload_length, AAP2_CLIENT_TIMEOUT_MS ); } while (rv == AAP2_CLIENT_EAGAIN); // EAGAIN = Keepalive was received and ACKed if (rv != AAP2_CLIENT_OK) { aap2_client_close(client); fprintf(stderr, "Reception of ADU failed with status = %d!\n", rv); exit(EXIT_FAILURE); } fprintf(stderr, "Received ADU from \"%s\"\n", out_spec.source_eid); // Write the received payload to a file. FILE *const fp = fopen(filename, "wb"); if (!fp) { perror("fopen()"); aap2_client_free_bundle_spec_fields(&out_spec); free(out_payload); exit(EXIT_FAILURE); } if (fwrite(out_payload, out_payload_length, 1, fp) != 1 && out_payload_length) { perror("fwrite()"); aap2_client_free_bundle_spec_fields(&out_spec); free(out_payload); fclose(fp); exit(EXIT_FAILURE); } aap2_client_free_bundle_spec_fields(&out_spec); free(out_payload); fclose(fp); exit(EXIT_SUCCESS); }