Repository : ssh://git@open-mesh.org/alfred
On branch : master
commit 3fb247469e13242f102e566b287f2e8e7a3a57ab Author: Sven Eckelmann sven@open-mesh.com Date: Thu Jan 17 16:27:45 2013 +0100
alfred: Report errors for request data back to client
The client must be able whether there was an error in requesting data or there is just no data to return. The server will check whether the complete data was returned and when not it will send an error status packet to the client.
Signed-off-by: Sven Eckelmann sven@open-mesh.com
3fb247469e13242f102e566b287f2e8e7a3a57ab alfred.h | 4 ++++ client.c | 46 ++++++++++++++++++++++++++++++++++++++------ recv.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++----------- unix_sock.c | 32 ++++++++++++++++++++++++++++++ 4 files changed, 127 insertions(+), 17 deletions(-)
diff --git a/alfred.h b/alfred.h index ae2dd7c..5e7a505 100644 --- a/alfred.h +++ b/alfred.h @@ -121,6 +121,10 @@ int alfred_client_request_data(struct globals *globals); int alfred_client_set_data(struct globals *globals); /* recv.c */ int recv_alfred_packet(struct globals *globals); +struct transaction_head * +transaction_add(struct globals *globals, struct ether_addr mac, uint16_t id); +struct transaction_head * transaction_clean(struct globals *globals, + struct transaction_head *search); /* send.c */ int push_data(struct globals *globals, struct in6_addr *destination, enum data_source max_source_level, int type_filter, diff --git a/client.c b/client.c index 90b9f02..a535f5a 100644 --- a/client.c +++ b/client.c @@ -36,8 +36,10 @@ int alfred_client_request_data(struct globals *globals) unsigned char buf[MAX_PAYLOAD], *pos; struct alfred_request_v0 *request; struct alfred_push_data_v0 *push; + struct alfred_status_v0 *status; + struct alfred_tlv *tlv; struct alfred_data *data; - int ret, len, headlen, data_len, i; + int ret, len, data_len, i;
if (unix_sock_open_client(globals, ALFRED_SOCK_PATH)) return -1; @@ -57,22 +59,40 @@ int alfred_client_request_data(struct globals *globals) fprintf(stderr, "%s: only wrote %d of %d bytes: %s\n", __func__, ret, len, strerror(errno));
- headlen = sizeof(*push) + sizeof(*data); push = (struct alfred_push_data_v0 *)buf; - while ((ret = read(globals->unix_sock, buf, headlen)) > 0) { + tlv = (struct alfred_tlv *)buf; + while ((ret = read(globals->unix_sock, buf, sizeof(*tlv))) > 0) { + if (ret < (int)sizeof(*tlv)) + break; + + if (tlv->type == ALFRED_STATUS_ERROR) + goto recv_err; + + if (tlv->type != ALFRED_PUSH_DATA) + break; + + /* read the rest of the header */ + ret = read(globals->unix_sock, buf + sizeof(*tlv), + sizeof(*push) - sizeof(*tlv)); + /* too short */ - if (ret < headlen) + if (ret < (int)(sizeof(*push) - (int)sizeof(*tlv))) break;
+ /* read the rest of the header */ + ret = read(globals->unix_sock, buf + sizeof(*push), + sizeof(*data)); + data = push->data; data_len = ntohs(data->header.length);
/* would it fit? it should! */ - if (data_len > (int)(sizeof(buf) - headlen)) + if (data_len > (int)(sizeof(buf) - sizeof(*push))) break;
/* read the data */ - ret = read(globals->unix_sock, buf + headlen, data_len); + ret = read(globals->unix_sock, + buf + sizeof(*push) + sizeof(*data), data_len);
/* again too short */ if (ret < data_len) @@ -101,6 +121,20 @@ int alfred_client_request_data(struct globals *globals) unix_sock_close(globals);
return 0; + +recv_err: + /* read the rest of the status message */ + ret = read(globals->unix_sock, buf + sizeof(*tlv), + sizeof(*status) - sizeof(*tlv)); + + /* too short */ + if (ret < (int)(sizeof(*status) - sizeof(*tlv))) + return -1; + + status = (struct alfred_status_v0 *)buf; + fprintf(stderr, "Request failed with %d\n", status->tx.seqno); + + return status->tx.seqno;; }
int alfred_client_set_data(struct globals *globals) diff --git a/recv.c b/recv.c index 24e8d47..d2accf4 100644 --- a/recv.c +++ b/recv.c @@ -102,6 +102,48 @@ err: return -1; }
+struct transaction_head * +transaction_add(struct globals *globals, struct ether_addr mac, uint16_t id) +{ + struct transaction_head *head; + + head = malloc(sizeof(*head)); + if (!head) + return NULL; + + head->server_addr = mac; + head->id = id; + head->finished = 0; + head->num_packet = 0; + INIT_LIST_HEAD(&head->packet_list); + if (hash_add(globals->transaction_hash, head)) { + free(head); + return NULL; + } + + return head; +} + +struct transaction_head * transaction_clean(struct globals *globals, + struct transaction_head *search) +{ + struct transaction_packet *transaction_packet, *safe; + struct transaction_head *head; + + head = hash_find(globals->transaction_hash, search); + if (!head) + return head; + + list_for_each_entry_safe(transaction_packet, safe, &head->packet_list, + list) { + list_del(&transaction_packet->list); + free(transaction_packet->push); + free(transaction_packet); + } + + return hash_remove(globals->transaction_hash, search); +} + static int process_alfred_push_data(struct globals *globals, struct in6_addr *source, struct alfred_push_data_v0 *push) @@ -124,19 +166,14 @@ static int process_alfred_push_data(struct globals *globals,
head = hash_find(globals->transaction_hash, &search); if (!head) { - head = malloc(sizeof(*head)); - if (!head) + /* slave must create the transactions to be able to correctly + * wait for it */ + if (globals->opmode != OPMODE_MASTER) goto err;
- head->server_addr = mac; - head->id = ntohs(push->tx.id); - head->finished = 0; - head->num_packet = 0; - INIT_LIST_HEAD(&head->packet_list); - if (hash_add(globals->transaction_hash, head)) { - free(head); + head = transaction_add(globals, mac, ntohs(push->tx.id)); + if (!head) goto err; - } } clock_gettime(CLOCK_MONOTONIC, &head->last_rx_time);
@@ -303,7 +340,10 @@ static int process_alfred_status_txend(struct globals *globals, free(transaction_packet); }
- hash_remove(globals->transaction_hash, &search); + /* master mode only syncs. no client is waiting the finished + * transaction */ + if (globals->opmode == OPMODE_MASTER) + transaction_clean(globals, &search);
return 0; } diff --git a/unix_sock.c b/unix_sock.c index b4b05cd..f5e8b08 100644 --- a/unix_sock.c +++ b/unix_sock.c @@ -158,6 +158,9 @@ static int unix_sock_req_data(struct globals *globals, uint8_t buf[MAX_PAYLOAD]; struct alfred_push_data_v0 *push; uint16_t seqno = 0; + uint16_t id; + struct transaction_head search, *head = NULL; + struct alfred_status_v0 status;
len = ntohs(request->header.length);
@@ -172,6 +175,14 @@ static int unix_sock_req_data(struct globals *globals, if (globals->opmode == OPMODE_MASTER) goto send_reply;
+ id = ntohs(request->tx_id); + head = transaction_add(globals, globals->best_server->hwaddr, id); + if (!head) + return -1; + + search.server_addr = globals->best_server->hwaddr; + search.id = id; + send_alfred_packet(globals, &globals->best_server->address, request, sizeof(*request));
@@ -200,8 +211,17 @@ static int unix_sock_req_data(struct globals *globals, recv_alfred_packet(globals); }
+ head = transaction_clean(globals, &search); + if (!head || head->finished != 1) { + free(head); + goto reply_error; + } + send_reply:
+ if (globals->opmode != OPMODE_MASTER) + free(head); + /* send some data back through the unix socket */
push = (struct alfred_push_data_v0 *)buf; @@ -229,6 +249,18 @@ send_reply: }
return 0; + +reply_error: + + free(head); + status.header.type = ALFRED_STATUS_ERROR; + status.header.version = ALFRED_VERSION; + status.header.length = htons(sizeof(status) - sizeof(status.header)); + status.tx.id = request->tx_id; + status.tx.seqno = 1; + write(client_sock, &status, sizeof(status)); + + return 0; }
int unix_sock_read(struct globals *globals)