/* Called when we receive a packet */ static void my_recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, struct ip_addr *addr, u16_t port) { xid_t xid; struct rpc_queue *q_item; xid = extract_xid(p->payload); q_item = get_from_queue(xid); debug("Recieved a reply for xid: %u (%d) %p\n", xid, p->len, q_item); if (q_item == NULL) return; if (q_item->func != NULL) { p->arg[0] = p->payload; q_item->func(q_item->callback, q_item->arg, p); } /* Free our memory */ pbuf_free(p); pbuf_free(q_item->pbuf); free(q_item); }
static void add_to_queue(struct pbuf *pbuf, int port, void (*func)(void *, uintptr_t, struct pbuf *), void *callback, uintptr_t arg) { /* Need a lock here */ struct rpc_queue *q_item; struct rpc_queue *tmp; q_item = malloc(sizeof(struct rpc_queue)); assert(q_item != NULL); q_item->next = NULL; q_item->pbuf = pbuf; q_item->xid = extract_xid(pbuf->payload); q_item->timeout = 0; q_item->port = port; q_item->func = func; q_item->arg = arg; q_item->callback = callback; if (queue == NULL) { /* Add at start of the linked list */ queue = q_item; } else { /* Add to end of the linked list */ for(tmp = queue; tmp->next != NULL; tmp = tmp->next) ; tmp->next = q_item; } }
enum rpc_stat rpc_call(struct pbuf *pbuf, int len, struct udp_pcb *pcb, void (*func)(void *, uintptr_t, struct pbuf *), void *callback, uintptr_t token) { struct rpc_call_arg call_arg; struct rpc_queue *q_item; int time_out; enum rpc_stat stat; xid_t xid; /* If we give up early, we must ensure that the argument remains in memory * just in case the packet comes in later */ assert(pcb); assert(pbuf); /* GeneratrSend the thing with the unlock frunction as a callback */ call_arg.func = func; call_arg.callback = callback; call_arg.token = token; call_arg.complete = 0; /* Make the call */ xid = extract_xid(pbuf); stat = rpc_send(pbuf, pbuf->tot_len, pcb, &rpc_call_cb, NULL, (uintptr_t)&call_arg); if(stat){ return stat; } /* Wait for the response */ time_out = RETRANSMIT_DELAY_MS * (CALL_RETRIES + 1); while(time_out >= 0){ _usleep(CALL_TIMEOUT_MS * 1000); if(call_arg.complete) { /* Success */ return 0; } rpc_timeout(CALL_TIMEOUT_MS); time_out -= CALL_TIMEOUT_MS; } /* If we get here, we have failed. Data is on the stack so make sure * we remove references from the queue */ q_item = get_from_queue(xid); assert(q_item); pbuf_free(q_item->pbuf); free(q_item); return RPCERR_COMM; }
static void my_recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, struct ip_addr *addr, u16_t port) { xid_t xid; struct rpc_queue *q_item; (void)port; xid = extract_xid(p); q_item = get_from_queue(xid); debug("Recieved a reply for xid: %u (%d) %p\n", xid, p->len, q_item); if (q_item != NULL){ assert(q_item->func); q_item->func(q_item->callback, q_item->arg, p); /* Clean up the queue item */ pbuf_free(q_item->pbuf); free(q_item); } /* Done with the incoming packet so free it */ pbuf_free(p); }