mirror of https://github.com/wb2osz/direwolf.git
Issue 169 - Fix AGW protocol 'Y' command.
This commit is contained in:
parent
e1a4716857
commit
41a85d87a7
75
ax25_link.c
75
ax25_link.c
|
@ -887,6 +887,7 @@ static ax25_dlsm_t *get_link_handle (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LE
|
||||||
//
|
//
|
||||||
// dl_connect_request
|
// dl_connect_request
|
||||||
// dl_disconnect_request
|
// dl_disconnect_request
|
||||||
|
// dl_outstanding_frames_request - (mine) Ask about outgoing queue for a link.
|
||||||
// dl_data_request - send connected data
|
// dl_data_request - send connected data
|
||||||
// dl_unit_data_request - not implemented. APRS & KISS bypass this
|
// dl_unit_data_request - not implemented. APRS & KISS bypass this
|
||||||
// dl_flow_off - not implemented. Not in AGW API.
|
// dl_flow_off - not implemented. Not in AGW API.
|
||||||
|
@ -1505,6 +1506,80 @@ void dl_unregister_callsign (dlq_item_t *E)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Name: dl_outstanding_frames_request
|
||||||
|
*
|
||||||
|
* Purpose: Client app wants to know how many frames are still on their way
|
||||||
|
* to other station. This is handy for flow control. We would like
|
||||||
|
* to keep the pipeline filled sufficiently to take advantage of a
|
||||||
|
* large window size (MAXFRAMES). It is also good to know that the
|
||||||
|
* the last packet sent was actually received before we commence
|
||||||
|
* the disconnect.
|
||||||
|
*
|
||||||
|
* Inputs: E - Event from the queue.
|
||||||
|
* The caller will free it.
|
||||||
|
*
|
||||||
|
* Outputs: This gets back to the AGW server which sends the 'Y' reply.
|
||||||
|
*
|
||||||
|
* Description: This is the sum of:
|
||||||
|
* - Incoming connected data, from application still in the queue.
|
||||||
|
* - I frames which have been transmitted but not yet acknowleged.
|
||||||
|
*
|
||||||
|
*------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
void dl_outstanding_frames_request (dlq_item_t *E)
|
||||||
|
{
|
||||||
|
ax25_dlsm_t *S;
|
||||||
|
int ok_to_create = 0; // must exist already.
|
||||||
|
|
||||||
|
|
||||||
|
if (s_debug_client_app) {
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf ("dl_outstanding_frames_request ( to %s )\n", E->addrs[PEERCALL]);
|
||||||
|
}
|
||||||
|
|
||||||
|
S = get_link_handle (E->addrs, E->num_addr, E->chan, E->client, ok_to_create);
|
||||||
|
|
||||||
|
if (S == NULL) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Can't get outstanding frames for %s -> %s, chan %d\n", E->addrs[OWNCALL], E->addrs[PEERCALL], E->chan);
|
||||||
|
server_outstanding_frames_reply (E->chan, E->client, E->addrs[OWNCALL], E->addrs[PEERCALL], 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add up these
|
||||||
|
//
|
||||||
|
// cdata_t *i_frame_queue; // Connected data from client which has not been transmitted yet.
|
||||||
|
// // Linked list.
|
||||||
|
// // The name is misleading because these are just blocks of
|
||||||
|
// // data, not "I frames" at this point. The name comes from
|
||||||
|
// // the protocol specification.
|
||||||
|
//
|
||||||
|
// cdata_t *txdata_by_ns[128]; // Data which has already been transmitted.
|
||||||
|
// // Indexed by N(S) in case it gets lost and needs to be sent again.
|
||||||
|
// // Cleared out when we get ACK for it.
|
||||||
|
|
||||||
|
int count1 = 0;
|
||||||
|
cdata_t *incoming;
|
||||||
|
for (incoming = S->i_frame_queue; incoming != NULL; incoming = incoming->next) {
|
||||||
|
count1++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int count2 = 0;
|
||||||
|
int k;
|
||||||
|
for (k = 0; k < S->modulo; k++) {
|
||||||
|
if (S->txdata_by_ns[k] != NULL) {
|
||||||
|
count2++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
server_outstanding_frames_reply (S->chan, S->client, S->addrs[OWNCALL], S->addrs[PEERCALL], count1 + count2);
|
||||||
|
|
||||||
|
} // end dl_outstanding_frames_request
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------------
|
/*------------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* Name: dl_client_cleanup
|
* Name: dl_client_cleanup
|
||||||
|
|
66
dlq.c
66
dlq.c
|
@ -1,7 +1,7 @@
|
||||||
//
|
//
|
||||||
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2014, 2015, 2016 John Langner, WB2OSZ
|
// Copyright (C) 2014, 2015, 2016, 2018 John Langner, WB2OSZ
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -553,7 +553,69 @@ void dlq_disconnect_request (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int
|
||||||
|
|
||||||
append_to_queue (pnew);
|
append_to_queue (pnew);
|
||||||
|
|
||||||
} /* end dlq_connect_request */
|
} /* end dlq_disconnect_request */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Name: dlq_outstanding_frames_request
|
||||||
|
*
|
||||||
|
* Purpose: Client application wants to know number of outstanding information
|
||||||
|
* frames supplied, supplied by the client, that have not yet been
|
||||||
|
* delivered to the remote station.
|
||||||
|
*
|
||||||
|
* Inputs: addrs - Source (owncall), destination (peercall)
|
||||||
|
*
|
||||||
|
* num_addr - Number of addresses. Should be 2.
|
||||||
|
* If more they will be ignored.
|
||||||
|
*
|
||||||
|
* chan - Channel, 0 is first.
|
||||||
|
*
|
||||||
|
* client - Client application instance. We could have multiple
|
||||||
|
* applications, all on the same channel, connecting
|
||||||
|
* to different stations. We need to know which one
|
||||||
|
* should get the results.
|
||||||
|
*
|
||||||
|
* Outputs: Request is appended to queue for processing by
|
||||||
|
* the data link state machine.
|
||||||
|
*
|
||||||
|
* Description: The data link state machine will count up all information frames
|
||||||
|
* for the given source(mycall) / destination(remote) / channel link.
|
||||||
|
* A 'Y' response will be sent back to the client application.
|
||||||
|
*
|
||||||
|
*--------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
void dlq_outstanding_frames_request (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, int chan, int client)
|
||||||
|
{
|
||||||
|
struct dlq_item_s *pnew;
|
||||||
|
#if DEBUG
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf ("dlq_outstanding_frames_request (...)\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
assert (chan >= 0 && chan < MAX_CHANS);
|
||||||
|
|
||||||
|
/* Allocate a new queue item. */
|
||||||
|
|
||||||
|
pnew = (struct dlq_item_s *) calloc (sizeof(struct dlq_item_s), 1);
|
||||||
|
s_new_count++;
|
||||||
|
|
||||||
|
pnew->type = DLQ_OUTSTANDING_FRAMES_REQUEST;
|
||||||
|
pnew->chan = chan;
|
||||||
|
memcpy (pnew->addrs, addrs, sizeof(pnew->addrs));
|
||||||
|
pnew->num_addr = num_addr;
|
||||||
|
pnew->client = client;
|
||||||
|
|
||||||
|
/* Put it into queue. */
|
||||||
|
|
||||||
|
append_to_queue (pnew);
|
||||||
|
|
||||||
|
} /* end dlq_outstanding_frames_request */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------
|
/*-------------------------------------------------------------------
|
||||||
|
|
4
dlq.h
4
dlq.h
|
@ -35,7 +35,7 @@ typedef struct cdata_s {
|
||||||
|
|
||||||
/* Types of things that can be in queue. */
|
/* Types of things that can be in queue. */
|
||||||
|
|
||||||
typedef enum dlq_type_e {DLQ_REC_FRAME, DLQ_CONNECT_REQUEST, DLQ_DISCONNECT_REQUEST, DLQ_XMIT_DATA_REQUEST, DLQ_REGISTER_CALLSIGN, DLQ_UNREGISTER_CALLSIGN, DLQ_CHANNEL_BUSY, DLQ_SEIZE_CONFIRM, DLQ_CLIENT_CLEANUP} dlq_type_t;
|
typedef enum dlq_type_e {DLQ_REC_FRAME, DLQ_CONNECT_REQUEST, DLQ_DISCONNECT_REQUEST, DLQ_XMIT_DATA_REQUEST, DLQ_REGISTER_CALLSIGN, DLQ_UNREGISTER_CALLSIGN, DLQ_OUTSTANDING_FRAMES_REQUEST, DLQ_CHANNEL_BUSY, DLQ_SEIZE_CONFIRM, DLQ_CLIENT_CLEANUP} dlq_type_t;
|
||||||
|
|
||||||
|
|
||||||
/* A queue item. */
|
/* A queue item. */
|
||||||
|
@ -108,6 +108,8 @@ void dlq_connect_request (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num
|
||||||
|
|
||||||
void dlq_disconnect_request (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, int chan, int client);
|
void dlq_disconnect_request (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, int chan, int client);
|
||||||
|
|
||||||
|
void dlq_outstanding_frames_request (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, int chan, int client);
|
||||||
|
|
||||||
void dlq_xmit_data_request (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, int chan, int client, int pid, char *xdata_ptr, int xdata_len);
|
void dlq_xmit_data_request (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, int chan, int client, int pid, char *xdata_ptr, int xdata_len);
|
||||||
|
|
||||||
void dlq_register_callsign (char addr[AX25_MAX_ADDR_LEN], int chan, int client);
|
void dlq_register_callsign (char addr[AX25_MAX_ADDR_LEN], int chan, int client);
|
||||||
|
|
117
server.c
117
server.c
|
@ -136,11 +136,7 @@
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#ifdef __OpenBSD__
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#else
|
|
||||||
#include <sys/errno.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
@ -1121,6 +1117,50 @@ void server_rec_conn_data (int chan, int client, char *remote_call, char *own_ca
|
||||||
} /* end server_rec_conn_data */
|
} /* end server_rec_conn_data */
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Name: server_outstanding_frames_reply
|
||||||
|
*
|
||||||
|
* Purpose: Send 'Y' Outstanding frames for connected data to the application.
|
||||||
|
*
|
||||||
|
* Inputs: chan - Which radio channel.
|
||||||
|
*
|
||||||
|
* client - Which one of potentially several clients.
|
||||||
|
*
|
||||||
|
* own_call - Callsign[-ssid] of my end.
|
||||||
|
*
|
||||||
|
* remote_call - Callsign[-ssid] of remote station.
|
||||||
|
*
|
||||||
|
* count - Number of frames sent from the application but
|
||||||
|
* not yet received by the other station.
|
||||||
|
*
|
||||||
|
*--------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
void server_outstanding_frames_reply (int chan, int client, char *own_call, char *remote_call, int count)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct agwpe_s hdr;
|
||||||
|
int count_NETLE;
|
||||||
|
} reply;
|
||||||
|
|
||||||
|
|
||||||
|
memset (&reply.hdr, 0, sizeof(reply.hdr));
|
||||||
|
|
||||||
|
reply.hdr.portx = chan;
|
||||||
|
reply.hdr.datakind = 'Y';
|
||||||
|
|
||||||
|
strlcpy (reply.hdr.call_from, own_call, sizeof(reply.hdr.call_from));
|
||||||
|
strlcpy (reply.hdr.call_to, remote_call, sizeof(reply.hdr.call_to));
|
||||||
|
|
||||||
|
reply.hdr.data_len_NETLE = host2netle(4);
|
||||||
|
reply.count_NETLE = host2netle(count);
|
||||||
|
|
||||||
|
send_to_client (client, &reply);
|
||||||
|
|
||||||
|
} /* end server_outstanding_frames_reply */
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------
|
/*-------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* Name: read_from_socket
|
* Name: read_from_socket
|
||||||
|
@ -1220,8 +1260,9 @@ static THREAD_F cmd_listen_thread (void *arg)
|
||||||
struct {
|
struct {
|
||||||
struct agwpe_s hdr; /* Command header. */
|
struct agwpe_s hdr; /* Command header. */
|
||||||
|
|
||||||
char data[512]; /* Additional data used by some commands. */
|
char data[AX25_MAX_PACKET_LEN]; /* Additional data used by some commands. */
|
||||||
/* Maximum for 'V': 1 + 8*10 + 256 */
|
/* Maximum for 'V': 1 + 8*10 + 256 */
|
||||||
|
/* Maximum for 'D': Info part length + 1 */
|
||||||
} cmd;
|
} cmd;
|
||||||
|
|
||||||
int client = (int)(long)arg;
|
int client = (int)(long)arg;
|
||||||
|
@ -1864,6 +1905,7 @@ static THREAD_F cmd_listen_thread (void *arg)
|
||||||
|
|
||||||
int n = 0;
|
int n = 0;
|
||||||
if (cmd.hdr.portx >= 0 && cmd.hdr.portx < MAX_CHANS) {
|
if (cmd.hdr.portx >= 0 && cmd.hdr.portx < MAX_CHANS) {
|
||||||
|
// Count both normal and expedited in transmit queue for given channel.
|
||||||
n = tq_count (cmd.hdr.portx, -1, "", "", 0);
|
n = tq_count (cmd.hdr.portx, -1, "", "", 0);
|
||||||
}
|
}
|
||||||
reply.data_NETLE = host2netle(n);
|
reply.data_NETLE = host2netle(n);
|
||||||
|
@ -1874,34 +1916,53 @@ static THREAD_F cmd_listen_thread (void *arg)
|
||||||
|
|
||||||
case 'Y': /* How Many Outstanding frames wait for tx for a particular station */
|
case 'Y': /* How Many Outstanding frames wait for tx for a particular station */
|
||||||
|
|
||||||
/* Number of frames sitting in transmit queue for given channel, */
|
// This is different than the above 'y' because this refers to a specific
|
||||||
/* source (optional) and destination addresses. */
|
// link in connected mode.
|
||||||
|
|
||||||
|
// This would be useful for a couple different purposes.
|
||||||
|
|
||||||
|
// When sending bulk data, we want to keep a fair amount queued up to take
|
||||||
|
// advantage of large window sizes (MAXFRAME, EMAXFRAME). On the other
|
||||||
|
// hand we don't want to get TOO far ahead when transferring a large file.
|
||||||
|
|
||||||
|
// Before disconnecting from another station, it would be good to know
|
||||||
|
// that it actually received the last message we sent. For this reason,
|
||||||
|
// I think it would be good for this to include information frames that were
|
||||||
|
// transmitted but not yet acknowleged.
|
||||||
|
// You could say that a particular frame is still waiting to be sent even
|
||||||
|
// if was already sent because it could be sent again if lost previously.
|
||||||
|
|
||||||
|
// The documentation is inconsistent about the address order.
|
||||||
|
// One place says "callfrom" is my callsign and "callto" is the other guy.
|
||||||
|
// That would make sense. We are asking about frames going to the other guy.
|
||||||
|
|
||||||
|
// But another place says it depends on who initiated the connection.
|
||||||
|
//
|
||||||
|
// "If we started the connection CallFrom=US and CallTo=THEM
|
||||||
|
// If the other end started the connection CallFrom=THEM and CallTo=US"
|
||||||
|
//
|
||||||
|
// The response description says nothing about the order; it just mentions two addresses.
|
||||||
|
// If you are writing a client or server application, the order would
|
||||||
|
// be clear but right here it could be either case.
|
||||||
|
//
|
||||||
|
// Another version of the documentation mentioned the source address being optional.
|
||||||
|
//
|
||||||
|
|
||||||
|
// The only way to get this information is from inside the data link state machine.
|
||||||
|
// We will send a request to it and the result coming out will be used to
|
||||||
|
// send the reply back to the client application.
|
||||||
|
|
||||||
{
|
{
|
||||||
char source[AX25_MAX_ADDR_LEN];
|
|
||||||
char dest[AX25_MAX_ADDR_LEN];
|
|
||||||
|
|
||||||
struct {
|
char callsigns[2][AX25_MAX_ADDR_LEN];
|
||||||
struct agwpe_s hdr;
|
const int num_calls = 2;
|
||||||
int data_NETLE; // Little endian order.
|
|
||||||
} reply;
|
|
||||||
|
|
||||||
strlcpy (source, cmd.hdr.call_from, sizeof(source));
|
strlcpy (callsigns[AX25_SOURCE], cmd.hdr.call_from, sizeof(callsigns[AX25_SOURCE]));
|
||||||
strlcpy (dest, cmd.hdr.call_to, sizeof(dest));
|
strlcpy (callsigns[AX25_DESTINATION], cmd.hdr.call_to, sizeof(callsigns[AX25_SOURCE]));
|
||||||
|
|
||||||
memset (&reply, 0, sizeof(reply));
|
// Issue 169. Proper implementation for 'Y'.
|
||||||
reply.hdr.portx = cmd.hdr.portx; /* Reply with same port number, addresses. */
|
dlq_outstanding_frames_request (callsigns, num_calls, cmd.hdr.portx, client);
|
||||||
reply.hdr.datakind = 'Y';
|
|
||||||
strlcpy (reply.hdr.call_from, source, sizeof(reply.hdr.call_from));
|
|
||||||
strlcpy (reply.hdr.call_to, dest, sizeof(reply.hdr.call_to));
|
|
||||||
reply.hdr.data_len_NETLE = host2netle(4);
|
|
||||||
|
|
||||||
int n = 0;
|
|
||||||
if (cmd.hdr.portx >= 0 && cmd.hdr.portx < MAX_CHANS) {
|
|
||||||
n = tq_count (cmd.hdr.portx, -1, source, dest, 0);
|
|
||||||
}
|
|
||||||
reply.data_NETLE = host2netle(n);
|
|
||||||
|
|
||||||
send_to_client (client, &reply);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
2
server.h
2
server.h
|
@ -24,5 +24,7 @@ void server_link_terminated (int chan, int client, char *remote_call, char *own_
|
||||||
|
|
||||||
void server_rec_conn_data (int chan, int client, char *remote_call, char *own_call, int pid, char *data_ptr, int data_len);
|
void server_rec_conn_data (int chan, int client, char *remote_call, char *own_call, int pid, char *data_ptr, int data_len);
|
||||||
|
|
||||||
|
void server_outstanding_frames_reply (int chan, int client, char *own_call, char *remote_call, int count);
|
||||||
|
|
||||||
|
|
||||||
/* end server.h */
|
/* end server.h */
|
||||||
|
|
Loading…
Reference in New Issue