Added wait option
This commit is contained in:
parent
3329b3d35c
commit
7e3491f6c7
5 changed files with 109 additions and 18 deletions
33
DigestPlay.c
33
DigestPlay.c
|
@ -24,7 +24,7 @@
|
||||||
|
|
||||||
#define COUNT(array) sizeof(array) / sizeof(array[0])
|
#define COUNT(array) sizeof(array) / sizeof(array[0])
|
||||||
|
|
||||||
#define BUFFER_SIZE 64
|
#define BUFFER_SIZE 128
|
||||||
#define CLIENT_NAME "DigestPlay " STRING(VERSION) " " BUILD
|
#define CLIENT_NAME "DigestPlay " STRING(VERSION) " " BUILD
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
|
@ -47,6 +47,9 @@ int main(int argc, char* argv[])
|
||||||
struct RewindSuperHeader header;
|
struct RewindSuperHeader header;
|
||||||
memset(&header, 0, sizeof(struct RewindSuperHeader));
|
memset(&header, 0, sizeof(struct RewindSuperHeader));
|
||||||
|
|
||||||
|
time_t waiting = 0;
|
||||||
|
struct RewindSessionPollData poll;
|
||||||
|
|
||||||
// Start up
|
// Start up
|
||||||
|
|
||||||
struct option options[] =
|
struct option options[] =
|
||||||
|
@ -58,6 +61,7 @@ int main(int argc, char* argv[])
|
||||||
{ "source-id", required_argument, NULL, 'u' },
|
{ "source-id", required_argument, NULL, 'u' },
|
||||||
{ "group-id", required_argument, NULL, 'g' },
|
{ "group-id", required_argument, NULL, 'g' },
|
||||||
{ "talker-alias", required_argument, NULL, 't' },
|
{ "talker-alias", required_argument, NULL, 't' },
|
||||||
|
{ "wait", required_argument, NULL, 'o' },
|
||||||
{ "linear", no_argument, NULL, 'l' },
|
{ "linear", no_argument, NULL, 'l' },
|
||||||
{ "mode33", no_argument, NULL, 'm' },
|
{ "mode33", no_argument, NULL, 'm' },
|
||||||
{ NULL, 0, NULL, 0 }
|
{ NULL, 0, NULL, 0 }
|
||||||
|
@ -67,7 +71,7 @@ int main(int argc, char* argv[])
|
||||||
int control = 0;
|
int control = 0;
|
||||||
int selection = 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)
|
switch (selection)
|
||||||
{
|
{
|
||||||
case 'w':
|
case 'w':
|
||||||
|
@ -103,6 +107,7 @@ int main(int argc, char* argv[])
|
||||||
if (value > 0)
|
if (value > 0)
|
||||||
{
|
{
|
||||||
header.destinationID = htole32(value);
|
header.destinationID = htole32(value);
|
||||||
|
poll.number = header.destinationID;
|
||||||
control |= 0b10000;
|
control |= 0b10000;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -111,6 +116,10 @@ int main(int argc, char* argv[])
|
||||||
strncpy(header.sourceCall, optarg, REWIND_CALL_LENGTH);
|
strncpy(header.sourceCall, optarg, REWIND_CALL_LENGTH);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'o':
|
||||||
|
waiting = strtol(optarg, NULL, 10);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'l':
|
case 'l':
|
||||||
size = LINEAR_FRAME_SIZE;
|
size = LINEAR_FRAME_SIZE;
|
||||||
break;
|
break;
|
||||||
|
@ -134,6 +143,7 @@ int main(int argc, char* argv[])
|
||||||
" --talker-alias <text to send as Talker Alias>\n"
|
" --talker-alias <text to send as Talker Alias>\n"
|
||||||
" --linear (use AMBE linear format instead of DSD)\n"
|
" --linear (use AMBE linear format instead of DSD)\n"
|
||||||
" --mode33 (use AMBE mode 33 format instead of DSD)\n"
|
" --mode33 (use AMBE mode 33 format instead of DSD)\n"
|
||||||
|
" --wait <number of seconds>\n"
|
||||||
"\n",
|
"\n",
|
||||||
argv[0]);
|
argv[0]);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
@ -175,6 +185,25 @@ int main(int argc, char* argv[])
|
||||||
return EXIT_FAILURE;
|
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
|
// Initialize timer handle
|
||||||
|
|
||||||
int handle;
|
int handle;
|
||||||
|
|
9
Rewind.h
9
Rewind.h
|
@ -47,6 +47,7 @@ extern "C"
|
||||||
#define REWIND_TYPE_CONFIGURATION (REWIND_CLASS_APPLICATION + 0x00)
|
#define REWIND_TYPE_CONFIGURATION (REWIND_CLASS_APPLICATION + 0x00)
|
||||||
#define REWIND_TYPE_SUBSCRIPTION (REWIND_CLASS_APPLICATION + 0x01)
|
#define REWIND_TYPE_SUBSCRIPTION (REWIND_CLASS_APPLICATION + 0x01)
|
||||||
#define REWIND_TYPE_CANCELLING (REWIND_CLASS_APPLICATION + 0x02)
|
#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_DATA_BASE (REWIND_CLASS_APPLICATION + 0x10)
|
||||||
#define REWIND_TYPE_DMR_AUDIO_FRAME (REWIND_CLASS_APPLICATION + 0x20)
|
#define REWIND_TYPE_DMR_AUDIO_FRAME (REWIND_CLASS_APPLICATION + 0x20)
|
||||||
#define REWIND_TYPE_DMR_EMBEDDED_DATA (REWIND_CLASS_APPLICATION + 0x27)
|
#define REWIND_TYPE_DMR_EMBEDDED_DATA (REWIND_CLASS_APPLICATION + 0x27)
|
||||||
|
@ -103,6 +104,14 @@ struct RewindSubscriptionData
|
||||||
uint32_t number; // Destination ID
|
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
|
struct RewindSuperHeader
|
||||||
{
|
{
|
||||||
uint32_t type; // SESSION_TYPE_*
|
uint32_t type; // SESSION_TYPE_*
|
||||||
|
|
|
@ -52,9 +52,9 @@
|
||||||
|
|
||||||
#define BUFFER_SIZE 256
|
#define BUFFER_SIZE 256
|
||||||
|
|
||||||
#define CONNECTION_ATTEMPT_COUNT 5
|
#define ATTEMPT_COUNT 3
|
||||||
#define CONNECTION_RECEIVE_TIMEOUT 2
|
#define RECEIVE_TIMEOUT 2
|
||||||
#define CONNECTION_CONNECT_TIMEOUT 5
|
#define CONNECT_TIMEOUT 5
|
||||||
|
|
||||||
static int CompareAddresses(struct sockaddr* value1, struct sockaddr_in6* value2)
|
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
|
// Create socket
|
||||||
|
|
||||||
address.sin6_family = AF_INET6;
|
address.sin6_family = AF_INET6;
|
||||||
address.sin6_addr = in6addr_any;
|
address.sin6_addr = in6addr_any;
|
||||||
address.sin6_port = 0;
|
address.sin6_port = 0;
|
||||||
address.sin6_scope_id = 0;
|
address.sin6_scope_id = 0;
|
||||||
|
|
||||||
interval.tv_sec = 2;
|
interval.tv_sec = RECEIVE_TIMEOUT;
|
||||||
interval.tv_usec = 0;
|
interval.tv_usec = 0;
|
||||||
|
|
||||||
context->handle = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
|
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;
|
ssize_t length;
|
||||||
|
|
||||||
size_t attempt = 0;
|
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);
|
uint8_t* digest = (uint8_t*)alloca(SHA256_DIGEST_LENGTH);
|
||||||
|
|
||||||
|
@ -233,10 +233,7 @@ int ConnectRewindClient(struct RewindContext* context, const char* location, con
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (getaddrinfo(location, port, &hints, &context->address) != 0)
|
if (getaddrinfo(location, port, &hints, &context->address) != 0)
|
||||||
{
|
|
||||||
// Could not resolve address
|
|
||||||
return CLIENT_ERROR_DNS_RESOLVE;
|
return CLIENT_ERROR_DNS_RESOLVE;
|
||||||
}
|
|
||||||
|
|
||||||
// Do login procedure
|
// Do login procedure
|
||||||
|
|
||||||
|
@ -257,14 +254,12 @@ int ConnectRewindClient(struct RewindContext* context, const char* location, con
|
||||||
switch (le16toh(buffer->type))
|
switch (le16toh(buffer->type))
|
||||||
{
|
{
|
||||||
case REWIND_TYPE_CHALLENGE:
|
case REWIND_TYPE_CHALLENGE:
|
||||||
if (attempt < CONNECTION_ATTEMPT_COUNT)
|
if (attempt < ATTEMPT_COUNT)
|
||||||
{
|
{
|
||||||
length -= sizeof(struct RewindData);
|
length -= sizeof(struct RewindData);
|
||||||
length += sprintf(buffer->data + length, "%s", password);
|
length += sprintf(buffer->data + length, "%s", password);
|
||||||
SHA256(buffer->data, length, digest);
|
SHA256(buffer->data, length, digest);
|
||||||
|
|
||||||
TransmitRewindData(context, REWIND_TYPE_AUTHENTICATION, REWIND_FLAG_NONE, digest, SHA256_DIGEST_LENGTH);
|
TransmitRewindData(context, REWIND_TYPE_AUTHENTICATION, REWIND_FLAG_NONE, digest, SHA256_DIGEST_LENGTH);
|
||||||
|
|
||||||
attempt ++;
|
attempt ++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -274,7 +269,6 @@ int ConnectRewindClient(struct RewindContext* context, const char* location, con
|
||||||
if (options != 0)
|
if (options != 0)
|
||||||
{
|
{
|
||||||
data.options = htole32(options);
|
data.options = htole32(options);
|
||||||
|
|
||||||
TransmitRewindData(context, REWIND_TYPE_CONFIGURATION, REWIND_FLAG_NONE, &data, sizeof(struct RewindConfigurationData));
|
TransmitRewindData(context, REWIND_TYPE_CONFIGURATION, REWIND_FLAG_NONE, &data, sizeof(struct RewindConfigurationData));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -286,3 +280,56 @@ int ConnectRewindClient(struct RewindContext* context, const char* location, con
|
||||||
|
|
||||||
return CLIENT_ERROR_RESPONSE_TIMEOUT;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -15,9 +15,14 @@ extern "C"
|
||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define SESSION_TYPE_FLAG_GROUP (1 << 1)
|
||||||
|
|
||||||
#define SESSION_TYPE_PRIVATE_VOICE 5
|
#define SESSION_TYPE_PRIVATE_VOICE 5
|
||||||
#define SESSION_TYPE_GROUP_VOICE 7
|
#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_SUCCESS 0
|
||||||
#define CLIENT_ERROR_SOCKET_IO -1
|
#define CLIENT_ERROR_SOCKET_IO -1
|
||||||
#define CLIENT_ERROR_WRONG_ADDRESS -2
|
#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);
|
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 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 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 );
|
#define TransmitRewindCloae(context) TransmitRewindData(context, REWIND_TYPE_CLOSE, REWIND_FLAG_NONE, NULL, 0 );
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
#define VERSION 20170527
|
#define VERSION 20170607
|
||||||
|
|
Loading…
Add table
Reference in a new issue