?? ctpforwardingenginep.nc
字號:
fe_queue_entry_t *qe;
dbg("Forwarder", "%s: sending packet from client %hhu: %x, len %hhu\n", __FUNCTION__, client, msg, len);
if (!hasState(ROUTING_ON)) {return EOFF;}
if (len > call Send.maxPayloadLength[client]()) {return ESIZE;}
call Packet.setPayloadLength(msg, len);
hdr = getHeader(msg);
hdr->origin = TOS_NODE_ID;
hdr->originSeqNo = seqno++;
hdr->type = call CollectionId.fetch[client]();
hdr->thl = 0;
if (clientPtrs[client] == NULL) {
dbg("Forwarder", "%s: send failed as client is busy.\n", __FUNCTION__);
return EBUSY;
}
qe = clientPtrs[client];
qe->msg = msg;
qe->client = client;
qe->retries = MAX_RETRIES;
dbg("Forwarder", "%s: queue entry for %hhu is %hhu deep\n", __FUNCTION__, client, call SendQueue.size());
if (call SendQueue.enqueue(qe) == SUCCESS) {
if (hasState(RADIO_ON) && !hasState(SENDING)) {
dbg("FHangBug", "%s posted sendTask.\n", __FUNCTION__);
post sendTask();
}
clientPtrs[client] = NULL;
return SUCCESS;
}
else {
dbg("Forwarder",
"%s: send failed as packet could not be enqueued.\n",
__FUNCTION__);
// send a debug message to the uart
call CollectionDebug.logEvent(NET_C_FE_SEND_QUEUE_FULL);
// Return the pool entry, as it's not for me...
return FAIL;
}
}
command error_t Send.cancel[uint8_t client](message_t* msg) {
// cancel not implemented. will require being able
// to pull entries out of the queue.
return FAIL;
}
command uint8_t Send.maxPayloadLength[uint8_t client]() {
return call Packet.maxPayloadLength();
}
command void* Send.getPayload[uint8_t client](message_t* msg, uint8_t len) {
return call Packet.getPayload(msg, len);
}
/*
* These is where all of the send logic is. When the ForwardingEngine
* wants to send a packet, it posts this task. The send logic is
* independent of whether it is a forwarded packet or a packet from
* a send clientL the two cases differ in how memory is managed in
* sendDone.
*
* The task first checks that there is a packet to send and that
* there is a valid route. It then marshals the relevant arguments
* and prepares the packet for sending. If the node is a collection
* root, it signals Receive with the loopback message. Otherwise,
* it sets the packet to be acknowledged and sends it. It does not
* remove the packet from the send queue: while sending, the
* packet being sent is at the head of the queue; a packet is dequeued
* in the sendDone handler, either due to retransmission failure
* or to a successful send.
*/
task void sendTask() {
uint16_t gradient;
dbg("Forwarder", "%s: Trying to send a packet. Queue size is %hhu.\n", __FUNCTION__, call SendQueue.size());
if (hasState(SENDING) || call SendQueue.empty()) {
call CollectionDebug.logEvent(NET_C_FE_SENDQUEUE_EMPTY);
return;
}
else if ((!call RootControl.isRoot() &&
!call UnicastNameFreeRouting.hasRoute()) ||
(call CtpInfo.getEtx(&gradient) != SUCCESS)) {
/* This code path is for when we don't have a valid next
* hop. We set a retry timer.
*
* Technically, this timer isn't necessary, as if a route
* is found we'll get an event. But just in case such an event
* is lost (e.g., a bug in the routing engine), we retry.
* Otherwise the forwarder might hang indefinitely. As this test
* doesn't require radio activity, the energy cost is minimal. */
dbg("Forwarder", "%s: no route, don't send, try again in %i.\n", __FUNCTION__, NO_ROUTE_RETRY);
call RetxmitTimer.startOneShot(NO_ROUTE_RETRY);
call CollectionDebug.logEvent(NET_C_FE_NO_ROUTE);
return;
}
else {
/* We can send a packet.
First check if it's a duplicate;
if not, try to send/forward. */
error_t subsendResult;
fe_queue_entry_t* qe = call SendQueue.head();
uint8_t payloadLen = call SubPacket.payloadLength(qe->msg);
am_addr_t dest = call UnicastNameFreeRouting.nextHop();
if (call SentCache.lookup(qe->msg)) {
/* This packet is a duplicate, so suppress it: free memory and
* send next packet. Duplicates are only possible for
* forwarded packets, so we can circumvent the client or
* forwarded branch for freeing the buffer. */
call CollectionDebug.logEvent(NET_C_FE_DUPLICATE_CACHE_AT_SEND);
call SendQueue.dequeue();
if (call MessagePool.put(qe->msg) != SUCCESS)
call CollectionDebug.logEvent(NET_C_FE_PUT_MSGPOOL_ERR);
if (call QEntryPool.put(qe) != SUCCESS)
call CollectionDebug.logEvent(NET_C_FE_PUT_QEPOOL_ERR);
post sendTask();
return;
}
// Not a duplicate: we've decided we're going to send.
dbg("Forwarder", "Sending queue entry %p\n", qe);
if (call RootControl.isRoot()) {
/* Code path for roots: copy the packet and signal receive. */
collection_id_t collectid = getHeader(qe->msg)->type;
uint8_t* payload;
uint8_t payloadLength;
memcpy(loopbackMsgPtr, qe->msg, sizeof(message_t));
payload = call Packet.getPayload(loopbackMsgPtr, call Packet.payloadLength(loopbackMsgPtr));
payloadLength = call Packet.payloadLength(loopbackMsgPtr);
dbg("Forwarder", "%s: I'm a root, so loopback and signal receive.\n", __FUNCTION__);
loopbackMsgPtr = signal Receive.receive[collectid](loopbackMsgPtr,
payload,
payloadLength);
signal SubSend.sendDone(qe->msg, SUCCESS);
}
else {
/* The basic forwarding/sending case. */
call CtpPacket.setEtx(qe->msg, gradient);
call CtpPacket.clearOption(qe->msg, CTP_OPT_ECN | CTP_OPT_PULL);
if (call PacketAcknowledgements.requestAck(qe->msg) == SUCCESS) {
setState(ACK_PENDING);
}
if (hasState(QUEUE_CONGESTED)) {
call CtpPacket.setOption(qe->msg, CTP_OPT_ECN);
clearState(QUEUE_CONGESTED);
}
subsendResult = call SubSend.send(dest, qe->msg, payloadLen);
if (subsendResult == SUCCESS) {
// Successfully submitted to the data-link layer.
setState(SENDING);
dbg("Forwarder", "%s: subsend succeeded with %p.\n", __FUNCTION__, qe->msg);
return;
}
// The packet is too big: truncate it and retry.
else if (subsendResult == ESIZE) {
dbg("Forwarder", "%s: subsend failed from ESIZE: truncate packet.\n", __FUNCTION__);
call Packet.setPayloadLength(qe->msg, call Packet.maxPayloadLength());
post sendTask();
call CollectionDebug.logEvent(NET_C_FE_SUBSEND_SIZE);
}
else {
dbg("Forwarder", "%s: subsend failed from %i\n", __FUNCTION__, (int)subsendResult);
}
}
}
}
/*
* The second phase of a send operation; based on whether the transmission was
* successful, the ForwardingEngine either stops sending or starts the
* RetxmitTimer with an interval based on what has occured. If the send was
* successful or the maximum number of retransmissions has been reached, then
* the ForwardingEngine dequeues the current packet. If the packet is from a
* client it signals Send.sendDone(); if it is a forwarded packet it returns
* the packet and queue entry to their respective pools.
*
*/
void packetComplete(fe_queue_entry_t* qe, message_t* msg, bool success) {
// Four cases:
// Local packet: success or failure
// Forwarded packet: success or failure
if (qe->client < CLIENT_COUNT) {
clientPtrs[qe->client] = qe;
signal Send.sendDone[qe->client](msg, SUCCESS);
if (success) {
dbg("CtpForwarder", "%s: packet %hu.%hhu for client %hhu acknowledged.\n", __FUNCTION__, call CollectionPacket.getOrigin(msg), call CollectionPacket.getSequenceNumber(msg), qe->client);
call CollectionDebug.logEventMsg(NET_C_FE_SENT_MSG,
call CollectionPacket.getSequenceNumber(msg),
call CollectionPacket.getOrigin(msg),
call AMPacket.destination(msg));
} else {
dbg("CtpForwarder", "%s: packet %hu.%hhu for client %hhu dropped.\n", __FUNCTION__, call CollectionPacket.getOrigin(msg), call CollectionPacket.getSequenceNumber(msg), qe->client);
call CollectionDebug.logEventMsg(NET_C_FE_SENDDONE_FAIL_ACK_SEND,
call CollectionPacket.getSequenceNumber(msg),
call CollectionPacket.getOrigin(msg),
call AMPacket.destination(msg));
}
}
else {
if (success) {
call SentCache.insert(qe->msg);
dbg("CtpForwarder", "%s: forwarded packet %hu.%hhu acknowledged: insert in transmit queue.\n", __FUNCTION__, call CollectionPacket.getOrigin(msg), call CollectionPacket.getSequenceNumber(msg));
call CollectionDebug.logEventMsg(NET_C_FE_FWD_MSG,
call CollectionPacket.getSequenceNumber(msg),
call CollectionPacket.getOrigin(msg),
call AMPacket.destination(msg));
}
else {
dbg("CtpForwarder", "%s: forwarded packet %hu.%hhu dropped.\n", __FUNCTION__, call CollectionPacket.getOrigin(msg), call CollectionPacket.getSequenceNumber(msg));
call CollectionDebug.logEventMsg(NET_C_FE_SENDDONE_FAIL_ACK_FWD,
call CollectionPacket.getSequenceNumber(msg),
call CollectionPacket.getOrigin(msg),
call AMPacket.destination(msg));
}
if (call MessagePool.put(qe->msg) != SUCCESS)
call CollectionDebug.logEvent(NET_C_FE_PUT_MSGPOOL_ERR);
if (call QEntryPool.put(qe) != SUCCESS)
call CollectionDebug.logEvent(NET_C_FE_PUT_QEPOOL_ERR);
}
}
event void SubSend.sendDone(message_t* msg, error_t error) {
fe_queue_entry_t *qe = call SendQueue.head();
dbg("Forwarder", "%s to %hu and %hhu\n", __FUNCTION__, call AMPacket.destination(msg), error);
if (error != SUCCESS) {
/* The radio wasn't able to send the packet: retransmit it. */
dbg("Forwarder", "%s: send failed\n", __FUNCTION__);
call CollectionDebug.logEventMsg(NET_C_FE_SENDDONE_FAIL,
call CollectionPacket.getSequenceNumber(msg),
call CollectionPacket.getOrigin(msg),
call AMPacket.destination(msg));
startRetxmitTimer(SENDDONE_FAIL_WINDOW, SENDDONE_FAIL_OFFSET);
}
else if (hasState(ACK_PENDING) && !call PacketAcknowledgements.wasAcked(msg)) {
/* No ack: if countdown is not 0, retransmit, else drop the packet. */
call LinkEstimator.txNoAck(call AMPacket.destination(msg));
call CtpInfo.recomputeRoutes();
if (--qe->retries) {
dbg("Forwarder", "%s: not acked, retransmit\n", __FUNCTION__);
call CollectionDebug.logEventMsg(NET_C_FE_SENDDONE_WAITACK,
call CollectionPacket.getSequenceNumber(msg),
call CollectionPacket.getOrigin(msg),
call AMPacket.destination(msg));
startRetxmitTimer(SENDDONE_NOACK_WINDOW, SENDDONE_NOACK_OFFSET);
} else {
/* Hit max retransmit threshold: drop the packet. */
call SendQueue.dequeue();
clearState(SENDING);
startRetxmitTimer(SENDDONE_OK_WINDOW, SENDDONE_OK_OFFSET);
packetComplete(qe, msg, FALSE);
}
}
else {
/* Packet was acknowledged. Updated the link estimator,
free the buffer (pool or sendDone), start timer to
send next packet. */
call SendQueue.dequeue();
clearState(SENDING);
startRetxmitTimer(SENDDONE_OK_WINDOW, SENDDONE_OK_OFFSET);
call LinkEstimator.txAck(call AMPacket.destination(msg));
packetComplete(qe, msg, TRUE);
}
}
/*
* Function for preparing a packet for forwarding. Performs
* a buffer swap from the message pool. If there are no free
* message in the pool, it returns the passed message and does not
* put it on the send queue.
*/
message_t* ONE forward(message_t* ONE m) {
if (call MessagePool.empty()) {
dbg("Route", "%s cannot forward, message pool empty.\n", __FUNCTION__);
// send a debug message to the uart
call CollectionDebug.logEvent(NET_C_FE_MSG_POOL_EMPTY);
}
else if (call QEntryPool.empty()) {
dbg("Route", "%s cannot forward, queue entry pool empty.\n",
__FUNCTION__);
// send a debug message to the uart
call CollectionDebug.logEvent(NET_C_FE_QENTRY_POOL_EMPTY);
}
else {
message_t* newMsg;
fe_queue_entry_t *qe;
uint16_t gradient;
qe = call QEntryPool.get();
if (qe == NULL) {
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -