From 7e3491f6c716e4d5a9d904c7b7fa2c19a78833fe Mon Sep 17 00:00:00 2001 From: Artem Prilutskiy Date: Wed, 7 Jun 2017 12:26:19 +0300 Subject: [PATCH] Added wait option --- DigestPlay.c | 33 ++++++++++++++++++++-- Rewind.h | 9 ++++++ RewindClient.c | 77 ++++++++++++++++++++++++++++++++++++++++---------- RewindClient.h | 6 ++++ Version.h | 2 +- 5 files changed, 109 insertions(+), 18 deletions(-) diff --git a/DigestPlay.c b/DigestPlay.c index 21b9ef8..7150948 100644 --- a/DigestPlay.c +++ b/DigestPlay.c @@ -24,7 +24,7 @@ #define COUNT(array) sizeof(array) / sizeof(array[0]) -#define BUFFER_SIZE 64 +#define BUFFER_SIZE 128 #define CLIENT_NAME "DigestPlay " STRING(VERSION) " " BUILD int main(int argc, char* argv[]) @@ -47,6 +47,9 @@ int main(int argc, char* argv[]) struct RewindSuperHeader header; memset(&header, 0, sizeof(struct RewindSuperHeader)); + time_t waiting = 0; + struct RewindSessionPollData poll; + // Start up struct option options[] = @@ -58,6 +61,7 @@ int main(int argc, char* argv[]) { "source-id", required_argument, NULL, 'u' }, { "group-id", required_argument, NULL, 'g' }, { "talker-alias", required_argument, NULL, 't' }, + { "wait", required_argument, NULL, 'o' }, { "linear", no_argument, NULL, 'l' }, { "mode33", no_argument, NULL, 'm' }, { NULL, 0, NULL, 0 } @@ -67,7 +71,7 @@ int main(int argc, char* argv[]) int control = 0; int selection = 0; - while ((selection = getopt_long(argc, argv, "w:c:s:p:u:g:t:lm", options, NULL)) != EOF) + while ((selection = getopt_long(argc, argv, "w:c:s:p:u:g:t:o:lm", options, NULL)) != EOF) switch (selection) { case 'w': @@ -103,6 +107,7 @@ int main(int argc, char* argv[]) if (value > 0) { header.destinationID = htole32(value); + poll.number = header.destinationID; control |= 0b10000; } break; @@ -111,6 +116,10 @@ int main(int argc, char* argv[]) strncpy(header.sourceCall, optarg, REWIND_CALL_LENGTH); break; + case 'o': + waiting = strtol(optarg, NULL, 10); + break; + case 'l': size = LINEAR_FRAME_SIZE; break; @@ -134,6 +143,7 @@ int main(int argc, char* argv[]) " --talker-alias \n" " --linear (use AMBE linear format instead of DSD)\n" " --mode33 (use AMBE mode 33 format instead of DSD)\n" + " --wait \n" "\n", argv[0]); return EXIT_FAILURE; @@ -175,6 +185,25 @@ int main(int argc, char* argv[]) return EXIT_FAILURE; } + // Wait for the end of existing call session if required + + if (waiting > 0) + { + poll.type = htole32(TREE_SESSION_BY_TARGET); + poll.flag = htole32(SESSION_TYPE_FLAG_GROUP); + + result = WaitForRewindSessionEnd(context, &poll, waiting); + + if (result != CLIENT_ERROR_SUCCESS) + { + printf("Waiting limit exceeded (%i)\n", result); + TransmitRewindCloae(context); + + ReleaseRewindContext(context); + return EXIT_FAILURE; + } + } + // Initialize timer handle int handle; diff --git a/Rewind.h b/Rewind.h index 451fe9c..00e82f4 100644 --- a/Rewind.h +++ b/Rewind.h @@ -47,6 +47,7 @@ extern "C" #define REWIND_TYPE_CONFIGURATION (REWIND_CLASS_APPLICATION + 0x00) #define REWIND_TYPE_SUBSCRIPTION (REWIND_CLASS_APPLICATION + 0x01) #define REWIND_TYPE_CANCELLING (REWIND_CLASS_APPLICATION + 0x02) +#define REWIND_TYPE_SESSION_POLL (REWIND_CLASS_APPLICATION + 0x03) #define REWIND_TYPE_DMR_DATA_BASE (REWIND_CLASS_APPLICATION + 0x10) #define REWIND_TYPE_DMR_AUDIO_FRAME (REWIND_CLASS_APPLICATION + 0x20) #define REWIND_TYPE_DMR_EMBEDDED_DATA (REWIND_CLASS_APPLICATION + 0x27) @@ -103,6 +104,14 @@ struct RewindSubscriptionData uint32_t number; // Destination ID }; +struct RewindSessionPollData +{ + uint32_t type; // TREE_SESSION_* + uint32_t flag; // SESSION_FLAG_* + uint32_t number; // ID + uint32_t state; // +}; + struct RewindSuperHeader { uint32_t type; // SESSION_TYPE_* diff --git a/RewindClient.c b/RewindClient.c index 84d852a..1af3c79 100644 --- a/RewindClient.c +++ b/RewindClient.c @@ -52,9 +52,9 @@ #define BUFFER_SIZE 256 -#define CONNECTION_ATTEMPT_COUNT 5 -#define CONNECTION_RECEIVE_TIMEOUT 2 -#define CONNECTION_CONNECT_TIMEOUT 5 +#define ATTEMPT_COUNT 3 +#define RECEIVE_TIMEOUT 2 +#define CONNECT_TIMEOUT 5 static int CompareAddresses(struct sockaddr* value1, struct sockaddr_in6* value2) { @@ -91,12 +91,12 @@ struct RewindContext* CreateRewindContext(uint32_t number, const char* verion) { // Create socket - address.sin6_family = AF_INET6; - address.sin6_addr = in6addr_any; - address.sin6_port = 0; + address.sin6_family = AF_INET6; + address.sin6_addr = in6addr_any; + address.sin6_port = 0; address.sin6_scope_id = 0; - interval.tv_sec = 2; + interval.tv_sec = RECEIVE_TIMEOUT; interval.tv_usec = 0; context->handle = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); @@ -207,7 +207,7 @@ int ConnectRewindClient(struct RewindContext* context, const char* location, con ssize_t length; size_t attempt = 0; - time_t threshold = time(NULL) + CONNECTION_CONNECT_TIMEOUT; + time_t threshold = time(NULL) + CONNECT_TIMEOUT; uint8_t* digest = (uint8_t*)alloca(SHA256_DIGEST_LENGTH); @@ -233,10 +233,7 @@ int ConnectRewindClient(struct RewindContext* context, const char* location, con #endif if (getaddrinfo(location, port, &hints, &context->address) != 0) - { - // Could not resolve address return CLIENT_ERROR_DNS_RESOLVE; - } // Do login procedure @@ -257,14 +254,12 @@ int ConnectRewindClient(struct RewindContext* context, const char* location, con switch (le16toh(buffer->type)) { case REWIND_TYPE_CHALLENGE: - if (attempt < CONNECTION_ATTEMPT_COUNT) + if (attempt < ATTEMPT_COUNT) { length -= sizeof(struct RewindData); length += sprintf(buffer->data + length, "%s", password); SHA256(buffer->data, length, digest); - TransmitRewindData(context, REWIND_TYPE_AUTHENTICATION, REWIND_FLAG_NONE, digest, SHA256_DIGEST_LENGTH); - attempt ++; continue; } @@ -274,7 +269,6 @@ int ConnectRewindClient(struct RewindContext* context, const char* location, con if (options != 0) { data.options = htole32(options); - TransmitRewindData(context, REWIND_TYPE_CONFIGURATION, REWIND_FLAG_NONE, &data, sizeof(struct RewindConfigurationData)); continue; } @@ -286,3 +280,56 @@ int ConnectRewindClient(struct RewindContext* context, const char* location, con return CLIENT_ERROR_RESPONSE_TIMEOUT; } + +int WaitForRewindSessionEnd(struct RewindContext* context, struct RewindSessionPollData* request, time_t interval) +{ + struct RewindData* buffer = (struct RewindData*)alloca(BUFFER_SIZE); + struct RewindSessionPollData* response = (struct RewindSessionPollData*)buffer->data; + ssize_t length; + + uint32_t control = 0; + + interval += time(NULL); + while (interval > time(NULL)) + { + TransmitRewindData(context, REWIND_TYPE_KEEP_ALIVE, REWIND_FLAG_NONE, context->data, context->length); + TransmitRewindData(context, REWIND_TYPE_SESSION_POLL, REWIND_FLAG_NONE, request, sizeof(struct RewindSessionPollData)); + + length = ReceiveRewindData(context, buffer, BUFFER_SIZE); + + if ((length == CLIENT_ERROR_WRONG_ADDRESS) || + (length == CLIENT_ERROR_SOCKET_IO) && + ((errno == EWOULDBLOCK) || + (errno == EAGAIN))) + continue; + + if (length < 0) + return length; + + switch (le16toh(buffer->type)) + { + case REWIND_TYPE_KEEP_ALIVE: + control |= 0b01; + break; + + case REWIND_TYPE_SESSION_POLL: + if (response->state == 0) + { + // No active sessions + return CLIENT_ERROR_SUCCESS; + } + control |= 0b10; + break; + } + + if (control == 0b11) + { + // Got REWIND_TYPE_KEEP_ALIVE and REWIND_TYPE_SESSION_POLL + // Wait for 2 seconds before the next attempt + sleep(RECEIVE_TIMEOUT); + control = 0b00; + } + } + + return CLIENT_ERROR_RESPONSE_TIMEOUT; +} diff --git a/RewindClient.h b/RewindClient.h index 887599d..d29bb6f 100644 --- a/RewindClient.h +++ b/RewindClient.h @@ -15,9 +15,14 @@ extern "C" { #endif +#define SESSION_TYPE_FLAG_GROUP (1 << 1) + #define SESSION_TYPE_PRIVATE_VOICE 5 #define SESSION_TYPE_GROUP_VOICE 7 +#define TREE_SESSION_BY_SOURCE 8 +#define TREE_SESSION_BY_TARGET 9 + #define CLIENT_ERROR_SUCCESS 0 #define CLIENT_ERROR_SOCKET_IO -1 #define CLIENT_ERROR_WRONG_ADDRESS -2 @@ -44,6 +49,7 @@ void TransmitRewindData(struct RewindContext* context, uint16_t type, uint16_t f ssize_t ReceiveRewindData(struct RewindContext* context, struct RewindData* buffer, ssize_t length); int ConnectRewindClient(struct RewindContext* context, const char* location, const char* port, const char* password, uint32_t options); +int WaitForRewindSessionEnd(struct RewindContext* context, struct RewindSessionPollData* request, time_t interval); #define TransmitRewindKeepAlive(context) TransmitRewindData(context, REWIND_TYPE_KEEP_ALIVE, REWIND_FLAG_NONE, context->data, context->length); #define TransmitRewindCloae(context) TransmitRewindData(context, REWIND_TYPE_CLOSE, REWIND_FLAG_NONE, NULL, 0 ); diff --git a/Version.h b/Version.h index 9e02822..69e1cd7 100644 --- a/Version.h +++ b/Version.h @@ -1 +1 @@ -#define VERSION 20170527 +#define VERSION 20170607