RpcEndpoint *endpoint_create(struct sockaddr_in *addr, unsigned long subport) { RpcEndpoint *ep = (RpcEndpoint *)mem_alloc(sizeof(RpcEndpoint)); if (ep) { endpoint_complete(ep, addr, subport); } return ep; }
/* continuously reads messages from UDP port */ static void *reader(UNUSED void *args) { DataPayload *dp; char buf[10240]; struct sockaddr_in c_addr; socklen_t len; int n; debugf("reader thread started\n"); for(;;) { unsigned short cmd; unsigned long sb; unsigned long seqno; unsigned char fnum; unsigned char nfrags; char *sp; unsigned short pt; RpcEndpoint ep; CRecord *cr; len = sizeof(c_addr); memset(&c_addr, 0, len); n = recvfrom(my_sock, buf, sizeof(buf), 0, (struct sockaddr *)&c_addr, &len); if (n < 0) continue; buf[n] = '\0'; dp = (DataPayload *)buf; cmd = ntohs(dp->hdr.command); sb = ntohl(dp->hdr.subport); seqno = ntohl(dp->hdr.seqno); fnum = dp->hdr.fnum; nfrags = dp->hdr.nfrags; sp = inet_ntoa(c_addr.sin_addr); pt = ntohs(c_addr.sin_port); if (cmd >= CMD_LOW && cmd <= CMD_HIGH) { logf("%s from %s:%05u:%08lx; seqno = %ld, frag/nfrag = %u/%u\n", cmdnames[cmd], sp, pt, sb, seqno, fnum, nfrags); } else { errorf("Illegal command received: %d\n", cmd); continue; } endpoint_complete(&ep, &c_addr, sb); ctable_lock(); cr = ctable_look_ep(&ep); switch (cmd) { case CONNECT: { RpcEndpoint *nep; ConnectPayload *conp = (ConnectPayload *)dp; ControlPayload *p; int newcr = 0; SRecord *sr; sr = stable_lookup(conp->sname); if (sr == NULL) break; if (cr == NULL) { nep = endpoint_duplicate(&ep); cr = crecord_create(nep, seqno); crecord_setCID(cr, gen_conn_id()); newcr = 1; } else if (cr->state != ST_IDLE) { fprintf(stderr, "%s from %s:%05u:%08lx; seqno = %ld, frag/nfrag = %u/%u\n", cmdnames[cmd], sp, pt, sb, seqno, fnum, nfrags); crecord_dump(cr, "connectrqst"); } if (newcr || cr->state == ST_IDLE) { if (newcr) { p = (ControlPayload *)malloc(CP_SIZE); cp_complete(p, nep->subport, CACK, seqno, 1, 1); crecord_setPayload(cr, p, CP_SIZE, ATTEMPTS, TICKS); } crecord_setService(cr, sr); (void) send_payload(cr->ep, cr->pl, cr->size); crecord_setState(cr, ST_IDLE); } if (newcr) ctable_insert(cr); break; } case CACK: { if ((cr != NULL)) { if (seqno == cr->seqno) crecord_setState(cr, ST_IDLE); } break; } #define NEW 2 #define OLD 1 #define ILL 0 case QUERY: { DataPayload *p = NULL; ControlPayload *cp = NULL; int dplen, cplen; unsigned long state; int accept = ILL; if (cr == NULL) break; state = cr->state; if ((seqno - cr->seqno) == 1 && (state == ST_IDLE || state == ST_RESPONSE_SENT)) { accept = NEW; cr->seqno = seqno; p = (DataPayload *)malloc(n); dplen = n; memcpy(p, buf, n); } else if (seqno == cr->seqno && state == ST_FACK_SENT && (fnum - cr->lastFrag) == 1 && fnum == nfrags) { void *tp; unsigned short flen = ntohs(dp->dhdr.flen); accept = NEW; p = (DataPayload *)cr->resp; dplen = sizeof(PayloadHeader) + sizeof(DataHeader) + ntohs(dp->dhdr.tlen); cr->resp = NULL; tp = (void *)&(p->data[FR_SIZE * (fnum - 1)]); memcpy(tp, dp->data, flen); } else if (seqno == cr->seqno && (state == ST_QACK_SENT || state == ST_RESPONSE_SENT)) { accept = OLD; } switch (accept) { case NEW: cplen = CP_SIZE; cp = (ControlPayload *)malloc(cplen); cp_complete(cp, ep.subport, QACK, seqno, fnum, nfrags); crecord_setPayload(cr, cp, cplen, ATTEMPTS, TICKS); (void)send_payload(cr->ep, cp, cplen); tsl_append(cr->svc->s_queue, cr->ep, p, dplen); crecord_setState(cr, ST_QACK_SENT); break; case OLD: (void)send_payload(cr->ep, cr->pl, cr->size); crecord_setState(cr, state); break; case ILL: break; } break; } case QACK: { if (cr != NULL) { if (seqno == cr->seqno) crecord_setState(cr, ST_AWAITING_RESPONSE); } break; } case RESPONSE: { DataPayload *p = NULL; ControlPayload *cp = NULL; int cplen; unsigned long st; unsigned short flen = ntohs(dp->dhdr.flen); if (cr == NULL || seqno != cr->seqno) break; st = cr->state; if (st == ST_QUERY_SENT || st == ST_AWAITING_RESPONSE) { p = (DataPayload *)malloc(n); memcpy(p, buf, n); cr->resp = p; } else if (st == ST_FACK_SENT && (fnum - cr->lastFrag) == 1 && fnum == nfrags) { p = (DataPayload *)cr->resp; memcpy(&(p->data[FR_SIZE * (fnum -1)]), dp->data, flen); cr->lastFrag = fnum; } else break; cplen = CP_SIZE; cp = (ControlPayload *)malloc(cplen); cp_complete(cp, ep.subport, RACK, seqno, fnum, nfrags); crecord_setPayload(cr, cp, cplen, ATTEMPTS, TICKS); (void)send_payload(cr->ep, cp, cplen); crecord_setState(cr, ST_IDLE); break; } case RACK: { if (cr != NULL) { if (seqno == cr->seqno) crecord_setState(cr, ST_IDLE); } break; } case DISCONNECT: { ControlPayload cp; /* always send a DACK */ cp_complete(&cp, ep.subport, DACK, seqno, 1, 1); (void)send_payload(&ep, &cp, CP_SIZE); if (cr != NULL) { crecord_setState(cr, ST_TIMEDOUT); } break; } case DACK: { if (cr != NULL) { if (seqno == cr->seqno) crecord_setState(cr, ST_TIMEDOUT); } break; } case FRAGMENT: { DataPayload *p = NULL; ControlPayload *cp = NULL; int dplen, cplen; unsigned long st; int accept = ILL; unsigned short tlen = ntohs(dp->dhdr.tlen); unsigned short flen = ntohs(dp->dhdr.flen); int isQ, isR; if (cr == NULL) break; st = cr->state; isQ = (st == ST_IDLE || st == ST_RESPONSE_SENT) && (seqno - cr->seqno) == 1 && fnum == 1; isR = (st == ST_QUERY_SENT || st == ST_AWAITING_RESPONSE) && seqno == cr->seqno && fnum == 1; if (isQ || isR) { accept = NEW; cr->seqno = seqno; dplen = sizeof(PayloadHeader) + sizeof(DataHeader) + tlen; cr->resp = malloc(dplen); p = (DataPayload *)cr->resp; memcpy(p, buf, n); } else if (seqno == cr->seqno && st == ST_FACK_SENT && (fnum - cr->lastFrag) == 1) { void *tp; accept = NEW; p = (DataPayload *)cr->resp; tp = (void *)&(p->data[FR_SIZE * (fnum - 1)]); memcpy(tp, dp->data, flen); } else if (seqno == cr->seqno && st == ST_FACK_SENT && fnum == cr->lastFrag) { accept = OLD; } switch (accept) { case NEW: cr->lastFrag = fnum; cplen = CP_SIZE; cp = (ControlPayload *)malloc(cplen); cp_complete(cp, ep.subport, FACK, seqno, fnum, nfrags); crecord_setPayload(cr, cp, cplen, ATTEMPTS, TICKS); (void)send_payload(cr->ep, cp, cplen); crecord_setState(cr, ST_FACK_SENT); break; case OLD: (void)send_payload(cr->ep, cr->pl, cr->size); crecord_setState(cr, st); break; case ILL: break; } break; } case FACK: { if (cr != NULL) { if (seqno == cr->seqno && cr->state == ST_FRAGMENT_SENT && fnum == cr->lastFrag) { crecord_setState(cr, ST_FACK_RECEIVED); } } break; } case PING: { ControlPayload cp; if (cr != NULL) { cp_complete(&cp, ep.subport, PACK, seqno, 1, 1); (void)send_payload(&ep, &cp, CP_SIZE); } break; } case PACK: { if (cr != NULL) { crecord_setState(cr, cr->state); /* resets ping data */ } break; } case SEQNO: { ControlPayload *cp; if (cr != NULL) { unsigned long st = cr->state; if (st == ST_IDLE || st == ST_RESPONSE_SENT) { cp = (ControlPayload *)malloc(CP_SIZE); cp_complete(cp, ep.subport, SACK, seqno, 1, 1); crecord_setPayload(cr, cp, CP_SIZE, ATTEMPTS, TICKS); (void)send_payload(cr->ep, cp, CP_SIZE); cr->seqno = seqno; crecord_setState(cr, ST_IDLE); } } break; } case SACK: { if (cr != NULL && cr->state == ST_SEQNO_SENT) { crecord_setState(cr, ST_IDLE); } break; } default: { break; } } ctable_unlock(); } return NULL; }