00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <errno.h>
00024 #include <fcntl.h>
00025 #include <limits.h>
00026 #include <netdb.h>
00027 #include <poll.h>
00028 #include <signal.h>
00029 #include <stddef.h>
00030 #include <stdint.h>
00031 #include <stdio.h>
00032 #include <stdlib.h>
00033 #include <string.h>
00034 #include <time.h>
00035 #include <unistd.h>
00036 #include <arpa/inet.h>
00037 #include <sys/time.h>
00038 #include <sys/socket.h>
00039 #include <sys/stat.h>
00040 #include <sys/types.h>
00041 #include <sys/un.h>
00042 #include <netinet/in.h>
00043
00044 #include <ccn/bloom.h>
00045 #include <ccn/ccn.h>
00046 #include <ccn/ccn_private.h>
00047 #include <ccn/charbuf.h>
00048 #include <ccn/face_mgmt.h>
00049 #include <ccn/hashtb.h>
00050 #include <ccn/indexbuf.h>
00051 #include <ccn/schedule.h>
00052 #include <ccn/reg_mgmt.h>
00053 #include <ccn/uri.h>
00054
00055 #include "ccnr_private.h"
00056
00057 #include "ccnr_sendq.h"
00058
00059 #include "ccnr_io.h"
00060 #include "ccnr_link.h"
00061 #include "ccnr_msg.h"
00062 #include "ccnr_store.h"
00063
00064 static int
00065 choose_face_delay(struct ccnr_handle *h, struct fdholder *fdholder, enum cq_delay_class c)
00066 {
00067 if (fdholder->flags & CCNR_FACE_CCND)
00068 return(1);
00069 if (fdholder->flags & CCNR_FACE_REPODATA)
00070 return(1);
00071 return(1);
00072 }
00073
00074 static struct content_queue *
00075 content_queue_create(struct ccnr_handle *h, struct fdholder *fdholder, enum cq_delay_class c)
00076 {
00077 struct content_queue *q;
00078 unsigned usec;
00079 q = calloc(1, sizeof(*q));
00080 if (q != NULL) {
00081 usec = choose_face_delay(h, fdholder, c);
00082 q->burst_nsec = (usec <= 500 ? 500 : 150000);
00083 q->min_usec = usec;
00084 q->rand_usec = 2 * usec;
00085 q->nrun = 0;
00086 q->send_queue = ccn_indexbuf_create();
00087 if (q->send_queue == NULL) {
00088 free(q);
00089 return(NULL);
00090 }
00091 q->sender = NULL;
00092 }
00093 return(q);
00094 }
00095
00096 PUBLIC void
00097 r_sendq_content_queue_destroy(struct ccnr_handle *h, struct content_queue **pq)
00098 {
00099 struct content_queue *q;
00100 if (*pq != NULL) {
00101 q = *pq;
00102 ccn_indexbuf_destroy(&q->send_queue);
00103 if (q->sender != NULL) {
00104 ccn_schedule_cancel(h->sched, q->sender);
00105 q->sender = NULL;
00106 }
00107 free(q);
00108 *pq = NULL;
00109 }
00110 }
00111
00112 static enum cq_delay_class
00113 choose_content_delay_class(struct ccnr_handle *h, unsigned filedesc, int content_flags)
00114 {
00115 return(CCN_CQ_NORMAL);
00116 }
00117
00118 static unsigned
00119 randomize_content_delay(struct ccnr_handle *h, struct content_queue *q)
00120 {
00121 unsigned usec;
00122
00123 usec = q->min_usec + q->rand_usec;
00124 if (usec < 2)
00125 return(1);
00126 if (usec <= 20 || q->rand_usec < 2)
00127 return(usec);
00128 usec = q->min_usec + (nrand48(h->seed) % q->rand_usec);
00129 if (usec < 2)
00130 return(1);
00131 return(usec);
00132 }
00133
00134 static int
00135 content_sender(struct ccn_schedule *sched,
00136 void *clienth,
00137 struct ccn_scheduled_event *ev,
00138 int flags)
00139 {
00140 int i, j;
00141 int delay;
00142 int nsec;
00143 int burst_nsec;
00144 int burst_max;
00145 struct ccnr_handle *h = clienth;
00146 struct content_entry *content = NULL;
00147 unsigned filedesc = ev->evint;
00148 struct fdholder *fdholder = NULL;
00149 struct content_queue *q = ev->evdata;
00150 (void)sched;
00151
00152 if ((flags & CCN_SCHEDULE_CANCEL) != 0)
00153 goto Bail;
00154 fdholder = r_io_fdholder_from_fd(h, filedesc);
00155 if (fdholder == NULL)
00156 goto Bail;
00157 if (q->send_queue == NULL)
00158 goto Bail;
00159 if ((fdholder->flags & CCNR_FACE_NOSEND) != 0)
00160 goto Bail;
00161
00162 if (q->ready > q->send_queue->n ||
00163 (q->ready == 0 && q->nrun >= 12 && q->nrun < 120))
00164 q->ready = q->send_queue->n;
00165 nsec = 0;
00166 burst_nsec = q->burst_nsec;
00167 burst_max = 2;
00168 if (q->ready < burst_max)
00169 burst_max = q->ready;
00170 if (burst_max == 0)
00171 q->nrun = 0;
00172 for (i = 0; i < burst_max && nsec < 1000000; i++) {
00173 content = r_store_content_from_cookie(h, q->send_queue->buf[i]);
00174 if (content == NULL)
00175 q->nrun = 0;
00176 else {
00177 r_link_send_content(h, fdholder, content);
00178
00179 if (r_io_fdholder_from_fd(h, filedesc) == NULL)
00180 goto Bail;
00181
00182 q->nrun++;
00183 }
00184 }
00185 if (q->ready < i) abort();
00186 q->ready -= i;
00187
00188 for (j = 0; i < q->send_queue->n; i++, j++)
00189 q->send_queue->buf[j] = q->send_queue->buf[i];
00190 q->send_queue->n = j;
00191
00192 delay = (nsec + 499) / 1000 + 1;
00193 if (q->ready > 0) {
00194 return(delay);
00195 }
00196 q->ready = j;
00197 if (q->nrun >= 12 && q->nrun < 120) {
00198
00199 if (j == 0)
00200 delay += burst_nsec / 50;
00201 return(delay);
00202 }
00203
00204 for (i = 0; i < q->send_queue->n; i++) {
00205 content = r_store_content_from_cookie(h, q->send_queue->buf[i]);
00206 if (content != NULL) {
00207 q->nrun = 0;
00208 delay = randomize_content_delay(h, q);
00209 if (CCNSHOULDLOG(h, LM_8, CCNL_FINER))
00210 ccnr_msg(h, "fdholder %u queued %u delay %i",
00211 (unsigned)ev->evint, q->ready, delay);
00212 return(delay);
00213 }
00214 }
00215 q->send_queue->n = q->ready = 0;
00216 Bail:
00217 q->sender = NULL;
00218 return(0);
00219 }
00220
00221 PUBLIC int
00222 r_sendq_face_send_queue_insert(struct ccnr_handle *h,
00223 struct fdholder *fdholder, struct content_entry *content)
00224 {
00225 int ans = -1;
00226 int delay;
00227 enum cq_delay_class c;
00228 struct content_queue *q;
00229 if (fdholder == NULL || content == NULL || (fdholder->flags & CCNR_FACE_NOSEND) != 0)
00230 return(-1);
00231 c = choose_content_delay_class(h, fdholder->filedesc, r_store_content_flags(content));
00232 if (fdholder->q[c] == NULL)
00233 fdholder->q[c] = content_queue_create(h, fdholder, c);
00234 q = fdholder->q[c];
00235 if (q == NULL)
00236 return(-1);
00237 ans = ccn_indexbuf_set_insert(q->send_queue, r_store_content_cookie(h, content));
00238 if (q->sender == NULL) {
00239 delay = randomize_content_delay(h, q);
00240 q->ready = q->send_queue->n;
00241 q->sender = ccn_schedule_event(h->sched, delay,
00242 content_sender, q, fdholder->filedesc);
00243 if (CCNSHOULDLOG(h, LM_8, CCNL_FINER))
00244 ccnr_msg(h, "fdholder %u q %d delay %d usec", fdholder->filedesc, c, delay);
00245 }
00246 return (ans);
00247 }