rmdp/sender.c010064400373640000764000000214030657033200300146570ustar00ucaclxvcsstaff00002440000013#include #include #include #include #include #include #include #include #include #include #include #include "rmdpif.h" #include "fec.h" #include "rmdp.h" #include "layers.h" #include "sender.h" #include "agent.h" #include "init.h" #include "utils.h" #if (!defined(Linux)) #if ( defined(SunOS) && (OSMVER < 5)) extern char *sys_errlist[]; extern int errno; #endif #endif /* this is an hack ... I'm using rlc net.o */ int openrsock(unsigned long addr, short *port); unsigned long localaddr(int ssock_); static int get_flen(int filn); static int setup_req_chan(rmdp_inst_t *se); #define getinstance(i) ((rmdp_inst_t *)_rlc_getinstance(i, rmdp_inst_mngr)) #define ID_RMDP_REQU 212134 static int sender_init_done = 0; /*++++ Retrieves the number of layers used in the sender. Params: - pi: protocol instance identifier. Returns: - the number of layers, on success. - a negative value on failure: */ int rmdp_get_nlay (int pi) { rmdp_inst_t *inst; if ((inst = getinstance(pi)) == NULL) { return (rlc_return_error_(-1, RMDP_NOSUCH_INST, NULL)); } return ( inst->nlay ); } /*++++ Retrieves the number of packets left to transmit in the base layer. Params: - pi: protocol instance identifier. Returns: - the number of packets, on success. - a negative value on failure: */ int rmdp_get_left (int pi) { rmdp_inst_t *inst; if ((inst = getinstance(pi)) == NULL) { return (rlc_return_error_(-1, RMDP_NOSUCH_INST, NULL)); } return ( inst->pkts_left ); } /*++++ Increments the number of packets left to transmit in the base layer. Params: - pi: protocol instance identifier. Returns: - 0 on success. - a negative value on failure: */ int rmdp_incr_left (int pi, int incr) { rmdp_inst_t *inst; if ((inst = getinstance(pi)) == NULL) { return (rlc_return_error_(-1, RMDP_NOSUCH_INST, NULL)); } inst->pkts_left = inst->pkts_left + incr; return ( 0 ); } int _rmdp_sender_init() { if (!sender_init_done) { sender_init_done = 1; } return (0); } /* * returns the data packet to send and its lenght, * only the payload is filled, the transport header gets filled * by the caller. * */ int _rmdp_tx_packet(int des, int lay, char flags, char **p) { int pkt, blk, res; rmdp_inst_t *inst; rmdp_header_t *mp; if ((inst = getinstance(des)) == NULL) { rlc_have_error_(-1, RMDP_NOSUCH_INST, NULL); return (RMDP_NOSUCH_INST); } if (inst->mfeeso == -1 && (res = setup_req_chan(inst)) < 0) { _rmdp_deleteinstance(inst); rlc_have_error_(inst->rlc_pi, res, NULL); } /* lay < 0 is a termination */ if (lay >= 0 && inst->pkts_left>0) { which_packet(inst->B, inst->k, inst->nlay, -1, &lay, &(inst->idxs[lay]), &pkt, &blk); (inst->idxs[lay]) ++; if (pkt < inst->k) *p = (char *)mp = (rmdp_header_t *)inst->alldata[blk][pkt]; else { fec_encode(inst->feccode, (void **)inst->allpkts[blk], RMDP_DATA(inst->sparepkt), pkt, inst->psize); *p = (char *)mp = (rmdp_header_t *)inst->sparepkt; } mp->B = htons(inst->B); mp->k = htons(inst->k); mp->the_B = htons(blk); mp->the_k = htons(pkt); mp->sessid = htonl(inst->sessid); mp->flength = htonl(inst->flength); mp->left = htonl(inst->pkts_left); if (!lay && inst->pkts_left != RMDP_LEFT_INFINITE) { inst->pkts_left --; } NDEB(fprintf(stderr, "&&&& left %ld\n", inst->pkts_left);) return(inst->psize+RMDP_H_S); } else { _rmdp_deleteinstance(inst); return(0); } } /* * Reads the file to be sent. * */ int _rmdp_tx_read(int des, int fd) { rmdp_inst_t *inst; int tlength, done, i, j; if ((inst = getinstance(des)) == NULL) { return (rlc_return_error_(-1, RMDP_NOSUCH_INST, NULL)); } /* XXX we should make sure that this get called just once * or at least .... */ if ((tlength = get_flen(fd)) <= 0) return rlc_return_error_(inst->rlc_pi, RMDP_STAT_ERROR, NULL); inst->flength = tlength; inst->npkts = (tlength+inst->psize-1)/inst->psize; if (compute_k_B(&(inst->k), &(inst->B), inst->npkts, inst->nlay) < 0) { return (rlc_return_error_ (inst->rlc_pi, RMDP_COMPUTE_K, NULL)); } if ((inst->feccode = get_fec(inst->k, 256)) == NULL) { return (rlc_return_error_ (inst->rlc_pi, RMDP_COD_INST_ERR, NULL)); } /* ** computing the number of packets scheduled initially ** tricky... we use the maximum between those sufficient ** at an average layer and 40 ... */ inst->init_left = max (40, inst->k*inst->B / (1<<((inst->nlay)/2)) ); #if 0 inst->init_left *= 1000; /* XXX */ NDEB(fprintf(stderr, "&&&& left %ld\n", inst->init_left);) #endif if ( inst->pkts_left != RMDP_LEFT_INFINITE) inst->pkts_left = inst->init_left; /* allocate file buffers and read file */ if ( _rmdp_allocation(inst) < 0 ) return (rlc_return_error_(inst->rlc_pi, RMDP_ALLOC_ERROR, "* rmdp: Cannot allocate file data structure")); for (done=0, i=0; i<(inst->B); i++) { for (j=0; j<(inst->k); j++) { if (NULL ==(inst->alldata[i][j] = (char *)calloc(1, inst->psize+RMDP_H_S))) { return (rlc_return_error_(inst->rlc_pi, RMDP_ALLOC_ERROR, "* rmdp: Cannot allocate file data structure")); } inst->allpkts[i][j] = RMDP_DATA(inst->alldata[i][j]); if (!done && (read(fd, inst->allpkts[i][j], inst->psize)) != inst->psize) { done = 1; } } } return 0; } static void have_extension_req(rmdp_inst_t *se, rmdp_cont_pkt_t *req) { unsigned long ext; ext = ntohl(req->extension); NDEB(fprintf(stderr, "> req %ld, now %ld!\n", ext, se->pkts_left);) if (ext > 0 && se->pkts_left != RMDP_LEFT_INFINITE) /* XXX we should implement more sophisticated policies */ se->pkts_left += min (ext, se->init_left); } static int have_feedback(rmdp_inst_t *se) { char feedpkt[4096]; rmdp_cont_pkt_t *extreq; rmdp_feed_pkt_t *feereq; struct sockaddr_in srcaddr; int len, srcaddrlen=sizeof(srcaddr); int sock; sock = rlc_showselected (); NDEB(fprintf(stderr, "> have feedback!\n");) /* read request */ if ((len = recvfrom(sock, (char *)&feedpkt, sizeof(feedpkt), 0, (struct sockaddr *)&srcaddr, &srcaddrlen))<=0 ) { /* ... this is a warning */ rlc_have_error_ (se->rlc_pi, RMDP_CANT_READ_REQ, NULL); NDEB(fprintf(stderr, "> have request cant read *** !\n");) return 0; } extreq = (rmdp_cont_pkt_t *)&feedpkt; /* check integrity */ if (len < sizeof(rmdp_cont_pkt_t) || ntohl(extreq->magic) != RMDP_L_MAGIC || ntohl(extreq->sessid) != se->sessid) { /* ... this is a warning */ rlc_have_error_ (se->rlc_pi, RMDP_BAD_REQ, NULL); NDEB(fprintf(stderr, "> have request bad req *** !\n");) return 0; } if (ntohl(extreq->extension) != 0) have_extension_req (se, extreq); if (len >= sizeof(rmdp_cont_pkt_t) + 4) { /* there's something else */ feereq = (rmdp_feed_pkt_t *)&feedpkt; switch (ntohl(feereq->type)) { case RMDP_FEED_RLC_STATS: if (se->stafd > 0) { stats_rec_t st; int size = len - sizeof(rmdp_cont_pkt_t) - 4; st.time = htonl(timestamp_s()); st.fromip = srcaddr.sin_addr.s_addr; st.fromport = srcaddr.sin_port; st.type = feereq->type; st.size = htonl(size); if (write(se->stafd, (void *)&st, sizeof(st)) != sizeof(st) || write(se->stafd, feedpkt + len - size, size) != size) { se->stafd = -1; rlc_have_error_ (se->rlc_pi, RMDP_CANT_WRITE_STATS, NULL); } } break; default: /* don't know this, ignore */ break; } } return 0; } static int setup_req_chan(rmdp_inst_t *se) { unsigned long myaddr; /* first arrange for multicast feedback */ if ((se->mfeeso = openrsock(se->addr, &(se->port))) < 0 || fcntl(se->mfeeso, F_SETFL, O_NONBLOCK) < 0 || rlc_insertchan(se->mfeeso, ID_RMDP_REQU, (CALLBACK)have_feedback, (void *)se) < 0) { return (rlc_internal_set_error_ (se->rlc_pi, RMDP_NO_SOCK, NULL)); } /* then for unicast ... */ if ((myaddr = localaddr(se->mfeeso)) == -1) return (rlc_internal_set_error_ (se->rlc_pi, RMDP_NO_SOCK, "Cannot" "determine local address")); if ((se->ufeeso = openrsock(myaddr, &(se->port))) < 0 || fcntl(se->ufeeso, F_SETFL, O_NONBLOCK) < 0 || rlc_insertchan(se->ufeeso, ID_RMDP_REQU, (CALLBACK)have_feedback, (void *)se) < 0) { return (rlc_internal_set_error_ (se->rlc_pi, RMDP_NO_SOCK, NULL)); } return 0; } static int get_flen(int filn) { struct stat filest; int i=fstat(filn, &filest); if (i < 0) { #if (!defined(Linux)) #if ( defined(SunOS) && (OSMVER < 5)) return rlc_return_error_(-1, RMDP_STAT_ERROR, sys_errlist [errno]); #else return rlc_return_error_(-1, RMDP_STAT_ERROR, strerror (errno)); #endif #else return rlc_return_error_(-1, RMDP_STAT_ERROR, strerror (errno)); #endif } return(filest.st_size); } rmdp/receiver.c010064400373640000764000000322240657253613200152210ustar00ucaclxvcsstaff00002440000013#include #include #include #include #include #include #include #include #include #include #include #include "receiver.h" #include "agent.h" #include "rmdpif.h" #include "fec.h" #include "rmdp.h" #include "init.h" #include "utils.h" #define getinstance(i) ((rmdp_inst_t *)_rlc_getinstance(i, rmdp_inst_mngr)) static int receiver_init_done = 0; /* this is an hack ... I'm using rlc net.o */ int openssock(unsigned long addr, short port, int ttl, int noblock); static int decode(rmdp_inst_t *inst); static int save(rmdp_inst_t *inst); static int send_request(void *ides); static int ask_more(rmdp_inst_t *inst, int *rtime); static int setup_feed_sock (rmdp_inst_t *inst); static void unset_feed_sock (rmdp_inst_t *inst); #define RMDP_RETR_TIM 9090 #define KFACT 0.2 /* moving average factor */ #define SAFEF 1.2 /* safety factor for extension */ /*++++ Sets the function to be called when the reception terminates because of a timeout. This function is called either if the receiver times out waiting for the next packet, or if it is unable to prolong a too short transmission. If this timeout handler is not set, the usual asynchronous error handling mechanism is used instead. Params: - pi: protocol instance identifier. - err_f: the error callback function. It is of type typedef void (*rmdp_rx_err_f) (int pi); Returns: - 0 on success; - a negative value on failure: */ int rmdp_rx_set_err_callback (int pi, rmdp_rx_err_f err_f) { rmdp_inst_t *inst; if ((inst = getinstance(pi)) == NULL) { return (rlc_return_error_(-1, RMDP_NOSUCH_INST, NULL)); } inst->err_f = err_f; return (0); } /*++++ Enables multicast feedback. Default is unicast! Params: - pi: protocol instance identifier. - multifeed: if != enable multicast, otherwise unicast. Returns: - 0 on success, a negative value on failure. */ int rmdp_rx_enable_multifeed (int pi, int multifeed) { rmdp_inst_t *inst; if ((inst = getinstance(pi)) == NULL) { return (rlc_return_error_(pi, RMDP_NOSUCH_INST, NULL)); } if (multifeed) inst->mcastfeed = 1; else inst->mcastfeed = 0; unset_feed_sock (inst); return (0); } int _rmdp_receiver_init() { if (!receiver_init_done) { receiver_init_done = 1; } return (0); } void _rmdp_send_stats (int pi, void *buff, int size) { char tbu[RMDP_STATS_PAYSIZE+sizeof(rmdp_feed_pkt_t)]; rmdp_inst_t *inst; int thissize; DEB(fprintf(stderr, "_rmdp_send_stats pi %d with size %d\n", pi, size);) if ((inst = getinstance(pi)) == NULL) { /* rlc_have_error_(-1, RMDP_NOSUCH_INST, NULL); */ return; } /* XXX */ thissize = min (size, RMDP_STATS_PAYSIZE); bcopy (buff, tbu+sizeof(rmdp_feed_pkt_t), thissize); if (inst->mfeeso == -1 && inst->ufeeso == -1 && setup_feed_sock (inst) < 0) { /* rlc_have_error_ (inst->rlc_pi, RMDP_NO_SOCK, NULL); */ return; } RMDP_FEE_RLC_FILL(*((rmdp_feed_pkt_t *)tbu), inst->sessid); if (send(inst->mfeeso, (char *)&tbu, thissize, 0) == -1) { /* rlc_have_error_ (inst->rlc_pi, RMDP_ER_SND, NULL); */ return; } } /* reveived paket handling */ void _rmdp_rx_packet(int ides, int lay, char flags, char *pkt, int size) { int i, ret; int pkt_n, blk_n; rmdp_inst_t *inst; int rtime, newleft; NDEB(fprintf(stderr,"*** got l %d, siz %d\n", lay, size);) if (size <= 0) { NDEB(fprintf(stderr, "--- rx_packet: (lay %d) skipping void (%d) pkt\n", lay, size);) return; } if ((inst = getinstance(ides)) == NULL) { rlc_have_error_(-1, RMDP_NOSUCH_INST, "* rx_packet called for unknown instance"); return; } if (inst->rlc_pi < 0) { rlc_have_error_(-1, RMDP_NO_RLC_ID, NULL); return; } /* see what we have */ pkt_n = ntohs(RMDP_H_P(pkt)->the_k); blk_n = ntohs(RMDP_H_P(pkt)->the_B); NDEB(fprintf(stderr,"--- got B %d, k %d\n", pkt_n, blk_n);) /* must allocate data buffers */ if (inst->B == 0 ) { inst->k = ntohs(RMDP_H_P(pkt)->k); inst->B = ntohs(RMDP_H_P(pkt)->B); inst->flength = ntohl(RMDP_H_P(pkt)->flength); inst->psize = size - RMDP_H_S; inst->npkts = (inst->flength+inst->psize-1)/inst->psize; NDEB(fprintf(stderr,"--- first packet, must allocate things" " (len %lu B %d)\n", inst->flength, inst->B);) NDEB(fprintf(stderr,"--- got B %d, k %d\n", inst->B, inst->k)); inst->missingblocks = inst->B; inst->duppackets = 0; if ( (inst->B > 4000) || (inst->flength > 10000000) ) { rlc_have_error_(inst->rlc_pi, RMDP_DATA_SIZE, NULL); /* _rmdp_deleteinstance(inst); */ free (pkt); /* is it OK? XXX */ return; } if (_rmdp_allocation(inst) < 0) { rlc_have_error_(inst->rlc_pi, RMDP_ALLOC_ERROR, NULL); _rmdp_deallocation(inst); free (pkt); /* is it OK? XXX */ return; } if (inst->stafd > 0 && (ret = rlc_rx_set_stats_deliver_f ( inst->rlc_pi, ides, _rmdp_send_stats, RMDP_STATS_PAYSIZE)) < 0) rlc_have_error_(inst->rlc_pi, ret, NULL); #ifdef HAVE_UI if (inst->have_gui) { rlc_gui_tcl_exec(inst->rlc_pi, NULL, "pkts_init %d %d %d %d", inst->B, inst->k, inst->flength, inst->psize); NDEB(fprintf(stderr,"--- UI update: " "pkts_init %d %d\n", inst->B, inst->k);) } #endif } /* if have sessid check if it belongs to us !! */ if (inst->sessid && inst->sessid != ntohl(RMDP_H_P(pkt)->sessid)) { free (pkt); /* is it OK? XXX */ return; } else { inst->sessid = ntohl(RMDP_H_P(pkt)->sessid); } inst->totgot ++; /* update a stat .. */ newleft = ntohl(RMDP_H_P(pkt)->left); NDEB(fprintf(stderr, "now left is %d\n", newleft);) if (inst->left > newleft) { int f; f = (inst->totgot-inst->oldtotgot); inst->oldtotgot = inst->totgot; inst->speedf += KFACT * (f - inst->speedf); NDEB(fprintf(stderr, "now f is %f\n", inst->speedf);) } if (inst->countdata[blk_n] >= inst->k) { inst->duppackets++; free (pkt); /* is it OK? XXX */ } else { int valid = 1; for (i=0; icountdata[blk_n]; i++) if (pkt_n == inst->whichdata[blk_n][i]) { valid = 0; NDEB(fprintf(stderr, "not valid.. blk %d pkt %d\n", blk_n, pkt_n)) #ifdef HAVE_UI if (inst->have_gui) { rlc_gui_tcl_exec(inst->rlc_pi, NULL, "pkts_have_dup %d 1", blk_n); NDEB(fprintf(stderr,"--- UI update: pkts_have_dup %d 1\n", blk_n);) } #endif break; } if (valid) { inst->netgot ++; inst->whichdata[blk_n][inst->countdata[blk_n]] = pkt_n; inst->maxn = max (inst->maxn, pkt_n); inst->alldata[blk_n][inst->countdata[blk_n]] = pkt; inst->allpkts[blk_n][inst->countdata[blk_n]] = RMDP_DATA(pkt); inst->countdata[blk_n]++; NDEB(fprintf(stderr, "now blk %4d pkt %4d (%4d pkts); " "miss %4d pkts %4d blks\n", blk_n, pkt_n, inst->countdata[blk_n], inst->k-inst->countdata[blk_n],inst->missingblocks)) if (inst->countdata[blk_n] == inst->k) { inst->missingblocks--; } #ifdef HAVE_UI if (inst->have_gui) { int part = inst->netgot * 50 / (inst->B * inst->k); if (part > inst->recpercent) { inst->recpercent = part; rlc_gui_tcl_exec(inst->rlc_pi, NULL, "prog_percent %f", part/50.0); } } #endif } else { inst->duppackets++; free (pkt); /* is it OK? XXX */ } } #ifdef HAVE_UI if (inst->have_gui) { rlc_gui_tcl_exec(inst->rlc_pi, NULL, "pkts_have_more %d 1", blk_n); NDEB(fprintf(stderr,"--- UI update: pkts_have_more %d 1\n", blk_n);) } #endif /* end reception ? */ if (!inst->missingblocks) { int res; inst->reqpending = 0; res = decode(inst); NDEB(fprintf(stderr, "rmdp: h_p %d (%x) decoded with %d\n", ides, (int)inst, res);) if (inst->end_f) inst->end_f(ides, res); NDEB(fprintf(stderr, "rmdp: h_p after end_f for %d (%x)\n", ides, (int)inst);) save(inst); /* _rmdp_deleteinstance(inst); */ NDEB(fprintf(stderr, "rmdp: h_p delated %d (%x)\n", ides, (int)inst);) return; } /* handle extension of transmission */ /* sender has extended the trnasmissin, * we try to `reset' the timeout process */ if (inst->reqpending && newleft > inst->left) inst->reqsent = 0; inst->left = newleft; if ((!inst->reqpending) && (inst->reqpending=ask_more(inst, &rtime))) { inst->reqpending = 1; inst->reqsent = 0; NDEB(fprintf(stderr, "scheduling req at %d\n", rtime);) if (rlc_settimer(RMDP_RETR_TIM, rtime, (CALLBACK)send_request, (void *)ides, 0) < 0) { rlc_have_error_(inst->rlc_pi, RMDP_ER_RETR_TI, NULL); } } else if (inst->reqpending && !ask_more(inst, &rtime)) { /* the sender has possibly extended the transmission */ inst->reqpending = 0; inst->reqsent = 0; } } /* If we should ask for an extension return the amount, * otherwise return 0. */ static int ask_more(rmdp_inst_t *inst, int *rtime) { int more; rx_info_t info; double adv; int len = sizeof(rx_info_t); /* ** B*k is the number of `net' packets we want ** netgot is the amount we got ** totgot is the total number we got ** speedf is the # pkts got for each pkt sent on lay 0 */ more = (( (inst->B * inst->k * SAFEF) /*tot safly need*/ - inst->netgot /*got this so far*/ ) /*=net needed*/ * inst->netgot/(double)inst->totgot /*waste factor*/ /*=tot needed*/ - inst->left ) /*=will be needed*/ / (double)inst->speedf + 1; /*=pkt on 0 will be needed*/ /* prevent asking for a small increment at * the begginning of the reception */ rlc_rx_info(inst->rlc_pi, (void *)&info, &len); adv = 1. - (double)inst->left/(inst->B * inst->k); if (adv < .75 && (info.t0 * inst->left) > 2e6 && more < (inst->B * inst->k - inst->netgot)) more = 0; if (more > 0) { /* XXX need some error checking ... */ *rtime = info.t0 * inst->left * drand48() / 2; if (*rtime <= 0) *rtime = RMDP_LAST_RETR_TIM; NDEB(fprintf(stderr, "ask_more ret %d (%d) \n", more, *rtime);) return(more); } return (0); } /* send a continuation request */ static int send_request(void *ides) { static rmdp_cont_pkt_t cp; int rtime; unsigned long howmany; rmdp_inst_t *inst; NDEB(fprintf(stderr, "*** send_request called \n");) /* always uses mfeeso (both for uni and multi) */ if ((inst = getinstance((int)ides)) == NULL) { return 0; } if (inst->mfeeso == -1 && inst->ufeeso == -1 && setup_feed_sock (inst) < 0) rlc_have_error_ (inst->rlc_pi, RMDP_NO_SOCK, NULL); if (!inst->reqpending) return 0; if (inst->reqsent >= RMDP_MAX_RETRIES) { if (inst->err_f) { inst->err_f( (int)ides ); } else { rlc_have_error_(inst->rlc_pi, RMDP_ER_TIMEOUT, NULL); } /* _rmdp_deleteinstance(inst); */ return 0; } howmany = ask_more(inst, &rtime); RMDP_CP_FILL(cp, inst->sessid, howmany, inst->left); if (send(inst->mfeeso, (char *)&cp, RMDP_CP_S, 0) == -1) { rlc_have_error_ (inst->rlc_pi, RMDP_ER_SND, NULL); } inst->reqsent++; if (inst->reqsent < RMDP_MAX_RETRIES) { if (rlc_settimer(RMDP_RETR_TIM, rtime, (CALLBACK)send_request, (void *)ides, 0) < 0) { rlc_have_error_(inst->rlc_pi, RMDP_ER_RETR_TI, NULL); } } else { if (rlc_settimer(RMDP_RETR_TIM, RMDP_LAST_RETR_TIM, (CALLBACK)send_request, (void *)ides, 0) < 0) { rlc_have_error_(inst->rlc_pi, RMDP_ER_RETR_TI, NULL); } } return 0; } static int save(rmdp_inst_t *inst) { int i, j, len = inst->psize; for (i=0; iB; i++) { for (j=0; jk && len > 0; j++) { len=inst->psize; if (inst->flength < len) len=inst->flength; inst->flength -= len; write(inst->fd, inst->allpkts[i][j], len); } } return 0; } static int decode(rmdp_inst_t *inst) { int i, thisn; /* first build allocate a `decoder' */ thisn = max (256, inst->maxn+1); if ((inst->feccode = get_fec(inst->k, thisn)) == NULL) { rlc_have_error_(inst->rlc_pi, RMDP_COD_INST_ERR, NULL); /* _rmdp_deleteinstance(inst); */ return -1; } NDEB (fprintf(stderr, "have decoder with %d %d\n", inst->k, thisn);) for (i=0; iB; i++) { NDEB (for(j=0; jk; j++) fprintf(stderr, "%d ", inst->whichdata[i][j]); fprintf(stderr, " indexes\n"); ) if (fec_decode(inst->feccode, inst->allpkts[i], inst->whichdata[i], inst->psize) != 0) { rlc_have_error_(inst->rlc_pi, RMDP_DECODER_ERR, NULL); /* _rmdp_deleteinstance(inst); */ return -1; } } return 0; } static int setup_feed_sock (rmdp_inst_t *inst) { unsigned long srcaddr; /* always uses mfeeso (both for uni and multi) */ if (inst->mcastfeed) { if ((inst->mfeeso = openssock(inst->addr, inst->port, inst->ttl, 0)) < 0 ) { return (rlc_return_error_ (inst->rlc_pi, RMDP_NO_SOCK, NULL)); } } else if ((srcaddr = rlc_rx_get_src(inst->rlc_pi)) != -1) { if ((inst->mfeeso = openssock(srcaddr, inst->port, inst->ttl, 0)) < 0 ) { return (rlc_return_error_ (inst->rlc_pi, RMDP_NO_SOCK, NULL)); } } else { return (rlc_return_error_ (inst->rlc_pi, RMDP_NO_SOCK, "Cannot send feedback: don't know sender address")); } return 0; } static void unset_feed_sock (rmdp_inst_t *inst) { if (inst->mfeeso != -1) { close(inst->mfeeso); inst->mfeeso = -1; } if (inst->ufeeso != -1) { close(inst->ufeeso); inst->ufeeso = -1; } } } } /* reveived paket handling */ void _rmdp_rx_packet(int ides, int lay, char flags, char *pkt, int size) { int i, ret; int pkt_n, blk_n; rmdp_inst_t *inst; int rtime, newleft; NDEB(fprintf(stderr,"*** got l %d, siz %d\n", lay, size);) if (size <= 0) { NDEB(fprintf(stderr, "--- rx_packet: (lay %d) skipping void (%d) pkt\n", lay, size);) rmdp/layers.c010064400373640000764000000037340656732040300147140ustar00ucaclxvcsstaff00002440000013#include "layers.h" #include "rmdp.h" #include "compat.h" #include "assert.h" #include #include /* * Establish packet organization within layers. * `lay' is the layer index (0..nc-1) and `lidx' the * slot index within the layer. `idx' is the global * slot index. * * Compute pkt# and blk#. If `idx' (global index) == -1 * use `lay' and `lidx' (layer, and layer index). Otherwise * use `idx' and compute `lay' as well, but not `lidx' (XXX). * In this case if lay >= 0 chack that its value matches with * the one computed. * Always return the global index. */ int which_packet(int B, int k, int nc, int idx, int *lay, #if 0 /*ppp*/ int *lidx, int *pkt, int *blk) #else unsigned short *lidx, int *pkt, int *blk) #endif { int x, R = 1<<(nc-1); if (idx < 0) /* compute `idx' from `lay' and `lidx' */ if (*lay == 0) { x = (*lidx) * R + R - 1; } else { x = ((*lidx) * R) / (1<<((*lay)-1)) + R / (1<<(*lay)) - 1; } else { x = idx; } /* * This express the actual packet organization. */ #if 0 /* Mon Dec 8 12:26:13 GMT 1997 */ *pkt = ( x%R + (x/(B*R))*R + x/(k*R*B) )%(k*B); #else *pkt = ( x%R + (x/(B*R))*R + x/(k*R*B) )%(k*R); #endif *blk = ( x + x/max(B, R))%B; if (idx < 0) return (x); /* XXX compute lay, to be made more efficient */ { int div = 2, sub = 0, i = 0; while ( (x-sub)%div != 0) { if (i!=(nc-2)) div *= 2; sub += (1<= 0) { NDEB(fprintf(stderr, "*lay %d computed %d idx %d\n", *lay, nc-i-1, x) ); #if 0 /* doesn't work because we dont take into account bursts */ assert (*lay == nc-i-1); #endif } else *lay = nc-i-1; return (x); } } int compute_k_B(int *k, int *B, int npkts, int nlay) { int R = 1<<(nlay-1); *k = THE_K; if (*k > K_MAX) return(-1); if (R > N_MAX) return(-1); *B = (npkts + *k - 1)/ *k; if (*B < R) { *B = R / (R / *B); } else { *B = ((*B - 1)/R + 1) * R; } return(0); } rmdp/init.c010064400373640000764000000025520656702662500143660ustar00ucaclxvcsstaff00002440000013#include #include #if (!defined(Linux)) #if ( defined(SunOS) && (OSMVER < 5)) #define NULL ((void *)0) #endif #endif #include "fec.h" #include "agent.h" #include "error.h" #include #include "rmdpif.h" #include "rmdp.h" #include "compat.h" #include "init.h" void *rmdp_inst_mngr = NULL; static int rmdp_init_done = 0; static fec_codes_t fec_codes[MAX_RMDP_INSTANCES]; int rmdp_init_() { int i, ret; if (rmdp_init_done) return (0); rmdp_init_done = 1; init_fec(); if (rmdp_error_init_() < 0) return (rlc_internal_set_error_(-1, RMDP_NOERR_H, NULL)); for (i=0; i 0 && fec_codes[i].k == k && fec_codes[i].n == n) { j = i; found = 1; p = fec_codes[i].p; break; } else if (j < 0 && fec_codes[i].inuse == 0) { j = i; } } if (j >= 0 && !found) { p=fec_new (k, n); fec_codes[j].inuse ++; fec_codes[j].k = k; fec_codes[j].n = n; fec_codes[j].p = p; } return p; } rmdp/error.c010064400373640000764000000064720657031367100145530ustar00ucaclxvcsstaff00002440000013/* * error.c -- error handling routines. * * This file is part of * * rmdp -- * * (C) 1998 Lorenzo Vicisano * (vicisano@cs.ucl.ac.uk) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Luigi Rizzo, * Lorenzo Vicisano and other contributors. * 4. Neither the name of the Authors nor the names of other contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include #ifndef NULL #define NULL ((void *)0) #endif #include #include "rmdpif.h" static char *error_msgs[] = { "* rmdp Error: library init error", "* rmdp Error: cannot determine file size", "* rmdp Error: address is not in class D", "* rmdp Error: cannot compute transmission param. for this file size", "* rmdp Error: too mamy protocol instances", "* rmdp Error: no such instance", "* rmdp Error: cannot allocate memory", "* rmdp Error: someting wrong with file size", "* rmdp Error: don't have ui stuff", "* rmdp Error: can't set continuation request timeout", "* rmdp Error: reception timeout", "* rmdp Error: can't send continuation request", "* rmdp Error: can't setup request socket", "* rmdp Error: bad file descriptor", "* rmdp Error: cannot instantiate coder instance", "* rmdp Error: decoder error", "* rmdp Error: no rlc instance id set" }; static char *warn_msgs[] = { "* rmdp Warning: no error messages", "* rmdp Warning: cannot read request", "* rmdp Warning: bad request message", "* rmdp Warning: reception timeout", "* rmdp Warning: cannot write stats" }; int rmdp_error_init_() { if (rlc_register_error_table (error_msgs, RMDP_BASE_ERROR, RMDP_ERROR_SIZE) < 0) return (rlc_internal_set_error_(-1, RMDP_NOERR_H, NULL)); if (rlc_register_error_table (warn_msgs, RMDP_BASE_WARNING, RMDP_WARNING_SIZE) < 0) return (rlc_internal_set_error_(-1, RMDP_NOERR_H, NULL)); return (0); } rmdp/fec.c010064400373640000764000000554750654377256400142000ustar00ucaclxvcsstaff00002440000013/* * fec.c -- forward error correction based on Vandermonde matrices * 980614 * (C) 1997-98 Luigi Rizzo (luigi@iet.unipi.it) * * Portions derived from code by Phil Karn (karn@ka9q.ampr.org), * Robert Morelos-Zaragoza (robert@spectra.eng.hawaii.edu) and Hari * Thirumoorthy (harit@spectra.eng.hawaii.edu), Aug 1995 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. */ /* * The following parameter defines how many bits are used for * field elements. The code supports any value from 2 to 16 * but fastest operation is achieved with 8 bit elements * This is the only parameter you may want to change. */ #ifndef GF_BITS #define GF_BITS 8 /* code over GF(2**GF_BITS) - change to suit */ #endif #include #include #include /* * compatibility stuff */ #ifdef MSDOS /* but also for others, e.g. sun... */ #define NEED_BCOPY #define bcmp(a,b,n) memcmp(a,b,n) #endif #ifdef NEED_BCOPY #define bcopy(s, d, siz) memcpy((d), (s), (siz)) #define bzero(d, siz) memset((d), '\0', (siz)) #endif /* * stuff used for testing purposes only */ #ifdef TEST #define DEB(x) #define DDB(x) x #define DEBUG 0 /* minimal debugging */ #ifdef MSDOS #include struct timeval { unsigned long ticks; }; #define gettimeofday(x, dummy) { (x)->ticks = clock() ; } #define DIFF_T(a,b) (1+ 1000000*(a.ticks - b.ticks) / CLOCKS_PER_SEC ) typedef unsigned long u_long ; typedef unsigned short u_short ; #else /* typically, unix systems */ #include #define DIFF_T(a,b) \ (1+ 1000000*(a.tv_sec - b.tv_sec) + (a.tv_usec - b.tv_usec) ) #endif #define TICK(t) \ {struct timeval x ; \ gettimeofday(&x, NULL) ; \ t = x.tv_usec + 1000000* (x.tv_sec & 0xff ) ; \ } #define TOCK(t) \ { u_long t1 ; TICK(t1) ; \ if (t1 < t) t = 256000000 + t1 - t ; \ else t = t1 - t ; \ if (t == 0) t = 1 ;} u_long ticks[10]; /* vars for timekeeping */ #else #define DEB(x) #define DDB(x) #define TICK(x) #define TOCK(x) #endif /* TEST */ /* * You should not need to change anything beyond this point. * The first part of the file implements linear algebra in GF. * * gf is the type used to store an element of the Galois Field. * Must constain at least GF_BITS bits. * * Note: unsigned char will work up to GF(256) but int seems to run * faster on the Pentium. We use int whenever have to deal with an * index, since they are generally faster. */ #if (GF_BITS < 2 && GF_BITS >16) #error "GF_BITS must be 2 .. 16" #endif #if (GF_BITS <= 8) typedef unsigned char gf; #else typedef unsigned short gf; #endif #define GF_SIZE ((1 << GF_BITS) - 1) /* powers of \alpha */ /* * Primitive polynomials - see Lin & Costello, Appendix A, * and Lee & Messerschmitt, p. 453. */ char *allPp[] = { /* GF_BITS polynomial */ NULL, /* 0 no code */ NULL, /* 1 no code */ "111", /* 2 1+x+x^2 */ "1101", /* 3 1+x+x^3 */ "11001", /* 4 1+x+x^4 */ "101001", /* 5 1+x^2+x^5 */ "1100001", /* 6 1+x+x^6 */ "10010001", /* 7 1 + x^3 + x^7 */ "101110001", /* 8 1+x^2+x^3+x^4+x^8 */ "1000100001", /* 9 1+x^4+x^9 */ "10010000001", /* 10 1+x^3+x^10 */ "101000000001", /* 11 1+x^2+x^11 */ "1100101000001", /* 12 1+x+x^4+x^6+x^12 */ "11011000000001", /* 13 1+x+x^3+x^4+x^13 */ "110000100010001", /* 14 1+x+x^6+x^10+x^14 */ "1100000000000001", /* 15 1+x+x^15 */ "11010000000010001" /* 16 1+x+x^3+x^12+x^16 */ }; /* * To speed up computations, we have tables for logarithm, exponent * and inverse of a number. If GF_BITS <= 8, we use a table for * multiplication as well (it takes 64K, no big deal even on a PDA, * especially because it can be pre-initialized an put into a ROM!), * otherwhise we use a table of logarithms. * In any case the macro gf_mul(x,y) takes care of multiplications. */ static gf gf_exp[GF_SIZE + 1]; /* index->poly form conversion table */ static int gf_log[GF_SIZE + 1]; /* Poly->index form conversion table */ static gf inverse[GF_SIZE+1]; /* inverse of field elem. */ /* inv[\alpha**i]=\alpha**(GF_SIZE-i-1) */ /* * modnn(x) computes x % GF_SIZE, where GF_SIZE is 2**GF_BITS - 1, * without a slow divide. */ static inline gf modnn(int x) { #if 0 /* speedup, saves 1-2% in GF(2^16) */ if (x < GF_SIZE) return x ; /* else if (x < 2*GF_SIZE ) return ( x - GF_SIZE ) ; */ else #endif while (x >= GF_SIZE) { x -= GF_SIZE; x = (x >> GF_BITS) + (x & GF_SIZE); } return x; } #define SWAP(a,b,t) {t tmp; tmp=a; a=b; b=tmp;} /* * gf_mul(x,y) multiplies two numbers. If GF_BITS<=8, it is much * faster to use a multiplication table. * */ #if (GF_BITS <= 8) static gf gf_mul_table[GF_SIZE + 1][GF_SIZE + 1]; #define gf_mul(x,y) gf_mul_table[x][y] static void init_mul_table() { int i, j; for (i=0; i< GF_SIZE+1; i++) for (j=0; j< GF_SIZE+1; j++) gf_mul_table[i][j] = gf_exp[modnn(gf_log[i] + gf_log[j]) ] ; for (j=0; j< GF_SIZE+1; j++) gf_mul_table[0][j] = gf_mul_table[j][0] = 0; } #else static inline gf gf_mul(x,y) { if ( (x) == 0 || (y)==0 ) return 0; return gf_exp[modnn(gf_log[x] + gf_log[y]) ] ; } #define init_mul_table() #endif /* * Generate GF(2**m) from the irreducible polynomial p(X) in p[0]..p[m] * Lookup tables: * index->polynomial form gf_exp[] contains j= \alpha^i; * polynomial form -> index form gf_log[ j = \alpha^i ] = i * \alpha=x is the primitive element of GF(2^m) */ /* * i use malloc so many times, it is easier to put checks all in * one place. */ static void * my_malloc(int sz, char *err_string) { void *p = malloc( sz ); if (p == NULL) { fprintf(stderr, "-- malloc failure allocating %s\n", err_string); exit(1) ; } return p ; } #define NEW_GF_MATRIX(rows, cols) \ (gf *)my_malloc(rows * cols * sizeof(gf), " ## __LINE__ ## " ) /* * initialize the data structures used for computations in GF. */ static void generate_gf(void) { int i; gf mask; char *Pp = allPp[GF_BITS] ; mask = 1; /* x ** 0 = 1 */ gf_exp[GF_BITS] = 0; /* will be updated at the end of the 1st loop */ /* * first, generate the (polynomial representation of) powers of \alpha, * which are stored in gf_exp[i] = \alpha ** i . * At the same time build gf_log[gf_exp[i]] = i . * The first GF_BITS powers are simply bits shifted to the left. */ for (i = 0; i < GF_BITS; i++, mask <<= 1 ) { gf_exp[i] = mask; gf_log[gf_exp[i]] = i; /* * If Pp[i] == 1 then \alpha ** i occurs in poly-repr * gf_exp[GF_BITS] = \alpha ** GF_BITS */ if ( Pp[i] == '1' ) gf_exp[GF_BITS] ^= mask; } /* * now gf_exp[GF_BITS] = \alpha ** GF_BITS is complete, so can als * compute its inverse. */ gf_log[gf_exp[GF_BITS]] = GF_BITS; /* * Poly-repr of \alpha ** (i+1) is given by poly-repr of * \alpha ** i shifted left one-bit and accounting for any * \alpha ** GF_BITS term that may occur when poly-repr of * \alpha ** i is shifted. */ mask = 1 << (GF_BITS - 1 ) ; for (i = GF_BITS + 1; i < GF_SIZE; i++) { if (gf_exp[i - 1] >= mask) gf_exp[i] = gf_exp[GF_BITS] ^ ((gf_exp[i - 1] ^ mask) << 1); else gf_exp[i] = gf_exp[i - 1] << 1; gf_log[gf_exp[i]] = i; } /* * log(0) is not defined, so use a special value * exp(GF_SIZE) is also invalid, because \alpha ^ GF_SIZE = 1, * but one should never use this entry because the table is * accessed with indexes modulo GF_SIZE. So we set gf_exp[GF_SIZE] * to a value consistent with the log() entry. */ gf_log[0] = GF_SIZE ; gf_exp[GF_SIZE] = 0; /* * again special cases. 0 has no inverse. This used to * be initialized to GF_SIZE, but it should make no difference * since noone is supposed to read from here. */ inverse[0] = 0 ; inverse[1] = 1; for (i=2; i<=GF_SIZE; i++) inverse[i] = gf_exp[GF_SIZE-gf_log[i]]; } /* * Various linear algebra operations that i use often. */ /* * addmul() computes dst[] = dst[] + c * src[] * This is used often, so better optimize it! Currently the loop is * unrolled 16 times, a good value for 486 and pentium-class machines. * The case c=0 is also optimized, whereas c=1 is not. These * calls are unfrequent in my typical apps so I did not bother. If * you use them often, then it better to make them inline. */ #define addmul(dst, src, c, sz) \ if (c != 0) addmul1(dst, src, c, sz) #define UNROLL 16 /* 1, 4, 8, 16 */ static void addmul1(gf *dst, gf *src, gf c, int sz) { int i = 0, lim = sz - UNROLL ; #if 0 if (c == 0) /* should't call it with c = 0 ! */ return ; #endif #if (UNROLL > 1) /* unrolling by 8/16 is quite effective on the pentium */ for (; i < lim ; i += UNROLL) { dst[i] ^= gf_mul(c, src[i] ); dst[i+1] ^= gf_mul(c, src[i+1] ); dst[i+2] ^= gf_mul(c, src[i+2] ); dst[i+3] ^= gf_mul(c, src[i+3] ); #if (UNROLL > 4) dst[i+4] ^= gf_mul(c, src[i+4] ); dst[i+5] ^= gf_mul(c, src[i+5] ); dst[i+6] ^= gf_mul(c, src[i+6] ); dst[i+7] ^= gf_mul(c, src[i+7] ); #endif #if (UNROLL > 8) dst[i+8] ^= gf_mul(c, src[i+8] ); dst[i+9] ^= gf_mul(c, src[i+9] ); dst[i+10] ^= gf_mul(c, src[i+10] ); dst[i+11] ^= gf_mul(c, src[i+11] ); dst[i+12] ^= gf_mul(c, src[i+12] ); dst[i+13] ^= gf_mul(c, src[i+13] ); dst[i+14] ^= gf_mul(c, src[i+14] ); dst[i+15] ^= gf_mul(c, src[i+15] ); #endif } #endif for (; i < sz; i++) /* final components */ dst[i] ^= gf_mul(c, src[i] ); } /* * computes C = AB where A is n*k, B is k*m, C is n*m */ static void matmul(gf *a, gf *b, gf *c, int n, int k, int m) { int row, col, i ; for (row = 0; row < n ; row++) { for (col = 0; col < m ; col++) { gf *pa = &a[ row * k ]; gf *pb = &b[ col ]; gf acc = 0 ; for (i = 0; i < k ; i++, pa++, pb += m ) acc ^= gf_mul( *pa, *pb ) ; c[ row * m + col ] = acc ; } } } /* * returns 1 if the square matrix is identiy * (only for test) */ static int is_identity(gf *m, int k) { int row, col ; for (row=0; row 1) { fprintf(stderr, "singular matrix\n"); goto fail ; } } } } if (icol == -1) { fprintf(stderr, "XXX pivot not found!\n"); goto fail ; } found_piv: ++(ipiv[icol]) ; /* * swap rows irow and icol, so afterwards the diagonal * element will be correct. Rarely done, not worth * optimizing. */ if (irow != icol) { for (ix = 0 ; ix < k ; ix++ ) { SWAP( src[irow*k + ix], src[icol*k + ix], gf) ; } } indxr[col] = irow ; indxc[col] = icol ; pivot_row = &src[icol*k] ; c = pivot_row[icol] ; if (c == 0) { fprintf(stderr, "singular matrix 2\n"); goto fail ; } if (c != 1 ) { /* otherwhise this is a NOP */ /* * this is done often , but optimizing is not so * fruitful, at least in the obvious ways (unrolling) */ DEB( pivswaps++ ; ) c = inverse[ c ] ; pivot_row[icol] = 1 ; for (ix = 0 ; ix < k ; ix++ ) pivot_row[ix] = gf_mul(c, pivot_row[ix] ); } /* * from all rows, remove multiples of the selected row * to zero the relevant entry (in fact, the entry is not zero * because we know it must be zero). * (Here, if we know that the pivot_row is the identity, * we can optimize the addmul). */ id_row[icol] = 1; if (bcmp(pivot_row, id_row, k*sizeof(gf)) != 0) { for (p = src, ix = 0 ; ix < k ; ix++, p += k ) { if (ix != icol) { c = p[icol] ; p[icol] = 0 ; addmul(p, pivot_row, c, k ); } } } id_row[icol] = 0; } /* done all columns */ for (col = k-1 ; col >= 0 ; col-- ) { if (indxr[col] <0 || indxr[col] >= k) fprintf(stderr, "AARGH, indxr[col] %d\n", indxr[col]); else if (indxc[col] <0 || indxc[col] >= k) fprintf(stderr, "AARGH, indxc[col] %d\n", indxc[col]); else if (indxr[col] != indxc[col] ) { for (row = 0 ; row < k ; row++ ) { SWAP( src[row*k + indxr[col]], src[row*k + indxc[col]], gf) ; } } } error = 0 ; fail: free(indxc); free(indxr); free(ipiv); free(id_row); free(temp_row); return error ; } /* * fast code for inverting a vandermonde matrix. * XXX NOTE: It assumes that the matrix * is not singular and _IS_ a vandermonde matrix. Only uses * the second column of the matrix, containing the p_i's. * * Algorithm borrowed from "Numerical recipes in C" -- sec.2.8, but * largely revised for my purposes. * p = coefficients of the matrix (p_i) * q = values of the polynomial (known) */ int invert_vdm(gf *src, int k) { int i, j, row, col ; gf *b, *c, *p; gf t, xx ; if (k == 1) /* degenerate case, matrix must be p^0 = 1 */ return 0 ; /* * c holds the coefficient of P(x) = Prod (x - p_i), i=0..k-1 * b holds the coefficient for the matrix inversion */ c = NEW_GF_MATRIX(1, k); b = NEW_GF_MATRIX(1, k); p = NEW_GF_MATRIX(1, k); for ( j=1, i = 0 ; i < k ; i++, j+=k ) { c[i] = 0 ; p[i] = src[j] ; /* p[i] */ } /* * construct coeffs. recursively. We know c[k] = 1 (implicit) * and start P_0 = x - p_0, then at each stage multiply by * x - p_i generating P_i = x P_{i-1} - p_i P_{i-1} * After k steps we are done. */ c[k-1] = p[0] ; /* really -p(0), but x = -x in GF(2^m) */ for (i = 1 ; i < k ; i++ ) { gf p_i = p[i] ; /* see above comment */ for (j = k-1 - ( i - 1 ) ; j < k-1 ; j++ ) c[j] ^= gf_mul( p_i, c[j+1] ) ; c[k-1] ^= p_i ; } for (row = 0 ; row < k ; row++ ) { /* * synthetic division etc. */ xx = p[row] ; t = 1 ; b[k-1] = 1 ; /* this is in fact c[k] */ for (i = k-2 ; i >= 0 ; i-- ) { b[i] = c[i+1] ^ gf_mul(xx, b[i+1]) ; t = gf_mul(xx, t) ^ b[i] ; } for (col = 0 ; col < k ; col++ ) src[col*k + row] = gf_mul(inverse[t], b[col] ); } free(c) ; free(b) ; free(p) ; return 0 ; } /* * This section contains the proper FEC encoding/decoding routines. * The encoding matrix is computed starting with a Vandermonde matrix, * and then transforming it into a systematic matrix. */ struct fec_parms { int k, n ; /* parameters of the code */ gf *enc_matrix ; } ; void fec_free(struct fec_parms *p) { free(p->enc_matrix); free(p); } /* * create a new encoder, returning a descriptor. This contains k,n and * the encoding matrix. */ struct fec_parms * fec_new(int k, int n) { int row, col ; gf *p, *tmp_m ; struct fec_parms *retval ; if (k > GF_SIZE + 1 || n > GF_SIZE + 1 || k > n ) { fprintf(stderr, "Invalid parameters k %d n %d GF_SIZE %d\n", k, n, GF_SIZE ); return NULL ; } retval = my_malloc(sizeof(struct fec_parms), "new_code"); retval->k = k ; retval->n = n ; retval->enc_matrix = NEW_GF_MATRIX(n, k); tmp_m = NEW_GF_MATRIX(n, k); /* * fill the matrix with powers of field elements, starting from 0. * The first row is special, cannot be computed with exp. table. */ tmp_m[0] = 1 ; for (col = 1; col < k ; col++) tmp_m[col] = 0 ; for (p = tmp_m + k, row = 0; row < n-1 ; row++, p += k) { for ( col = 0 ; col < k ; col ++ ) p[col] = gf_exp[modnn(row*col)]; } /* * quick code to build systematic matrix: invert the top * k*k vandermonde matrix, multiply right the bottom n-k rows * by the inverse, and construct the identity matrix at the top. */ TICK(ticks[3]); invert_vdm(tmp_m, k); /* much faster than invert_mat */ matmul(tmp_m + k*k, tmp_m, retval->enc_matrix + k*k, n - k, k, k); /* * the upper matrix is I so do not bother with a slow multiply */ bzero(retval->enc_matrix, k*k*sizeof(gf) ); for (p = retval->enc_matrix, col = 0 ; col < k ; col++, p += k+1 ) *p = 1 ; free(tmp_m); TOCK(ticks[3]); DDB(fprintf(stderr, "--- %ld us to build encoding matrix\n", ticks[3]);) DEB(pr_matrix(retval->enc_matrix, n, k, "encoding_matrix");) return retval ; } void init_fec() { TICK(ticks[0]); generate_gf(); TOCK(ticks[0]); DDB(fprintf(stderr, "generate_gf took %ldus\n", ticks[0]);) TICK(ticks[0]); init_mul_table(); TOCK(ticks[0]); DDB(fprintf(stderr, "init_mul_table took %ldus\n", ticks[0]);) } /* * fec_encode accepts as input pointers to n data packets of size sz, * and produces as output a packet pointed to by fec, computed * with index "index". */ void fec_encode(struct fec_parms *code, gf *src[], gf *fec, int index, int sz) { int i, k = code->k ; gf *p ; if (GF_BITS > 8) sz /= 2 ; if (index < k) bcopy(src[index], fec, sz*sizeof(gf) ) ; else if (index < code->n) { p = &(code->enc_matrix[index*k] ); bzero(fec, sz*sizeof(gf)); for (i = 0; i < k ; i++) addmul(fec, src[i], p[i], sz ) ; } else fprintf(stderr, "Invalid index %d (max %d)\n", index, code->n - 1 ); } /* * shuffle move src packets in their position */ static int shuffle(gf *pkt[], int index[], int k) { int i; for ( i = 0 ; i < k ; ) { if (index[i] >= k || index[i] == i) i++ ; else { /* * put pkt in the right position (first check for conflicts). */ int c = index[i] ; if (index[c] == c) { DEB(fprintf(stderr, "\nshuffle, error at %d\n", i);) return 1 ; } SWAP(index[i], index[c], int) ; SWAP(pkt[i], pkt[c], gf *) ; } } DDB( /* just test that it works... */ for ( i = 0 ; i < k ; i++ ) { if (index[i] < k && index[i] != i) { fprintf(stderr, "shuffle: after\n"); for (i=0; ik ; gf *p, *matrix = NEW_GF_MATRIX(k, k); TICK(ticks[9]); for (i = 0, p = matrix ; i < k ; i++, p += k ) { #if 1 /* this is simply an optimization, not very useful indeed */ if (index[i] < k) { bzero(p, k*sizeof(gf) ); p[i] = 1 ; } else #endif if (index[i] < code->n ) bcopy( &(code->enc_matrix[index[i]*k]), p, k*sizeof(gf) ); else { fprintf(stderr, "decode: invalid index %d (max %d)\n", index[i], code->n - 1 ); free(matrix) ; return NULL ; } } TICK(ticks[9]); if (invert_mat(matrix, k)) { free(matrix); matrix = NULL ; } TOCK(ticks[9]); return matrix ; } /* * fec_decode receives as input a vector of packets, the indexes of * packets, and produces the correct vector as output. * * Input: * code: pointer to code descriptor * pkt: pointers to received packets. They are modified * to store the output packets (in place) * index: pointer to packet indexes (modified) * sz: size of each packet */ int fec_decode(struct fec_parms *code, gf *pkt[], int index[], int sz) { gf *m_dec ; gf **new_pkt ; int row, col ; int k = code->k ; if (GF_BITS > 8) sz /= 2 ; if (shuffle(pkt, index, k)) /* error if true */ return 1 ; m_dec = build_decode_matrix(code, pkt, index); if (m_dec == NULL) return 1 ; /* error */ /* * do the actual decoding */ new_pkt = my_malloc (k * sizeof (gf * ), "new pkt pointers" ); for (row = 0 ; row < k ; row++ ) { if (index[row] >= k) { new_pkt[row] = my_malloc (sz * sizeof (gf), "new pkt buffer" ); bzero(new_pkt[row], sz * sizeof(gf) ) ; for (col = 0 ; col < k ; col++ ) addmul(new_pkt[row], pkt[col], m_dec[row*k + col], sz) ; } } /* * move pkts to their final destination */ for (row = 0 ; row < k ; row++ ) { if (index[row] >= k) { bcopy(new_pkt[row], pkt[row], sz*sizeof(gf)); free(new_pkt[row]); } } free(new_pkt); free(m_dec); return 0; } /*********** end of FEC code -- beginning of test code ************/ #if (TEST || DEBUG) void test_gf() { int i ; /* * test gf tables. Sufficiently tested... */ for (i=0; i<= GF_SIZE; i++) { if (gf_exp[gf_log[i]] != i) fprintf(stderr, "bad exp/log i %d log %d exp(log) %d\n", i, gf_log[i], gf_exp[gf_log[i]]); if (i != 0 && gf_mul(i, inverse[i]) != 1) fprintf(stderr, "bad mul/inv i %d inv %d i*inv(i) %d\n", i, inverse[i], gf_mul(i, inverse[i]) ); if (gf_mul(0,i) != 0) fprintf(stderr, "bad mul table 0,%d\n",i); if (gf_mul(i,0) != 0) fprintf(stderr, "bad mul table %d,0\n",i); } } #endif /* TEST */ e correct. Rarely done, not worth * optimizing. */ if (irow != icol) { for (ix = 0 ; ix < k ; ix++ ) { SWAP( src[irow*k + ix], src[icol*k + ix], gf) ; } } indxr[col] = irow ; rmdp/utils.c010064400373640000764000000034110657026406000145450ustar00ucaclxvcsstaff00002440000013#include #include #include #include #include #if __STDC__ #include #else #include #endif #include #include /* #include "compat.h" */ #include "agent.h" #include "utils.h" #if __STDC__ void rmdp_my_error (int rmdp_i, char const *fmt, ...) #else void rmdp_my_error (rmdp_i, fmt, va_alist) int rmdp_i; char *fmt; va_dcl #endif { va_list ap; char buf[1024]; rmdp_inst_t *inst; int rlc_pi; #if __STDC__ va_start(ap, fmt); #else va_start(ap); #endif #if 1 if (rmdp_i >= 0 && (inst = (rmdp_inst_t *)_rlc_getinstance(rmdp_i, rmdp_inst_mngr)) != NULL) rlc_pi = inst->rlc_pi; else rlc_pi = -1; vsprintf(buf, fmt, ap); rlc_have_error_ (rlc_pi, -1, buf); #else vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); #endif va_end(ap); exit(1); } unsigned long rmdp_compute_sessid_() { short seed[3]; struct timeval getime; gettimeofday(&getime, NULL); seed[0] = (short)getime.tv_usec; seed[1] = (short)(getime.tv_usec*0xffff); seed[2] = (short)getime.tv_sec; return(nrand48(seed)); } /* address parsing */ int rmdp_parse_addr(char *s, char *a, int addrlen, short *p, char *msg) { char *s1, *q = a ; strncpy(q, s, addrlen); s1=strchr(q,'/'); if (s1) { *p=atoi(s1+1); *s1='\0'; /* NDEB(printf("%s session [%s] [%d]\n", msg, q, ntohs(*p));) */ } else return -1; return 0; } int rmdp_n_parse_addr(char *s, char *a, int addrlen, short *p, int *ttl, char *msg) { char *s1, *q = a ; strncpy(q, s, addrlen); s1=strchr(q,'/'); if (s1) { s1=strchr(s1+1, '/'); if (s1) { *ttl = atoi(s1+1); *s1='\0'; } else *ttl = -1; } return (rmdp_parse_addr(a, a, addrlen, p, msg)); } rmdp/rmdp.c010064400373640000764000000351320657032111000143420ustar00ucaclxvcsstaff00002440000013#include #include #include #include #include #include #include #include #include #include #include #include "rmdpif.h" #include "fec.h" #include "rmdp.h" #include "layers.h" #include "sender.h" #include "receiver.h" #include "agent.h" #include "init.h" #include "utils.h" #define getinstance(i) ((rmdp_inst_t *)_rlc_getinstance(i, rmdp_inst_mngr)) #ifdef HAVE_UI extern char RMDP_TCL_SCRIPT[]; extern char RMDP_RX_TCL_SCRIPT[]; extern char RMDP_TX_TCL_SCRIPT[]; #endif /*++++ Creates a new protocol instance assigning a local protocol instance identifier. Params: - isreceiver: 1 means that this is a receiver, 0 a sender. Returns: - the protocol instance id, on success. - a negative value on failure: */ int rmdp_new (int isreceiver) { int ret; rmdp_inst_t *se; /* ** global library init */ if (rmdp_init_() < 0) return (rlc_return_error_(-1, RMDP_INITERR, NULL)); /* ** sender init */ if (_rmdp_sender_init() < 0) return (rlc_return_error_(-1, RMDP_INITERR, NULL)); /* ** receiver init */ if (_rmdp_receiver_init() < 0) return (rlc_return_error_(-1, RMDP_INITERR, NULL)); /** ** allocate session descriptor **/ if (NULL == (se = calloc(1, sizeof(rmdp_inst_t)))) { return (rlc_return_error_ (-1, RMDP_ALLOC_ERROR, "* rmdp: Cannot allocate session descriptor")); } if (isreceiver) { se->sessid = 0; /* 0 means not assigned, if start receiving * like that, it will pick up the sessid in * the first valid packet and stick to that */ } else { se->sessid = rmdp_compute_sessid_(); } se->alldata = NULL; se->B = se->k = se->npkts = se->flength = 0; se->psize = RMDP_PKT_SIZE; /* in the receiver will be set to the right * value at the first received packet */ se->feccode = NULL; se->rlc_pi = -1; se->have_gui = 0; se->addr = 0; se->port = 0; se->ufeeso = -1; se->mfeeso = -1; se->fd = -1; if (isreceiver) se->isreceiver = 1; else se->isreceiver = 0; /* sender specific ... */ se->nlay = RMDP_NLAY; se->idxs = NULL; se->allpkts = NULL; se->sparepkt = NULL; se->pkts_left = se->init_left = 0; if ((se->idxs = (unsigned short *)calloc(se->nlay, sizeof(unsigned short))) == NULL) { _rmdp_deleteinstance(se); return (rlc_return_error_(-1, RMDP_ALLOC_ERROR, "* rmdp: Cannot file data structure")); } se->stafd = -1; /* receiver specific ... */ se->ttl = 0; se->whichdata = NULL; se->countdata = NULL; se->maxn = se->missingblocks = se-> duppackets = 0; se->oldtotgot = se->totgot = se->netgot = 0; se->speedf = 1.; se->end_f = NULL; se->err_f = NULL; se->reqpending = se->reqsent = 0; se->recpercent = 0; se->left = 0; se->mcastfeed = 0; /* default unicast ! */ if ((ret = _rlc_insert_instance ((instance_des_t *)se, rmdp_inst_mngr)) < 0) { _rmdp_deleteinstance(se); return (rlc_return_error_(-1, RMDP_TOOMANY_INST, "rmdp Error: too many" " instances")); } return (ret); } /*++++ Provides and input/output descriptor associated with the file being transmitted/received (sender/receiver). In the sender the input descriptor must be able to provide the file length, using fstat(). Params: - pi: protocol instance identifier. - fd: input/output file descriptor. Returns: - 0 on success; - a negative value on failure: */ int rmdp_set_io (int pi, int fd) { int ret; rmdp_inst_t *se; if ((se = getinstance(pi)) == NULL) { return (rlc_return_error_(-1, RMDP_NOSUCH_INST, NULL)); } /** ** chek output file descriptor **/ if (fd < 0) { return (rlc_return_error_ (se->rlc_pi, RMDP_OUT_FILE_ERR, NULL)); } if (!se->isreceiver && (ret = _rmdp_tx_read(pi, fd)) < 0) { return (rlc_return_error_(se->rlc_pi, ret, NULL)); } se->fd = fd; return (0); } /*++++ Provides multicast address/port for the feedback channel. Params: - pi: protocol instance identifier. - adds: data structures defined in "rmdpif.h", containing address (host order), port and ttl (used in the receiver only). Returns: - 0 on success; - a negative value on failure: */ int rmdp_set_addr (int pi, rmdp_addr_t *adds) { rmdp_inst_t *se; if ((se = getinstance(pi)) == NULL) { return (rlc_return_error_(-1, RMDP_NOSUCH_INST, NULL)); } if (!IN_CLASSD(adds->addr)) return rlc_return_error_(se->rlc_pi, RMDP_NOMCAST_ADDR, NULL); se->addr = htonl(adds->addr); se->port = htons(adds->port); se->ttl = adds->ttl; #if 0 if ( se->isreceiver && (se->mfeeso = openssock(se->addr, se->port, adds->ttl, 0)) < 0 ) { return (rlc_return_error_ (se->rlc_pi, RMDP_NO_SOCK, NULL)); } #endif return (0); } /*++++ Set the flow instance id. In the sender, the instance id must be unique within the sender host. If not set using this function, it will be generated internally. In the receiver, only incoming packet that belong to this instance will be considered. It should be called before starting the reception. If the instance id is not set, the one found in the first valid packet will be used. Params: - pi: protocol instance identifier. - id: the flow instance id. Returns: - 0 on success; - a negative value on failure: */ int rmdp_set_id (int pi, unsigned long id) { rmdp_inst_t *inst; if ((inst = getinstance(pi)) == NULL) { return (rlc_return_error_(-1, RMDP_NOSUCH_INST, NULL)); } inst->sessid = id; return (0); } /*++++ Get the flow instance id. Params: - pi: protocol instance identifier. - id: ponter to a memory area that will be set to the value of the flow instance id. Returns: - 0 on success; - a negative value on failure: */ int rmdp_get_id (int pi, unsigned long *id) { rmdp_inst_t *inst; if ((inst = getinstance(pi)) == NULL) { return (rlc_return_error_(-1, RMDP_NOSUCH_INST, NULL)); } *id = inst->sessid; return (0); } /*++++ Retrieves a reference to the function that gets called to provide the outgoing/consume the incoming data packets. The function returned will be of type typedef void (* rmdp_rx_packet_t) (int pi, int lay, char flags, char *p, int size); in the receiver, and typedef int (* rmdp_tx_packet_t) (int pi, int lay, char flags, char **p); in the sender. Params: - pi: protocol instance identifier. - f: ponter to a memory area that will be set to the ponter of the function. Returns: - 0 on success; - a negative value on failure: */ int rmdp_get_f (int pi, void **f) { rmdp_inst_t *inst; if ((inst = getinstance(pi)) == NULL) { return (rlc_return_error_(-1, RMDP_NOSUCH_INST, NULL)); } if (inst->isreceiver) *f = (void *)_rmdp_rx_packet; else *f = (void *)_rmdp_tx_packet; return (0); } /*++++ Deletes a protocol instance and claims back the storage used. Params: - pi: protocol instance identifier. Returns: - 0 on success; - a negative value on failure: */ int rmdp_delete (int pi) { _rmdp_deleteinstance(getinstance(pi)); return (0); } /*++++ Retrieves the rmdp packet size (rmdp payload size + rmdp header). Params: - pi: protocol instance identifier. Returns: - the packet size on success; - a negative value on failure: */ int rmdp_get_psize (int pi) { rmdp_inst_t *inst; if ((inst = getinstance(pi)) == NULL) { return (rlc_return_error_(-1, RMDP_NOSUCH_INST, NULL)); } return ( inst->psize + RMDP_H_S ); } /*++++ Registers the associated rlc instance ID. This function is ininfluent in the sender. Params: - pi: protocol instance identifier. Returns: - 0 on success; - a negative value on failure: */ int rmdp_set_rlc (int pi, int rlc_pi) { rmdp_inst_t *inst; if ((inst = getinstance(pi)) == NULL) { return (rlc_return_error_(-1, RMDP_NOSUCH_INST, NULL)); } inst->rlc_pi = rlc_pi; return (0); } /*++++ Gets the associated rlc instance ID, previously set with rmdp_set_rlc. Params: - pi: protocol instance identifier. - id: ponter to a memory area that will be set to the value of the rlc instance id. Returns: - 0 on success; - a negative value on failure: */ int rmdp_get_rlc (int pi, unsigned long *id) { rmdp_inst_t *inst; if ((inst = getinstance(pi)) == NULL) { return (rlc_return_error_(-1, RMDP_NOSUCH_INST, NULL)); } *id = inst->rlc_pi; return 0; } /*++++ Enables the UI capability. Use only after rmdp_set_rlc is called. It has no effect unless both rmdp and rlc have been compiled with the proper flag (HAVE_UI). Params: - pi: protocol instance identifier. Returns: - 0 on success; - a negative value on failure: */ int rmdp_enable_gui (int pi) { rmdp_inst_t *inst; if ((inst = getinstance(pi)) == NULL) { return (rlc_return_error_(-1, RMDP_NOSUCH_INST, NULL)); } #ifdef HAVE_UI if ( rlc_gui_loadtcl(inst->rlc_pi, RMDP_TCL_SCRIPT) < 0 || (inst->isreceiver && rlc_gui_loadtcl(inst->rlc_pi, RMDP_RX_TCL_SCRIPT) < 0) || (!inst->isreceiver && rlc_gui_loadtcl(inst->rlc_pi, RMDP_TX_TCL_SCRIPT) < 0) ) { return (rlc_return_error_(inst->rlc_pi, RMDP_NO_UI, NULL)); } else inst->have_gui = 1; DEB(fprintf(stderr, "Yes, we have GUI\n");) return (0); #else return (rlc_return_error_(inst->rlc_pi, RMDP_NO_UI, NULL)); #endif } /*++++ Sets the application name in the UI. Use only after rmdp_set_rlc is called. Params: - pi: protocol instance identifier. - name: the application name. Returns: - 0 on success; - a negative value on failure: */ int rmdp_set_name (int pi, char *name) { rmdp_inst_t *inst; #ifdef HAVE_UI char *tmp; #endif if ((inst = getinstance(pi)) == NULL) { return (rlc_return_error_ (-1, RMDP_NOSUCH_INST, NULL)); } #ifdef HAVE_UI if (!inst->have_gui) return (rlc_return_error_ (inst->rlc_pi, RMDP_NO_UI, NULL)); if (inst->rlc_pi == -1) return (rlc_return_error_ (inst->rlc_pi, RMDP_NO_RLC_ID, NULL)); if ((tmp = malloc(strlen(name) + strlen("wm title . \"rmdp: ") + strlen("\"") + 1)) == NULL) { return (rlc_return_error_ (inst->rlc_pi, RMDP_ALLOC_ERROR, NULL)); } strcpy (tmp, "wm title . \"rmdp: "); strcat (tmp, name); strcat (tmp, "\""); rlc_gui_loadtcl(inst->rlc_pi, tmp); return(0); #else return (rlc_return_error_ (inst->rlc_pi, RMDP_NO_UI, NULL)); #endif } /*++++ Set the function to be called when the reception/transmission terminates successfully. Params: - pi: protocol instance identifier. - end_f: the end callback function. It is of type typedef void (*rmdp_end_f) (int pi, int result); Returns: - 0 on success; - a negative value on failure: */ int rmdp_set_end_callback (int pi, rmdp_end_f end_f) { rmdp_inst_t *inst; if ((inst = getinstance(pi)) == NULL) { return (rlc_return_error_(-1, RMDP_NOSUCH_INST, NULL)); } inst->end_f = end_f; return (0); } /*++++ Enable receivers' stat reports. In the sender provides rmdp with a file descriptor to write receivers' stat reports. In the receiver enables stat reports generation if stafd > 0. If stafd < 0 generation/accumulation is disabled. Params: - pi: protocol instance identifier. - stafd: In the sender: file descriptor. Must be writable. In the receiver enable (>0) and disable (<0) stats reports generation. Returns: - 0 on success. - a negative value on failure: */ int rmdp_set_stat_reports (int pi, int stafd) { rmdp_inst_t *inst; if ((inst = getinstance(pi)) == NULL) { return (rlc_return_error_(-1, RMDP_NOSUCH_INST, NULL)); } inst->stafd = stafd; if (inst->isreceiver && inst->rlc_pi >= 0) { if (stafd > 0) return rlc_rx_set_stats_deliver_f (inst->rlc_pi, pi, _rmdp_send_stats, RMDP_STATS_PAYSIZE); else return rlc_rx_set_stats_deliver_f (inst->rlc_pi, pi, NULL, RMDP_STATS_PAYSIZE); } return ( 0 ); } void _rmdp_deallocation(rmdp_inst_t *inst) { int i, j; if (!inst) return; if (inst->alldata) { for (i=0; i<(inst->B); i++) { if (inst->alldata[i]) for (j=0; j<(inst->k); j++) if (inst->alldata[i][j]) free(inst->alldata[i][j]); free(inst->alldata[i]); } free(inst->alldata); } if (inst->allpkts) { for (i=0; i<(inst->B); i++) { if (inst->allpkts[i]) free(inst->allpkts[i]); } free(inst->allpkts); } if (inst->whichdata) { for (i=0; i<(inst->B); i++) { if (inst->whichdata[i]) free(inst->whichdata[i]); } free(inst->whichdata); } if (inst->sparepkt) free(inst->sparepkt); if (inst->countdata) free(inst->countdata); } void _rmdp_deleteinstance(rmdp_inst_t *inst) { if (!inst) return; if (inst->mfeeso != -1 && !inst->isreceiver) { rlc_deletechan(inst->mfeeso); close (inst->mfeeso); inst->mfeeso = -1; } if (inst->ufeeso != -1 && !inst->isreceiver) { rlc_deletechan(inst->ufeeso); close (inst->ufeeso); inst->ufeeso = -1; } _rmdp_deallocation(inst); _rlc_return_instance ((instance_des_t *) inst, rmdp_inst_mngr); free(inst); } int _rmdp_allocation(rmdp_inst_t *se) { int i,j; /* allocate file buffers pointers only */ if (NULL == (se->alldata = (void ***)calloc(se->B, sizeof(void *))) || NULL == (se->allpkts = (void ***)calloc(se->B, sizeof(void *))) || NULL == (se->countdata = (int *)calloc(se->B, sizeof(int))) || NULL == (se->whichdata = (int **)calloc(se->B, sizeof(int *))) ) { return (rlc_return_error_(se->rlc_pi, RMDP_ALLOC_ERROR, "* rmdp: Cannot allocate file data structure")); } for (i=0; i<(se->B); i++) { if (NULL == (se->alldata[i] = (void **)calloc((se->k), sizeof(void *))) || NULL == (se->allpkts[i] = (void **)calloc((se->k), sizeof(void *))) || NULL == (se->whichdata[i] = (int *)calloc((se->k), sizeof(int))) ) { return (rlc_return_error_(se->rlc_pi, RMDP_ALLOC_ERROR, "* rmdp: Cannot allocate file data structure")); } for (j=0; j<(se->k); j++) { se->whichdata[i][j] = -1; se->alldata[i][j] = se->allpkts[i][j] = NULL; #if 0 /* NO HERE */ if (NULL ==(se->alldata[i][j] = (char *)calloc(1, se->psize+RMDP_H_S))) { return (rlc_return_error_(se->rlc_pi, RMDP_ALLOC_ERROR, "* rmdp: Cannot allocate file data structure")); } se->allpkts[i][j] = RMDP_DATA(se->alldata[i][j]); if (!done && (read(fd, se->allpkts[i][j], se->psize)) != se->psize) { done = 1; } #endif } } if (NULL ==(se->sparepkt = (char *)calloc(1, se->psize+RMDP_H_S))) { return (rlc_return_error_(se->rlc_pi, RMDP_ALLOC_ERROR, "* rmdp: Cannot file allocate data structure")); } return (0); } ->port); se->ttl = adds->ttl; #if 0 if ( se->isreceiver && (se->mfeeso = openssock(se->addr, se->port, adds->ttl, 0)) < 0 ) { return (rlc_return_error_ (se->rlc_pi, RMDP_NO_SOCK, NULL)); } #endif return (0); } /*++++ Set the flow instance id. In the sender, the instance id must be unique within the sender host. If not set using this function, it will be generated internally. In the receiver,rmdp/rmdpif.h010064400373640000764000000053670657031551300147070ustar00ucaclxvcsstaff00002440000013#ifndef RMDP_RMDPIF_H #define RMDP_RMDPIF_H #define RMDP_LEFT_INFINITE 0xffffffff #define RMDP_BASE_ERROR -200 #define RMDP_ERROR_SIZE 17 /* ** Error codes. */ #define RMDP_INITERR -200 #define RMDP_STAT_ERROR -201 #define RMDP_NOMCAST_ADDR -202 #define RMDP_COMPUTE_K -203 #define RMDP_TOOMANY_INST -204 #define RMDP_NOSUCH_INST -205 #define RMDP_ALLOC_ERROR -206 #define RMDP_DATA_SIZE -207 #define RMDP_NO_UI -208 #define RMDP_ER_RETR_TI -209 #define RMDP_ER_TIMEOUT -210 #define RMDP_ER_SND -211 #define RMDP_NO_SOCK -212 #define RMDP_OUT_FILE_ERR -213 #define RMDP_COD_INST_ERR -214 #define RMDP_DECODER_ERR -215 #define RMDP_NO_RLC_ID -216 #define RMDP_BASE_WARNING 2000 #define RMDP_WARNING_SIZE 5 /* ** Warning codes. */ #define RMDP_NOERR_H 2000 /* Warning: no error messages */ #define RMDP_CANT_READ_REQ 2001 /* Warning: cannot read request */ #define RMDP_BAD_REQ 2002 /* Warning: bad request messages */ #define RMDP_TIMEOUT_WAR 2003 /* reception timeout warning */ #define RMDP_CANT_WRITE_STATS 2004 /* cannot write stats warning */ typedef struct _rmdp_addr_t { unsigned long addr; short port; short ttl; } rmdp_addr_t; typedef int (*rmdp_tx_packet_t) (int pi, int lay, char flags, char **p); typedef void (*rmdp_rx_packet_t) (int pi, int lay, char flags, char *p, int size); /** called when when the reception/transmission terminates successfully **/ typedef void (*rmdp_end_f) (int pi, int result); /** called when when the reception terminates because of a timeout **/ typedef void (*rmdp_rx_err_f) (int pi); /* ** Main routines ... */ int rmdp_new (int isreceiver); int rmdp_set_addr (int pi, rmdp_addr_t *adds); int rmdp_set_io (int pi, int fd); int rmdp_set_id (int pi, unsigned long id); int rmdp_get_id (int pi, unsigned long *id); int rmdp_get_f (int pi, void **f); int rmdp_delete (int pi); int rmdp_get_psize (int pi); int rmdp_get_rlc (int pi, unsigned long *id); int rmdp_set_rlc (int pi, int rlc_pi); int rmdp_enable_gui (int pi); int rmdp_set_name (int pi, char *name); int rmdp_set_end_callback (int pi, rmdp_end_f f); int rmdp_set_stat_reports (int pi, int stafd); /* ** sender side routines */ int rmdp_get_nlay (int pi); int rmdp_get_left (int pi); int rmdp_incr_left (int pi, int incr); /* ** receiver side routines */ int rmdp_rx_set_err_callback (int pi, rmdp_rx_err_f f); int rmdp_rx_enable_multifeed (int pi, int multifeed); /* ... must add gui stuff */ /* ** utils function */ int rmdp_parse_addr(char *s, char *a, int addrlen, short *p, char *msg); int rmdp_n_parse_addr(char *s, char *a, int addrlen, short *p, int *ttl, char *msg); #if __STDC__ void rmdp_my_error (int rmdp_i, char const *fmt, ...); #else void rmdp_my_error (rmdp_i, fmt, va_alist) int rmdp_i; char *fmt; va_dcl; #endif #endif /* RMDP_RMDPIF_H */ rmdp/rmdp.h010064400373640000764000000035560657032075000143650ustar00ucaclxvcsstaff00002440000013#ifndef RMDP_RMDP_H #define RMDP_RMDP_H #include "compat.h" #ifdef DEBUGE #define DEB(x) {x;} #else #define DEB(x) #endif #define NDEB(x) #define MAX_RMDP_INSTANCES 128 #define RMDP_PKT_SIZE 256 #define RMDP_BASE_RATE 16*1024 #define RMDP_NLAY 5 #define THE_K 8 #define RMDP_MAX_RETRIES 5 /* maximum # of continuation requests * before aborting */ #define RMDP_LAST_RETR_TIM 1000000 /*++++ * Data packet (actually is RLC payload) */ typedef struct _rmdp_header_t { unsigned short B; unsigned short k; unsigned short the_B; unsigned short the_k; unsigned long sessid; unsigned long flength; /* in bytes !! */ unsigned long left; /* left in the base layer */ } rmdp_header_t; #define RMDP_H_S sizeof(rmdp_header_t) #define RMDP_DATA(p) ((void *)((char *)(p)+RMDP_H_S)) #define RMDP_DATA_2_P(p) ((void *)((char *)(p)-RMDP_H_S)) #define RMDP_H_P(p) ((rmdp_header_t *)(p)) /*++++ * Continuation request packet (UDP payload) * and other feedback... */ #define COMM_FEEDHEAD \ unsigned long magic; \ unsigned long sessid; \ unsigned long extension; /* packet on the base layer */ \ unsigned long wasleft; /* left at the req. time */ typedef struct _rmdp_cont_pkt_t { COMM_FEEDHEAD } rmdp_cont_pkt_t; typedef struct _rmdp_feed_pkt_t { COMM_FEEDHEAD unsigned long type; } rmdp_feed_pkt_t; #define RMDP_STATS_PAYSIZE 1024 #define RMDP_L_MAGIC 0x15a85afe #define RMDP_FEED_RLC_STATS 0x15af33dc #define RMDP_CP_S sizeof(rmdp_cont_pkt_t) #define RMDP_CP_P(p) ((rmdp_cont_pkt_t *)(p)) #define RMDP_CP_FILL(p, sid, ext, lef) \ { \ (p).magic = htonl(RMDP_L_MAGIC); \ (p).sessid = htonl(sid); \ (p).extension = htonl(ext); \ (p).wasleft = htonl(lef); \ } #define RMDP_FEE_RLC_FILL(p, sid) \ { \ RMDP_CP_FILL(p, sid, 0, 0); \ (p).type = htonl(RMDP_FEED_RLC_STATS); \ } #endif /* RMDP_RMDP_H */ rmdp/sender.h010064400373640000764000000006730657033136400147030ustar00ucaclxvcsstaff00002440000013#ifndef RMDP_SENDER_H #define RMDP_SENDER_H int _rmdp_sender_init(); int _rmdp_tx_read(int des, int fd); typedef struct _stats_rec_t { unsigned long time; /* reception time */ unsigned long fromip; /* sender ip */ unsigned short fromport; /* sender port */ unsigned short padding; unsigned long type; /* net order */ unsigned long size; /* net order */ /* size bytes of data follows */ } stats_rec_t; #endif /* RMDP_SENDER_H */ rmdp/init.h010064400373640000764000000004100655067247400143630ustar00ucaclxvcsstaff00002440000013#ifndef RMDP__INIT_H #define RMDP__INIT_H #include "compat.h" int rmdp_init_(); void * get_fec(int k, int n); /*++++ * Fec code in use descriptor */ typedef struct _fec_codes_t { int k; int n; int inuse; void * p; } fec_codes_t; #endif /* RMDP__INIT_H */ rmdp/layers.h010064400373640000764000000005520651641224100147100ustar00ucaclxvcsstaff00002440000013#ifndef RMDP_LAYERS_H #define RMDP_LAYERS_H #include "compat.h" #define K_MAX 8 #define N_MAX 256 int which_packet(int B, int k, int nc, int idx, int *lay, #if 0 /*ppp*/ int *lidx, int *pkt, int *blk); #else unsigned short *lidx, int *pkt, int *blk); #endif int compute_k_B(int *k, int *B, int npkts, int nlay); #endif /* RMDP_LAYERS_H */ rmdp/fec.h010064400373640000764000000042440654373002000141460ustar00ucaclxvcsstaff00002440000013/* * fec.c -- forward error correction based on Vandermonde matrices * 980614 * (C) 1997-98 Luigi Rizzo (luigi@iet.unipi.it) * * Portions derived from code by Phil Karn (karn@ka9q.ampr.org), * Robert Morelos-Zaragoza (robert@spectra.eng.hawaii.edu) and Hari * Thirumoorthy (harit@spectra.eng.hawaii.edu), Aug 1995 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. */ /* * The following parameter defines how many bits are used for * field elements. The code supports any value from 2 to 16 * but fastest operation is achieved with 8 bit elements * This is the only parameter you may want to change. */ #ifndef GF_BITS #define GF_BITS 8 /* code over GF(2**GF_BITS) - change to suit */ #endif #define GF_SIZE ((1 << GF_BITS) - 1) /* powers of \alpha */ void fec_free(void *p) ; void * fec_new(int k, int n) ; void init_fec() ; void fec_encode(void *code, void *src[], void *dst, int index, int sz) ; int fec_decode(void *code, void *pkt[], int index[], int sz) ; /* end of file */ rmdp/error.h010064400373640000764000000001410651641223700145410ustar00ucaclxvcsstaff00002440000013#ifndef RMDP__ERROR_H #define RMDP__ERROR_H int rmdp_error_init_(); #endif /* RMDP__ERROR_H */ rmdp/utils.h010064400373640000764000000001540651641224500145530ustar00ucaclxvcsstaff00002440000013#ifndef RMDP_UTILS_H #define RMDP_UTILS_H unsigned long rmdp_compute_sessid_(); #endif /* RMDP_UTILS_H */ rmdp/receiver.h010064400373640000764000000002410657032070300152110ustar00ucaclxvcsstaff00002440000013#ifndef RMDP_RECEIVER_H #define RMDP_RECEIVER_H int _rmdp_receiver_init(); void _rmdp_send_stats (int pi, void *buff, int size); #endif /* RMDP_RECEIVER_H */ rmdp/compat.h010064400373640000764000000010750651641223700147020ustar00ucaclxvcsstaff00002440000013#ifndef RMDP_COMPAT_H #define RMDP_COMPAT_H #include #ifdef IRIX #include #include #endif #ifdef HPUX #include #endif #ifdef FreeBSD #include #endif #ifdef Linux #include #endif #ifdef SunOS #include #endif #ifdef __FreeBSD__ #include #else #define bcopy(s, d, siz) memcpy((d), (s), (siz)) #define bzero(d, siz) memset((d), '\0', (siz)) #endif #define min(x,y) (((x)>(y))?(y):(x)) #define max(x,y) (((x)<(y))?(y):(x)) #endif /* RMDP_COMPAT_H */ rmdp/receiver.h010064400373640000764000000002410657032070300152110ustar00ucaclxvcsstaff00002440000013#ifndef RMDP_RECEIVER_H #define RMDP_RECEIVER_H int _rmdp_receiver_init(); void _rmdp_send_stats (int pi, void *buff, int size); #endif /* RMDP_RECEIVER_H */ rmdp/agent.h010064400373640000764000000052760657031237100145220ustar00ucaclxvcsstaff00002440000013#ifndef RMDP_AGENT_H #define RMDP_AGENT_H #include "rlcif.h" #include "rmdpif.h" extern void *rmdp_inst_mngr; #define AGENT_FIELDS \ INSTANCE_DES_MEMB \ unsigned long sessid; /* random session identifier */ \ void ***alldata; /* packets... */ \ void ***allpkts; /* all plain data packets */ \ int B, k; /* encoding parameters */ \ unsigned long npkts, flength; \ int psize; /* pkt size */ \ \ void *feccode; \ int rlc_pi; /* rlc associated protocol instance */ \ int have_gui; /* have graphyc interface ? */ \ \ unsigned long addr; /* feedback channel address, net byte ord. */ \ short port; /* feedback channel port #, net byte ord. */ \ int ufeeso; /* unicast feedback socket */ \ int mfeeso; /* multicast feedback socket */ \ \ int fd; /* input/output file descriptor */ \ int isreceiver; /* 1 if this is receiver, 0 sender */ \ rmdp_end_f end_f; /* called when when the reception \ terminates successfully */ typedef struct _rmdp_inst_t { AGENT_FIELDS /* sender specific ... */ int nlay; unsigned short *idxs; /* counts the packet transmitted in each layer */ char *sparepkt; /* spare pkt pointer */ unsigned long pkts_left; /* packets left to transmit */ unsigned long init_left; /* initial scheduled packets */ int stafd; /* fil descriptor for stats report */ /* receiver specific ... */ int ttl; int **whichdata, *countdata;/* info on received packets */ int maxn; /* max packet index among those received */ int missingblocks, duppackets; int oldtotgot, totgot, netgot; double speedf; /* statistic: # pkts got for each pkt sent on lay 0 */ rmdp_rx_err_f err_f; /* called when when the reception terminates beacause of an error */ int reqpending; /* if a transmission extension timeout is pending, its > 0 */ int reqsent; int recpercent; unsigned long left; int mcastfeed; /* is != 0 uses mucast feedback otherwise uses unicast */ } rmdp_inst_t; void _rmdp_rx_packet(int ides, int lay, char flags, char *pkt, int size); int _rmdp_tx_packet(int des, int lay, char flags, char **p); void _rmdp_deleteinstance(rmdp_inst_t *inst); int _rmdp_allocation(rmdp_inst_t *se); void _rmdp_deallocation(rmdp_inst_t *inst); #if 1 int _rmdp_insert_instance (rmdp_inst_t * inst); void _rmdp_return_instance (rmdp_inst_t * inst); rmdp_inst_t * _rmdp_getinstance(int pi); void _rmdp_init_instance (); #endif #endif /* RMDP_AGENT_H */ rmdp/uirx.tcl010064400373640000764000000055040656713610100147410ustar00ucaclxvcsstaff00002440000013set pktsHdim 100 set pktsWdim 10 set pktsW1dim 10 set top .expr set thisgl [frame $top.fr -bd 2 -relief groove] set prog1d [canvas $thisgl.pkts1 -width $pktsW1dim -height $pktsHdim] set progla [label $thisgl.lab -text "*/*" -font $globFonts -width 9] ## set prog2d [canvas $thisgl.pkts -width $pktsWdim -height $pktsHdim] pack $thisgl -fill both -expand 1 pack $prog1d -side top pack $progla -side top ## pack $prog2d -side left $prog1d create rectangle \ 0 0 $pktsW1dim $pktsHdim -fill bisque -outline bisque -width 0 proc prog_percent {percent} { global prog1d progla pktsHdim pktsW1dim totsize $prog1d create rectangle \ 0 [expr (1.0 - $percent) * $pktsHdim] \ $pktsW1dim $pktsHdim -fill brown -outline brown -width 0 set app [expr $totsize * $percent] set pr [format "%.0fkB/\n%.0fkB" $app $totsize] $progla configure -text "$pr" } proc pkts_init {B k fsize psize} { global prog2d global pktsHfact pktsWfact pktsHdim pktsWdim global pktsB pktsk pktsHave pktsDups global pktssize filesize totsize # puts "#### init with B= $B and k= $k" ## $prog2d delete all set pktsHfact [expr ${pktsHdim}.0/$B] set pktsWfact [expr ${pktsWdim}.0/$k] set pktsk $k set pktsB $B set pktssize $psize set filesize $fsize set totsize [expr $k * $B * $psize / 1024.0] # puts "#### init have $B $k $pisize $fsize $totsize" for {set i 0} {$i < $B} {incr i} { set pktsHave($i) 0 set pktsDups($i) 0 } } proc pkts_have_dup {B more} { global prog2d return $prog2d create rectangle \ [expr $pktsDups($B) * $pktsWfact] \ [expr $B * $pktsHfact] \ [expr ($pktsDups($B)+$more) * $pktsWfact] \ [expr ($B+1) * $pktsHfact] \ -fill red -outline red -width 0] set pktsDups($B) [expr $pktsDups($B) + $more] } proc pkts_have_more {B more} { global prog2d global pktsk pktsHave global pktsHfact pktsWfact pktsHdim pktsWdim # puts "#### enter with $B : $pktsHave($B)" return set app [expr $pktsk - ($pktsHave($B) + $more)] if {$app >= 0} { set less 0 } elseif {$app > -$more} { set more [expr $more + $app] set less $app } else { set less [expr - $more] set more 0 } if {$more > 0} { set thisid [$prog2d create rectangle \ [expr $pktsHave($B) * $pktsWfact] \ [expr $B * $pktsHfact] \ [expr ($pktsHave($B)+$more) * $pktsWfact] \ [expr ($B+1) * $pktsHfact] \ -fill green -outline green -width 0] $prog2d lower $thisid set pktsHave($B) [expr $pktsHave($B) + $more] } if {$less < 0} { $prog2d create rectangle \ [expr (2 * $pktsk - ($pktsHave($B) - $less)) * $pktsWfact] \ [expr $B * $pktsHfact] \ [expr (2 * $pktsk - $pktsHave($B)) * $pktsWfact] \ [expr ($B+1) * $pktsHfact] \ -fill yellow -outline yellow -width 0 set pktsHave($B) [expr $pktsHave($B) - $less] set app [expr 2 * $pktsk - $pktsHave($B)] # puts "#### have $less for $B ($app)" } # puts "#### exit with $B : $pktsHave($B) (less = $less)" } rmdp/uitx.tcl010064400373640000764000000000000656434412000147240ustar00ucaclxvcsstaff00002440000013rmdp/ui.tcl010064400373640000764000000003760656713613600144010ustar00ucaclxvcsstaff00002440000013# let's give it a default name wm title . "rmdp" if {![info exists RMDPINFOS]} { set RMDPINFOS "Not present ... sorry!" } if [info exist HelpButt] { $HelpButt add command -label "About RMDP" -command \ "show_infos {$RMDPINFOS} \"About RMDP\"" } rmdp/Makefile.in010064400373640000764000000074620657056236400153300ustar00ucaclxvcsstaff00002440000013DEFINES=-D$(OSTYPE) -DOSMVER=$(OSMVER) -DHAVE_UI #-DDEBUGE # -DHAVE_UI define this to have UI support CHECK= -fbounds-checking -lcheck CFLAGS=-g -Wall -O2 $(DEFINES) $(RLC_INCLUDE) LDFLAGS=-Wl,-Bstatic # -pg CC=gcc #${CHECK} OBJDIR = obj/$(OSTYPE) LIBS= $(RLC_LIB) $(TK_LIB) $(TCL_LIB) $(X11_LIB) $(OTHER_LIBS) LIB_C_SRCS= sender.c receiver.c layers.c init.c error.c fec.c utils.c rmdp.c LIB_H_SRCS= rmdpif.h rmdp.h sender.h init.h layers.h \ fec.h error.h utils.h receiver.h compat.h receiver.h agent.h OTHER_SRCS= uirx.tcl uitx.tcl ui.tcl OTHER_C_STUFF= sen-sample.c rec-sample.c RMDPft.c OTHER_STUFF= Makefile.in Makefile.genarch makescript README INSTALL TODO \ Makefile.SunOS Makefile.FreeBSD Makefile.Linux Makefile.IRIX ALLSTUFF= $(LIB_C_SRCS) $(LIB_H_SRCS) $(OTHER_SRCS) $(OTHER_STUFF) \ $(OTHER_C_STUFF) UPALLSTUFF=$(ALLSTUFF:%=rmdp/%) #LIB_O=$(LIB_C_SRCS:.c=.o) LIB_O=$(LIB_C_SRCS:%.c=$(OBJDIR)/%.o) I_H_DOCS=$(LIB_H_SRCS:%.h=doc/%.h.tex) I_C_DOCS=$(LIB_C_SRCS:%.c=doc/%.c.tex) DOCS= $(I_H_DOCS) $(I_C_DOCS) SUFFIXES+= .c.tex .SUFFIXES: $(SUFFIXES) all: sh makescript x-all xref: sh makescript x-xref depend: sh makescript x-depend sample: sh makescript x-sample x-all: $(OBJDIR) $(OBJDIR)/librmdp.a $(OBJDIR)/librmdp.a: $(LIB_O) $(OBJDIR)/ui-tcl.o - rm $(OBJDIR)/librmdp.a ar r $(OBJDIR)/librmdp.a $(LIB_O) $(OBJDIR)/ui-tcl.o - ranlib $(OBJDIR)/librmdp.a $(OBJDIR)/ui-tcl.o: ui-tcl.c $(CC) $(CFLAGS) -c ui-tcl.c -o $(OBJDIR)/ui-tcl.o $(X11_INCLUDE) \ $(TK_INCLUDE) $(TCL_INCLUDE) ui-tcl.c: uirx.tcl uitx.tcl ui.tcl README (echo "char RMDP_TCL_SCRIPT[] = \"\\" ; \ ( (echo "set RMDPINFOS {\\"; \ cat README | sed 's/\([^$$]\)$$/\1\\/'; \ echo "}"); \ cat ui.tcl) | sed 's/\\/\\\\/g'| sed 's/$$/\\n\\/g' | \ sed 's/\"/\\\"/g'; \ echo "\";") > ui-tcl.c (echo "char RMDP_RX_TCL_SCRIPT[] = \"\\" ; \ cat uirx.tcl | sed 's/\\/\\\\/g'| sed 's/$$/\\n\\/g' | \ sed 's/\"/\\\"/g'; \ echo "\";") >> ui-tcl.c (echo "char RMDP_TX_TCL_SCRIPT[] = \"\\" ; \ cat uitx.tcl | sed 's/\\/\\\\/g'| sed 's/$$/\\n\\/g' | \ sed 's/\"/\\\"/g'; \ echo "\";") >> ui-tcl.c $(OBJDIR)/ui.o: ui.c ui.h $(CC) $(CFLAGS) -c ui.c -o $(OBJDIR)/ui.o $(X11_INCLUDE) $(TK_INCLUDE) \ $(TCL_INCLUDE) x-sample: $(OBJDIR)/rec-sample $(OBJDIR)/sen-sample $(OBJDIR)/RMDPft # $(TK_LIB) \ # $(TCL_LIB) $(OTHER_LIBS) $(X11_LIB) $(OBJDIR)/sen-sample: sen-sample.c $(OBJDIR)/librmdp.a $(CC) $(CFLAGS) $(LDFLAGS) sen-sample.c -o $(OBJDIR)/sen-sample \ -L$(OBJDIR)/ -lrmdp $(LIBS) $(OBJDIR)/rec-sample: rec-sample.c $(OBJDIR)/librmdp.a $(CC) $(CFLAGS) $(LDFLAGS) rec-sample.c -o $(OBJDIR)/rec-sample \ -L$(OBJDIR)/ -lrmdp $(LIBS) $(OBJDIR)/RMDPft: RMDPft.c $(OBJDIR)/librmdp.a $(CC) $(CFLAGS) $(LDFLAGS) RMDPft.c -o $(OBJDIR)/RMDPft -L$(OBJDIR)/ \ -lrmdp $(LIBS) clean: sh makescript x-clean x-clean: rm -f $(LIB_O) $(OBJDIR)/ui-tcl.o ui-tcl.c $(OBJDIR)/librmdp.a \ $(OBJDIR)/rec-sample $(OBJDIR)/sen-sample $(OBJDIR)/RMDPft tgz: (cd ..; tar cvf - $(UPALLSTUFF) ) | gzip > rmdp.tgz x-xref: doc-dir $(DOCS) -(cd doc; latex cxref; exit 0) $(OBJDIR): if [ -d $(OBJDIR) ] ;\ then \ echo "$(OBJDIR) exists";\ else \ mkdir -p $(OBJDIR) ;\ fi doc-dir: if [ -d ./doc ] ;\ then \ else \ mkdir doc ;\ fi $(OBJDIR)/%.o: %.c $(CC) $(CFLAGS) $(DEFINES) $(TK_INCLUDE) $(TCL_INCLUDE) $(X11_INCLUDE) \ $< -c -o $@ doc/%.c.tex: %.c cxref $(DEFINES) $(RLC_INCLUDE) $(TK_INCLUDE) $(TCL_INCLUDE) \ $(X11_INCLUDE) $< -Odoc -latex2e doc/%.h.tex: %.h cxref $(DEFINES) $(RLC_INCLUDE) $(TK_INCLUDE) $(TCL_INCLUDE) \ $(X11_INCLUDE) $< -Odoc -latex2e se: $(SE_O) $(CC) -o se $(SE_O) $(LIBS) re: $(RE_O) $(CC) -o re $(RE_O) $(LIBS) x-depend: makedepend -s"# DO NOT DELETE BELOW! (custom makedepend delim.) :-)"\ $(DEFINES) $(RLC_INCLUDE) $(X11_INCLUDE) \ $(TCL_INCLUDE) $(TK_INCLUDE) $(LIB_C_SRCS) # DO NOT DELETE BELOW! (custom makedepend delim.) :-) rmdp/Makefile.genarch010064400373640000764000000010210651641656400163120ustar00ucaclxvcsstaff00002440000013## # Personalize according to your environment. ## RLC_INCLUDE= -I../rlc RLC_LIB= -L../rlc -lrlc # sloaris need also: -lsocket -lnsl -ldl OTHER_LIBS= -lm ### ## The following only if you compile with -DHAVE_UI ### # in solaris : -I/usr/openwin/include/ X11_INCLUDE= -I/usr/X11R6/include/ TCL_INCLUDE= -I/usr/local/include/ TK_INCLUDE= -I/usr/local/include/ ### ## The following only if you compile the samples with -DHAVE_UI ### TCL_LIB= -L/usr/local/lib -ltcl TK_LIB= -L/usr/local/lib -ltk X11_LIB= -lX11 include Makefile rmdp/makescript010064400373640000764000000072130651641224200153270ustar00ucaclxvcsstaff00002440000013#!/bin/sh # # Build script for rat. This script determines the type of machine it's # running on, and calls "make" with the appropriate macro definitions # to set up the machine specific includes etc. # # NOTE: If the environment variable MAKE is set, it's value will be # used instead of the default "make". Use this to give a path # to gnu make, for example. # # $Revision: 1.1 $ # $Date: 1997/10/10 12:29:57 $ # # Copyright (c) 1996 University College London # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. All advertising materials mentioning features or use of this software # must display the following acknowledgement: # This product includes software developed by the Computer Science # Department at University College London # 4. Neither the name of the University nor of the Department may be used # to endorse or promote products derived from this software without # specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # Find out the type of system we're running on. The nasty stuff is needed for $OSMVER # since some systems (HP-UX) give the OS version in a weird format. At the end of this # we should have the following variables set: # # OSTYPE : Base operating system type # OSMVER : The major version number of the system # OSVERS : The full version number of the system # echo "Determining system type..." OSTYPE=`uname -s` OSVERS=`uname -r` case $OSTYPE in Linux ) OSMVER=`echo $OSVERS | awk -F. '{printf("%d_%d", $1, $2)}'` ;; SunOS | IRIX ) OSMVER=`echo $OSVERS | awk -F. '{print $1}'` OSLIBS="-lsocket -lnsl" ;; HP-UX ) OSTYPE=HPUX OSMVER=`echo $OSVERS | awk -F. '{print $2}'` ;; FreeBSD ) OSMVER=`echo $OSVERS | awk -F. '{print $1}'` OSLIBS="" ;; * ) echo "$OSTYPE $OSVERS is not supported!" exit ;; esac echo "OSTYPE=$OSTYPE" echo "OSVERS=$OSVERS" echo "OSMVER=$OSMVER" TARGET=${@:-all} MM=`which gmake | sed -n "/\/gmake/p"` #if which gmake 2> /dev/null > /dev/null if test -f "/$MM" && test -x "/$MM" then echo "using gmake"; MM=gmake else echo "gmake not found, hopefully make works..."; MM=make fi MAKEFILE=Makefile.$OSTYPE if [ -f $MAKEFILE ] then echo "using $MAKEFILE" else echo "can't find $MAKEFILE"; exit 1 fi export OSLIBS cmd="${MAKE:=$MM} -f $MAKEFILE $TARGET OSTYPE=$OSTYPE OSMVER=$OSMVER OSVERS=$OSVERS" exec $cmd rmdp/README010064400373640000764000000021560657026201300141220ustar00ucaclxvcsstaff00002440000013rmdp-1.0a1 20/08/98 l.vicisano@cs.ucl.ac.uk URL: http://www.cs.ucl.ac.uk/staff/l.vicisano/rmdp/ RMDP is an efficient protocol for reliable multicast bulk-data transfer, designed with scalability issues in mind. In this respect the protocol requires very small (or no) receiver feedback and allows asynchronous reception, not requiring inter-receivers coordination. Reliability is achieved by means of Erasure Correction techniques. A lightweight protocol is used to start and keep alive the sender. It requires a very small amount of feedback from receivers, that can be provided either using unicast or multicast. In both case a suppression protocol avoids implosion problems. This is a C implementation of RMDP that uses RLC () for congestion control. The present is an alpha release: it might (almost certainly) contain bugs. The current version of RMDP adds congestion control to a former implementation by Luigi Rizzo (luigi@iet.unipi.it) and Lorenzo Vicisano. Preliminary documentation concerning the API of RMDP library is available on line. For further information either send me an e-mail or look at the source code. rmdp/INSTALL010064400373640000764000000033750656710415300143050ustar00ucaclxvcsstaff00002440000013rmdp-1.0a1 20/08/98 l.vicisano@cs.ucl.ac.uk URL: http://www.cs.ucl.ac.uk/staff/l.vicisano/rmdp/ RMDP library compiles on Solaris, FreeBSD, Linux, SunOS, IRIX and (maybe) most of the others Unix flavours. To compile and use RMDP, you need RLC, currently available at the following URL: http://www.cs.ucl.ac.uk/staff/l.vicisano/rlc/ . RMDP will work properly provided that the required working conditions for RLC are satisfied. Please note that the current version of RMDP is not optimized as far as performance are concerned. In particular the FEC encoding makes use of small FEC-block size, which can lead to a significant percentage of useless packet reception. To build: - must have gmake or compatible, and rlc (librlc.{a,so} and rlcif.h. If you want to use the UI stuff, you must also have tk/tcl (It compiles with version 4.2/7.6 ... and maybe with some other versions), define HAVE_UI, and use a version of librlc with UI enabled. - copy Makefile.in to Makefile - possibly edit Makefile to change DEFINES (shouldn't be needed), the only thing that's optional is HAVE_UI ! - copy Makefile.genarch to Makefile., if you are not sure about the name, run `make` : it will complain searching your makefile. - edit Makefile. according to your environment. - make clean - make depend - make It all produces librmdp.a . Then you have to install it by hand, copying librmdp.a and rmdpif.h where you want to keep them. You can also try to compile the multicast ftp sample programs, using: - make sample It will produce RMDPft, sen-sample and rec-sample. Run them with -h argument to obtain the option list. Please send me any feedback you have to the following e-mail address: l.vicisano@cs.ucl.ac.uk . Lorenzo Vicisano rmdp/TODO010064400373640000764000000001220656725274200137370ustar00ucaclxvcsstaff00002440000013 - use a temporary file when receiving large files! - handle multi-homed machine rmdp/Makefile.SunOS010064400373640000764000000014020656727315400157170ustar00ucaclxvcsstaff00002440000013## # Personalize according to your environment. ## RLC_INCLUDE= -I../rlc RLC_LIB= -L../rlc/$(OBJDIR) -lrlc # sloaris need also: -lsocket -lnsl -ldl OTHER_LIBS= -Wl,-Bdynamic -lm -lsocket -lnsl -ldl #OTHER_LIBS= -lm -lsocket -lnsl -Wl,-Bdynamic -ldl ### ## The following only if you compile with -DHAVE_UI ### # in solaris : -I/usr/openwin/include/ X11_INCLUDE= -I/usr/openwin/include/ TCL_INCLUDE= -I/cs/research/mice/starship/common/solaris/include/ TK_INCLUDE= -I/cs/research/mice/starship/common/solaris/include/ ### ## The following only if you compile the samples with -DHAVE_UI ### TCL_LIB= -L/cs/research/mice/starship/common/solaris/lib -ltcl8.0 TK_LIB= -L/cs/research/mice/starship/common/solaris/lib -ltk8.0 X11_LIB= -Wl,-Bdynamic -lX11 include Makefile rmdp/Makefile.FreeBSD010064400373640000764000000010770656401772600161300ustar00ucaclxvcsstaff00002440000013## # Personalize according to your environment. ## RLC_INCLUDE= -I../rlc RLC_LIB= -L../rlc/$(OBJDIR) -lrlc # sloaris need also: -lsocket -lnsl -ldl OTHER_LIBS= -lm ### ## The following only if you compile with -DHAVE_UI ### # in solaris : -I/usr/openwin/include/ X11_INCLUDE= -I/usr/X11R6/include/ TCL_INCLUDE= -I//usr/local/include/tcl8.0 TK_INCLUDE= -I/usr/local/include/tk8.0 ### ## The following only if you compile the samples with -DHAVE_UI ### TCL_LIB= -L//usr/local/lib/ -ltcl80 TK_LIB= -L/usr/local/lib/ -ltk80 X11_LIB= -L/usr/X11R6/lib -lX11 include Makefile rmdp/Makefile.Linux010064400373640000764000000011050654715577200160120ustar00ucaclxvcsstaff00002440000013#### # Linux ## # Personalize according to your environment. ## RLC_INCLUDE= -I../rlc RLC_LIB= -L../rlc/$(OBJDIR) -lrlc # sloaris need also: -lsocket -lnsl -ldl OTHER_LIBS= -lm ### ## The following only if you compile with -DHAVE_UI ### X11_INCLUDE= -I/usr/X11R6/include/ X11_LIB= -L/usr/X11R6/lib/ -lX11 TCL_INCLUDE= -I/cs/research/mice/starship/common/linux/include/ TK_INCLUDE= -I/cs/research/mice/starship/common/linux/include/ TCL_LIB= -L/cs/research/mice/starship/common/linux/lib/ -ltcl8.0 TK_LIB= -L/cs/research/mice/starship/common/linux/lib/ -ltk8.0 include Makefile rmdp/Makefile.IRIX010064400373640000764000000011000655565544300154600ustar00ucaclxvcsstaff00002440000013#### # IRIX ## # Personalize according to your environment. ## RLC_INCLUDE= -I../rlc RLC_LIB= -L../rlc/$(OBJDIR) -lrlc # sloaris need also: -lsocket -lnsl -ldl OTHER_LIBS= -lm ### ## The following only if you compile with -DHAVE_UI ### X11_INCLUDE= -I/usr/X11R6/include/ X11_LIB= -L/usr/X11R6/lib/ -lX11 TCL_INCLUDE= -I/cs/research/mice/starship/common/irix/include/ TK_INCLUDE= -I/cs/research/mice/starship/common/irix/include/ TCL_LIB= -L/cs/research/mice/starship/common/irix/lib/ -ltcl8.0 TK_LIB= -L/cs/research/mice/starship/common/irix/lib/ -ltk8.0 include Makefile rmdp/sen-sample.c010064400373640000764000000112630656436234000154600ustar00ucaclxvcsstaff00002440000013#include #include #include #include #include #include #include #include #include #if defined(Linux) #include #endif #include #include "rmdpif.h" void badcmdline(char *arg) { rmdp_my_error(-1, "Bad argument %s\nCommand line:\n\t sen-sample [options]\n" "options:\n" "\t-f \n" "\t-d \n" "\t-i \n" "\t-l \n" "\t-t \n" "\t-I (non stop transmission)\n", arg); } int open_n_check(char *filn) { int fd; if (!strcmp(filn, "-")) return 0; if ((fd = open (filn, O_RDONLY)) < 0) { return (-1); } else return (fd); } #define ISSENDER 0 /* means that is sender ! */ int main(int argc, char *argv[]) { int fd = -1; /* input file */ char dataaddr[256]; int ttl = 5; int haveaddr = 0; int rmdp_i; /* rmdp instance id */ int rlc_i; /* rlc instance id */ int ret; char tmpaddr[256]; unsigned long addr0; short port; int pkt_size; /* rmdp payload + rmdp header */ int layers; int pid = -1; unsigned long base_rate = 16 * 1024; addr_list_t taddr; rlc_tx_params_t parml; /* tx parameter list ... */ rmdp_addr_t adds; unsigned long p; int errflg = 0, i; int nostop = 0; rmdp_tx_packet_t tx_f; extern char *optarg; extern int optind; /* parse command line... */ while ((i = getopt(argc,argv,"t:d:f:i:I")) != EOF) { switch(i) { case 'd': /* data addr/port */ strncpy(dataaddr, optarg, 256); haveaddr = 1; break; case 'I': /* protocol instance id */ nostop = 1; break; case 'i': /* protocol instance id */ pid = atoi(optarg); break; case 't': /* TTL */ ttl = atoi(optarg); if (ttl <= 0 || ttl > 255) badcmdline(optarg); break; case 'f': /* input file */ if ((fd = open_n_check(optarg)) < 0) badcmdline(optarg); break; case '?': errflg++; } } if (errflg) badcmdline("?"); argc -= optind; argv += optind; if (fd < 0) rmdp_my_error(-1, "must provide input file"); if (!haveaddr) rmdp_my_error(-1, "must provide destination address"); /* extract address (string) and port (short) from the * input parameter (x.x.x.x/yyy) */ if (rmdp_parse_addr(dataaddr, tmpaddr, sizeof(tmpaddr), &port, "data") < 0) { char *c; ret = rlc_error_info(&c); rmdp_my_error (-1, "Error %d in rmdp_parse_addr (%s)\n", ret, c); } addr0 = ntohl(inet_addr(tmpaddr)); adds.addr = addr0; adds.port = port+1; adds.ttl = ttl; /* setup an rmdp sender instance */ if ((ret = rmdp_i = rmdp_new (ISSENDER)) < 0 || (ret = rmdp_set_addr (rmdp_i, &adds)) < 0 || (ret = rmdp_set_io (rmdp_i, fd)) < 0 ) { char *c; ret = rlc_error_info(&c); rmdp_my_error (-1, "Error %d in protocol initialization (%s)\n", ret, c); } if (pid != -1 && (ret = rmdp_set_id(rmdp_i, pid)) < 0) { char *c; ret = rlc_error_info(&c); rmdp_my_error (-1, "Error %d in protocol initialization (%s)\n", ret, c); } if (nostop) { unsigned long left = rmdp_get_left (rmdp_i); if ((ret = rmdp_incr_left (rmdp_i, (unsigned long)0xffffffff - left)) < 0) { char *c; ret = rlc_error_info(&c); rmdp_my_error (-1, "Error %d in protocol initialization (%s)\n", ret, c); } } /* retrieve rmdp packet size (rlc payload) */ pkt_size = rmdp_get_psize(rmdp_i); /* retrieve rmdp number of layers */ layers = rmdp_get_nlay(rmdp_i); /* this is the interpacket-period (us) in the upper session */ p = 1e6 * (pkt_size) * 8 / base_rate / (1<<(layers-1)); /* get data transmission handler function from rmdp */ if ((ret = rmdp_get_f(rmdp_i, (void **)(&tx_f))) < 0) { char *c; ret = rlc_error_info(&c); rmdp_my_error (-1, "Error %d in rmdp_get_f (%s)\n", ret, c); } taddr.nadd = 1; taddr.addrs = &addr0; taddr.port = port; taddr.ttl = ttl; parml.nlay = layers; parml.mpkts = pkt_size; parml.Mpkts = pkt_size; parml.t = p; /* setup a rlc sender instance */ if ((ret = rlc_i = rlc_new(ISSENDER)) < 0 || (ret = rlc_set_addr (rlc_i, &taddr)) < 0 || (ret = rlc_attach (rlc_i, rmdp_i, (void *)tx_f)) < 0 || (ret = rlc_tx_setup(rlc_i, &parml)) < 0 || parml.t != p ) { char *c; ret = rlc_error_info(&c); rmdp_delete(rmdp_i); rmdp_my_error(-1, "error %d in rlc_tx_setup (%s)\n", ret, c); } /* start the transmission */ if ((ret = rlc_start(rlc_i)) < 0) { char *c; ret = rlc_error_info(&c); rmdp_delete(rmdp_i); rmdp_my_error(-1, "error %d in rlc_tx_start (%s)\n", ret, c); } while (rlc_getevent(1)!=EV_TERMINATE); exit(0); } rmdp/rec-sample.c010064400373640000764000000160100656436235200154420ustar00ucaclxvcsstaff00002440000013#include #include #include #include #include #include #include #include #include #if defined(Linux) #include #endif #include #include "rmdpif.h" void badcmdline(char *arg) { rmdp_my_error(-1, "Bad argument %s\nCommand line:\n\t rec-sample [options]\n" "options:\n" "\t-f \n" "\t-d \n" "\t-t \n" "\t-i \n" "\t-C \n" "\t-x \n" "\t-g \n" "\t-e \n" "\t-p \n" /* "\t-n \n" */ , arg); } int open_n_check(char *filn) { int fd; if (!strcmp(filn, "-")) return 1; if ((fd = open (filn, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) { return (-1); } else { return (fd); } } int rlc_i; /* rlc instance id */ int rmdp_i; /* rmdp instance id */ int fd = 1; /* output file */ int chosefile = 0; char *sessname=NULL; char *geometry=NULL; /* this handle the termination of * the current reception */ void reception_end(int rmdp_i, int success) { if (success >= 0 && chosefile) { #ifdef HAVE_UI char *ret = NULL; int res; if (sessname) res = rlc_gui_tcl_exec (rlc_i, &ret, "tk_getSaveFile -title {%s}", sessname); else res = rlc_gui_tcl_exec (rlc_i, &ret, "tk_getSaveFile -title \"RMDP\""); if (res >= 0 && ret != NULL) { if (ret[0] != '\0') { if ((fd = open_n_check(ret)) >= 0) { rmdp_set_io(rmdp_i, fd); } else rmdp_my_error (rmdp_i, "Error opening out file (%s)\n", ret); } else { rmdp_my_error (rmdp_i, "No file selected!\n"); } free(ret); } else { rmdp_my_error (rmdp_i, "rlc gui error|\n"); } #endif } else if (success < 0) { rmdp_my_error (rmdp_i, "Decoding error ? \n"); } /* in this example just abort the reception instance */ rlc_abort(rlc_i); } int main(int argc, char *argv[]) { char dataaddr[256]; int ttl = 5; int haveaddr = 0; int isreceiver = 1; int ret; char *ev_f = NULL , *po_f = NULL ; char tmpaddr[256]; unsigned long addr0; short port; int pkt_size; /* rmdp payload + rmdp header */ int reqsize; int pid = -1; addr_list_t taddr; rmdp_addr_t adds; int errflg = 0, i; rmdp_rx_packet_t rx_f; extern char *optarg; extern int optind; /* parse command line... */ while ((i = getopt(argc,argv,"g:i:t:d:f:C:e:p:x")) != EOF) switch(i) { case 'd': /* data addr/port */ strncpy(dataaddr, optarg, 256); haveaddr = 1; break; case 't': /* TTL */ ttl = atoi(optarg); if (ttl <= 0 || ttl > 255) badcmdline(optarg); break; case 'i': /* pid */ pid = atoi(optarg); break; case 'f': /* output file */ if ((fd = open_n_check(optarg)) <= 0) badcmdline(optarg); break; case 'C': /* session name */ if ((sessname = malloc(strlen(optarg)+1)) == NULL) break; strcpy (sessname, optarg); fprintf(stderr, "%s\n", sessname); break; case 'g': /* session name */ if ((geometry = malloc(strlen(optarg)+1)) == NULL) break; strcpy (geometry, optarg); break; case 'x': /* session name */ chosefile = 1; break; case 'e': /* event log file */ ev_f = (char *)calloc(strlen(optarg)+1, sizeof(char)); strncpy(ev_f, optarg, strlen(optarg)+1); break; case 'p': /* poll log file */ po_f = (char *)calloc(strlen(optarg)+1, sizeof(char)); strncpy(po_f, optarg, strlen(optarg)+1); break; case '?': errflg++; } if (errflg) badcmdline("?"); argc -= optind; argv += optind; if (!haveaddr) rmdp_my_error(-1, "must provide destination address"); /* extract address (string) and port (short) from the * input parameter (x.x.x.x/yyy) */ if (rmdp_parse_addr(dataaddr, tmpaddr, sizeof(tmpaddr), &port, "data") < 0) { char *c; ret = rlc_error_info(&c); rmdp_my_error (-1, "Error %d in rmdp_parse_addr (%s)\n", ret, c); } addr0 = ntohl(inet_addr(tmpaddr)); adds.addr = addr0; adds.port = port+1; adds.ttl = ttl; /* setup an rmdp receiver instance */ if ((ret = rmdp_i = rmdp_new (isreceiver)) < 0 || (ret = rmdp_set_addr (rmdp_i, &adds)) < 0 || (ret = rmdp_set_io (rmdp_i, fd)) < 0 ) { char *c; ret = rlc_error_info(&c); rmdp_my_error (-1, "Error %d in protocol initialization (%s)\n", ret, c); } if (pid != -1 && (ret = rmdp_set_id(rmdp_i, pid)) < 0) { char *c; ret = rlc_error_info(&c); rmdp_my_error (-1, "Error %d in protocol initialization (%s)\n", ret, c); } /* set reception-end callback */ if ((ret = rmdp_set_end_callback(rmdp_i, reception_end)) < 0) { char *c; ret = rlc_error_info(&c); rmdp_my_error (-1, "Error %d in rmdp_set_end_callback (%s)\n", ret, c); } /* get data reception handler function from rmdp */ if ((ret = rmdp_get_f(rmdp_i, (void **)(&rx_f))) < 0) { char *c; ret = rlc_error_info(&c); rmdp_my_error (-1, "Error %d in rmdp_get_f (%s)\n", ret, c); } reqsize = pkt_size; taddr.nadd = 1; taddr.addrs = &addr0; taddr.port = port; /* setup a rlc receiver instance */ if ((ret = rlc_i = rlc_new (isreceiver)) < 0 || (ret = rlc_set_addr (rlc_i, &taddr)) < 0 || (ret = rlc_attach (rlc_i, rmdp_i, (void *)rx_f)) < 0 ) { char *c; ret = rlc_error_info(&c); rmdp_delete(rmdp_i); rmdp_my_error(-1, "error %d in rlc_rx_setup (%s)\n", ret, c); } #ifdef HAVE_UI if (geometry) rlc_gui_geometry (rlc_i, geometry); if ((ret = rlc_gui_enable(rlc_i)) < 0) { char *c; ret = rlc_error_info(&c); rmdp_delete(rmdp_i); rmdp_my_error(-1, "error %d in rlc_gui_enable (%s)\n", ret, c); } #endif /* setup rlc idle watchdog */ if ((ret = rlc_rx_set_watchdog(rlc_i, NULL, 0)) < 0) { char *c; ret = rlc_error_info(&c); rmdp_delete(rmdp_i); rmdp_my_error(-1, "error %d in rlc_rx_setup (%s)\n", ret, c); } if ((ret = rmdp_set_rlc (rmdp_i, rlc_i)) < 0) { char *c; ret = rlc_error_info(&c); rmdp_my_error (-1, "Error %d in protocol initialization (%s)\n", ret, c); } #ifdef HAVE_UI /* enable UI in rmdp */ if ((ret = rmdp_enable_gui(rmdp_i)) < 0) { char *c; ret = rlc_error_info(&c); rmdp_my_error (-1, "Error %d in protocol initialization (%s)\n", ret, c); } else if (sessname != NULL && (ret = rmdp_set_name (rmdp_i, sessname)) < 0) { char *c; ret = rlc_error_info(&c); rmdp_my_error (-1, "Error %d in protocol initialization (%s)\n", ret, c); } #endif /* possibly setup rlc log facility */ if (ev_f || po_f) (void)rlc_rx_log(rlc_i, ev_f, po_f); /* start the reception */ if ((ret = rlc_start(rlc_i)) < 0) { char *c; ret = rlc_error_info(&c); rmdp_delete(rmdp_i); rmdp_my_error(-1, "error %d in rlc_rx_start (%s)\n", ret, c); } while (rlc_getevent(1)!=EV_TERMINATE); exit(0); } rmdp/RMDPft.c010064400373640000764000000304660657252154400145200ustar00ucaclxvcsstaff00002440000013#include #include #include #include #include #include #include #include #include #if defined(Linux) #include #endif #include #include "rmdpif.h" #define USAGE \ "Usage:\n\t RMDPft -[tifCGxgep] m.cast.ip/port/ttl" \ "\n\t RMDPft -s -[tifCGxgI] m.cast.ip/port/ttl\n" \ "options:\n" \ "\t-s \t\t\t Is sender (receiver by default)\n" \ "\t-i \n" \ "\t-f \n" \ "\t-C \n" \ "\t-G \t\t\t Use GUI (only if compiled in)\n" \ "\t-x \t\t\t Ask for filename\n" \ "\t-g \n" \ "\t-e \t (receiver only)\n" \ "\t-p \t (receiver only)\n" \ "\t-I \t\t\t Sender never stops\n" \ "\t-m \t\t\t Multicast feedback, def.is Unicast (rec.only)\n" \ "\t-F \t Log file for stats report (sender only)\n"\ "\t-h \t\t\t Prints the usage message\n" static int isreceiver = 1; /* receiver by default */ #define ISR ((isreceiver>0)?1:0) int rlc_i; /* rlc instance id */ int rmdp_i; /* rmdp instance id */ int fd = -1; /* IO file */ int chosefile = 0; char *sessname=NULL; char *geometry=NULL; #ifdef HAVE_UI int guicompiled = 1; #else int guicompiled = 0; #endif void badcmdline(char *arg) { rmdp_my_error(-1, "Bad argument %s\n" USAGE , arg); /* "\t-n \n" */ /* "\t-d \n" */ } int open_n_check(char *filn, int wr) { int fd = -1; #ifdef HAVE_UI int res; char *tit, *ret = NULL; #endif if (!strcmp(filn, "-")) { if (wr) return 1; else return 0; } else if (!strcmp(filn, "-GUI") && !wr) { #ifdef HAVE_UI if (sessname) tit = sessname; else tit = "RMDP"; res = rlc_gui_tcl_exec (rlc_i, &ret, "tk_getOpenFile -title {%s : Open File}", tit); if (res >= 0 && ret != NULL && ret[0] != '\0') filn = ret; #else return -1; #endif } if ((wr && (fd = open (filn, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) || (!wr && (fd = open (filn, O_RDONLY)) < 0)) { return (-1); } else { return (fd); } } void install_help () { #ifdef HAVE_UI char *ret; if ( rlc_gui_tcl_exec (rlc_i, &ret, "set RMDPftINFOS {" USAGE "}") == 0) { if (rlc_gui_tcl_exec (rlc_i, &ret, "if [info exist HelpButt] {" "$HelpButt add command -label \"About RMDPft\" -command " "\"show_infos {$RMDPftINFOS} \\\"About RMDPft\\\"\"" "}") != 0) fprintf(stderr, "** add command returns : %s\n", ret); } else fprintf(stderr, "** set RMDPftINFOS returns : %s\n", ret); #endif } /* this handle the termination of * the current reception */ void reception_end(int rmdp_i, int success) { if (success >= 0 && chosefile) { #ifdef HAVE_UI char *ret = NULL; int res; if (sessname) res = rlc_gui_tcl_exec (rlc_i, &ret, "tk_getSaveFile -title {%s : Save File}", sessname); else res = rlc_gui_tcl_exec (rlc_i, &ret, "tk_getSaveFile -title \"RMDP : Save File\""); if (res >= 0 && ret != NULL) { if (ret[0] != '\0') { if ((fd = open_n_check(ret, ISR)) >= 0) { rmdp_set_io(rmdp_i, fd); } else rmdp_my_error (rmdp_i, "Error opening out file (%s)\n", ret); } else { rmdp_my_error (rmdp_i, "No file selected!\n"); } free(ret); } else { rmdp_my_error (rmdp_i, "rlc gui error|\n"); } #endif } else if (success < 0) { rmdp_my_error (rmdp_i, "Decoding error ? \n"); } /* in this example just abort the reception instance */ rlc_abort(rlc_i); /* rmdp_delete(rmdp_i); */ } int main(int argc, char *argv[]) { char *dataaddr = NULL; char *tmpfilename = NULL; char *statsrepfile = NULL; int tttl, ttl = 5; int have_gui = 0; int multifeed = 0; int stafd = -1; int ret; char *ev_f = NULL , *po_f = NULL ; char tmpaddr[512]; unsigned long addr0; short port; int pkt_size; /* rmdp payload + rmdp header */ int pid = -1; addr_list_t taddr; rmdp_addr_t adds; int errflg = 0, i; rmdp_rx_packet_t rx_f; int layers; /* # of layers */ unsigned long base_rate = 16 * 1024; /* input parms ? */ unsigned long p; int nostop = 0; rlc_tx_params_t parml; extern char *optarg; extern int optind; /* parse command line... */ while ((i = getopt(argc,argv,"hsd:t:i:f:C:Gxg:Ime:p:F:")) != EOF) switch(i) { case 'h': /* help */ badcmdline("?"); break; case 's': /* is sender ! */ isreceiver = 0; break; case 'd': /* data addr/port */ if ((dataaddr = malloc(strlen(optarg)+1)) == NULL) break; strncpy(dataaddr, optarg, strlen(optarg)+1); break; case 't': /* TTL */ ttl = atoi(optarg); if (ttl <= 0 || ttl > 255) badcmdline(optarg); break; case 'i': /* pid */ pid = atoi(optarg); break; case 'f': /* input/output file */ if ((tmpfilename = malloc(strlen(optarg)+1)) == NULL) break; strncpy(tmpfilename, optarg, strlen(optarg)+1); break; case 'C': /* session name */ if ((sessname = malloc(strlen(optarg)+1)) == NULL) break; strcpy (sessname, optarg); break; case 'G': /* have GUI */ have_gui = 1; break; case 'x': /* GUI select I/O file */ chosefile = 1; break; case 'g': /* geometry */ if ((geometry = malloc(strlen(optarg)+1)) == NULL) break; strcpy (geometry, optarg); break; case 'I': /* sender no-stop */ nostop = 1; break; case 'm': /* multicast feedback */ multifeed = 1; break; case 'e': /* event log file */ ev_f = (char *)calloc(strlen(optarg)+1, sizeof(char)); strncpy(ev_f, optarg, strlen(optarg)+1); break; case 'p': /* poll log file */ po_f = (char *)calloc(strlen(optarg)+1, sizeof(char)); strncpy(po_f, optarg, strlen(optarg)+1); break; case 'F': /* stats report file */ if ((statsrepfile = malloc(strlen(optarg)+1)) == NULL) break; strncpy(statsrepfile, optarg, strlen(optarg)+1); break; case '?': default: errflg++; } if (errflg) badcmdline("?"); argc -= optind; argv += optind; if (argc > 0 && (dataaddr = malloc(strlen(argv[0])+1)) != NULL) { strncpy(dataaddr, argv[0], strlen(argv[0])+1); } /* and now some checks... */ if (have_gui && !guicompiled) badcmdline("GUI is not compiled in!"); if (!dataaddr) badcmdline("must provide destination address"); if ( !chosefile && ((!tmpfilename && (fd = open_n_check("-", ISR)) < 0) || (tmpfilename && (fd = open_n_check(tmpfilename, ISR)) < 0)) ) { badcmdline("input file name"); } if (isreceiver && nostop) badcmdline("no-stop option only for the sender"); if (!isreceiver && (ev_f || po_f)) badcmdline("logging facility only in the receiver"); if (!have_gui && (chosefile || geometry)) badcmdline("GUI is disabled!"); if (isreceiver && statsrepfile) badcmdline("-F option only for the sender"); if (statsrepfile && (stafd = open_n_check(statsrepfile, 1)) < 0) badcmdline("cannot open stats report file"); /* extract address (string) and port (short) from the * input parameter (x.x.x.x/yyy) */ #if 1 if (rmdp_n_parse_addr(dataaddr, tmpaddr, sizeof(tmpaddr), &port, &tttl, "data") < 0) { char *c; ret = rlc_error_info(&c); rmdp_my_error (-1, "Error %d in rmdp_parse_addr (%s)\n", ret, c); } if (tttl >= 0 && tttl <= 255) ttl = tttl; #else if (rmdp_parse_addr(dataaddr, tmpaddr, sizeof(tmpaddr), &port, "data") < 0) { char *c; ret = rlc_error_info(&c); rmdp_my_error (-1, "Error %d in rmdp_parse_addr (%s)\n", ret, c); } #endif addr0 = ntohl(inet_addr(tmpaddr)); adds.addr = addr0; adds.port = port+1; adds.ttl = ttl; /* setup an rmdp receiver instance */ if ((ret = rmdp_i = rmdp_new (isreceiver)) < 0 || (ret = rmdp_set_addr (rmdp_i, &adds)) < 0 || (fd >= 0 && (ret = rmdp_set_io (rmdp_i, fd)) < 0) ) { char *c; ret = rlc_error_info(&c); rmdp_my_error (-1, "Error %d in protocol initialization (%s)\n", ret, c); } if (pid != -1 && (ret = rmdp_set_id(rmdp_i, pid)) < 0) { char *c; ret = rlc_error_info(&c); rmdp_my_error (-1, "Error %d in protocol initialization (%s)\n", ret, c); } /* set reception-end callback */ if (isreceiver) { if ((ret = rmdp_set_end_callback(rmdp_i, reception_end)) < 0) { char *c; ret = rlc_error_info(&c); rmdp_my_error (-1, "Error %d in rmdp_set_end_callback (%s)\n", ret, c); } if (multifeed && (ret = rmdp_rx_enable_multifeed(rmdp_i, 1)) < 0) { char *c; ret = rlc_error_info(&c); rmdp_my_error (-1, "Error %d in rmdp_rx_enable_multifeed (%s)\n", ret, c); } } /* get data reception/transmission handler function from rmdp */ if ((ret = rmdp_get_f(rmdp_i, (void **)(&rx_f))) < 0) { char *c; ret = rlc_error_info(&c); rmdp_my_error (-1, "Error %d in rmdp_get_f (%s)\n", ret, c); } taddr.nadd = 1; taddr.addrs = &addr0; taddr.port = port; taddr.ttl = ttl; /* setup a rlc instance */ if ((ret = rlc_i = rlc_new (isreceiver)) < 0 || (ret = rlc_set_addr (rlc_i, &taddr)) < 0 || (ret = rlc_attach (rlc_i, rmdp_i, (void *)rx_f)) < 0 ) { char *c; ret = rlc_error_info(&c); rmdp_delete(rmdp_i); rmdp_my_error(-1, "error %d in rlc_setup (%s)\n", ret, c); } if ((ret = rmdp_set_rlc (rmdp_i, rlc_i)) < 0) { char *c; ret = rlc_error_info(&c); rmdp_my_error (-1, "Error %d in protocol initialization (%s)\n", ret, c); } if (!isreceiver) { /* retrieve rmdp packet size (rlc payload) */ pkt_size = rmdp_get_psize(rmdp_i); /* retrieve rmdp number of layers */ layers = rmdp_get_nlay(rmdp_i); /* this is the interpacket-period (us) in the upper session */ p = 1e6 * (pkt_size) * 8 / base_rate / (1<<(layers-1)); parml.nlay = layers; parml.mpkts = pkt_size; parml.Mpkts = pkt_size; parml.t = p; if ((ret = rlc_tx_setup(rlc_i, &parml)) < 0) { char *c; ret = rlc_error_info(&c); rmdp_delete(rmdp_i); rmdp_my_error(-1, "error %d in rlc_tx_setup (%s)\n", ret, c); } if (nostop) { unsigned long left = rmdp_get_left (rmdp_i); if ((ret = rmdp_incr_left (rmdp_i, RMDP_LEFT_INFINITE - left)) < 0) { char *c; ret = rlc_error_info(&c); rmdp_my_error (-1, "Error %d in protocol initialization (%s)\n", ret, c); } } } /* setup rlc idle watchdog */ if (isreceiver && (ret = rlc_rx_set_watchdog(rlc_i, NULL, 0)) < 0) { char *c; ret = rlc_error_info(&c); rmdp_delete(rmdp_i); rmdp_my_error(-1, "error %d in rlc_rx_setup (%s)\n", ret, c); } #ifdef HAVE_UI if (have_gui) { if (geometry) rlc_gui_geometry (rlc_i, geometry); if ((ret = rlc_gui_enable(rlc_i)) < 0) { char *c; ret = rlc_error_info(&c); rmdp_delete(rmdp_i); rmdp_my_error(-1, "error %d in rlc_gui_enable (%s)\n", ret, c); } /* enable UI in rmdp */ if ((ret = rmdp_enable_gui(rmdp_i)) < 0) { char *c; ret = rlc_error_info(&c); rmdp_my_error (-1, "Error %d in protocol initialization (%s)\n", ret, c); } if (sessname != NULL && (ret = rmdp_set_name (rmdp_i, sessname)) < 0) { char *c; ret = rlc_error_info(&c); rmdp_my_error (-1, "Error %d in protocol initialization (%s)\n", ret, c); } install_help (); if (!isreceiver && fd < 0 && chosefile && ( (fd = open_n_check("-GUI", ISR)) < 0 || (ret = rmdp_set_io (rmdp_i, fd)) < 0 ) ) { char *c; ret = rlc_error_info(&c); rmdp_my_error (-1, "Error %d in protocol initialization (%s)\n", ret, c); } } #endif /* possibly setup rlc log facility */ if (isreceiver && (ev_f || po_f)) (void)rlc_rx_log(rlc_i, ev_f, po_f); if (isreceiver && (ret = rmdp_set_stat_reports (rmdp_i, 1) ) < 0) { char *c; ret = rlc_error_info(&c); rmdp_my_error (-1, "Error %d in rmdp_set_stat_reports (%s)\n", ret, c); } if (!isreceiver && stafd >= 0 && (ret = rmdp_set_stat_reports (rmdp_i, stafd)) < 0) { char *c; ret = rlc_error_info(&c); rmdp_my_error (-1, "Error %d in rmdp_set_stat_reports (%s)\n", ret, c); } /* start the reception */ if ((ret = rlc_start(rlc_i)) < 0) { char *c; ret = rlc_error_info(&c); rmdp_delete(rmdp_i); rmdp_my_error(-1, "error %d in rlc_start (%s)\n", ret, c); } while (rlc_getevent(1)!=EV_TERMINATE); exit(0); }