├── Makefile ├── main.c ├── rudp.c └── rudp.h /Makefile: -------------------------------------------------------------------------------- 1 | rudp.exe : rudp.c main.c 2 | gcc -g -Wall -o $@ $^ 3 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include "rudp.h" 2 | #include 3 | #include 4 | 5 | static void 6 | dump_recv(struct rudp *U) { 7 | char tmp[MAX_PACKAGE]; 8 | int n; 9 | while ((n = rudp_recv(U, tmp))) { 10 | if (n < 0) { 11 | printf("CORRPUT\n"); 12 | break; 13 | } 14 | int i; 15 | printf("RECV "); 16 | for (i=0;isz;i++) { 31 | printf("%02x ", (uint8_t)p->buffer[i]); 32 | } 33 | printf(") "); 34 | p=p->next; 35 | } 36 | printf("\n"); 37 | } 38 | 39 | int 40 | main() { 41 | struct rudp *U = rudp_new(1, 5); 42 | 43 | char t1[] = { 1,2,3,4 }; 44 | char t2[] = { 5,6,7,8 }; 45 | char t3[] = { 46 | 2,1,1,1,1,1,1,3,2,1,1,1,1,1,1,3, 47 | 2,1,1,1,1,1,1,3,2,1,1,1,1,1,1,3, 48 | 2,1,1,1,1,1,1,3,2,1,1,1,1,1,1,3, 49 | 2,1,1,1,1,1,1,3,2,1,1,1,1,1,1,3, 50 | 2,1,1,1,1,1,1,3,2,1,1,1,1,1,1,3, 51 | 2,1,1,1,1,1,1,3,2,1,1,1,1,1,1,3, 52 | 2,1,1,1,1,1,1,3,2,1,1,1,1,1,1,3, 53 | 2,1,1,1,1,1,1,3,2,1,1,1,1,1,1,3, 54 | 2,1,1,1,1,1,1,3,2,1,1,1,1,1,1,3, 55 | 2,1,1,1,1,1,1,3,2,1,1,1,1,1,1,3, 56 | 2,1,1,1,1,1,1,3,2,1,1,1,1,1,1,3, 57 | 2,1,1,1,1,1,1,3,2,1,1,1,1,1,1,3, 58 | 2,1,1,1,1,1,1,3,2,1,1,1,1,1,1,3, 59 | 2,1,1,1,1,1,1,3,2,1,1,1,1,1,1,3, 60 | 2,1,1,1,1,1,1,3,2,1,1,1,1,1,1,3, 61 | 2,1,1,1,1,1,1,3,2,1,1,1,10,11,12,13, 62 | }; 63 | char t4[] = { 4,3,2,1 }; 64 | 65 | rudp_send(U, t1, sizeof(t1)); 66 | rudp_send(U, t2, sizeof(t2)); 67 | dump(rudp_update(U, NULL, 0, 1)); 68 | dump(rudp_update(U, NULL, 0, 1)); 69 | rudp_send(U, t3, sizeof(t3)); 70 | rudp_send(U, t4, sizeof(t4)); 71 | dump(rudp_update(U, NULL, 0, 1)); 72 | 73 | char r1[] = { 02, 00, 00, 02, 00, 03 }; 74 | dump(rudp_update(U, r1, sizeof(r1), 1)); 75 | dump_recv(U); 76 | char r2[] = { 5, 0, 1, 1, 77 | 5, 0, 3, 3, 78 | }; 79 | dump(rudp_update(U, r2, sizeof(r2), 1)); 80 | dump_recv(U); 81 | char r3[] = { 5, 0, 0, 0, 82 | 5, 0, 5, 5, 83 | }; 84 | dump(rudp_update(U, r3, sizeof(r3), 0)); 85 | char r4[] = { 5, 0, 2, 2 }; 86 | dump(rudp_update(U, r4, sizeof(r4), 1)); 87 | 88 | dump_recv(U); 89 | 90 | rudp_delete(U); 91 | return 0; 92 | } 93 | -------------------------------------------------------------------------------- /rudp.c: -------------------------------------------------------------------------------- 1 | #include "rudp.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | //#define GENERAL_PACKAGE 512 9 | #define GENERAL_PACKAGE 128 10 | 11 | struct message { 12 | struct message * next; 13 | uint8_t *buffer; 14 | int sz; 15 | int cap; 16 | int id; 17 | int tick; 18 | }; 19 | 20 | struct message_queue { 21 | struct message *head; 22 | struct message *tail; 23 | }; 24 | 25 | struct array { 26 | int cap; 27 | int n; 28 | int *a; 29 | }; 30 | 31 | struct rudp { 32 | struct message_queue send_queue; // user packages will send 33 | struct message_queue recv_queue; // the packages recv 34 | struct message_queue send_history; // user packages already send 35 | 36 | struct rudp_package *send_package; // returns by rudp_update 37 | 38 | struct message *free_list; // recycle message struct 39 | struct array send_again; // package id need send again 40 | 41 | int corrupt; 42 | int current_tick; 43 | int last_send_tick; 44 | int last_expired_tick; 45 | int send_id; 46 | int recv_id_min; 47 | int recv_id_max; 48 | int send_delay; 49 | int expired; 50 | }; 51 | 52 | struct rudp * 53 | rudp_new(int send_delay, int expired_time) { 54 | struct rudp * U = malloc(sizeof(*U)); 55 | memset(U, 0, sizeof(*U)); 56 | U->send_delay = send_delay; 57 | U->expired = expired_time; 58 | return U; 59 | } 60 | 61 | static void 62 | clear_outpackage(struct rudp *U) { 63 | struct rudp_package *tmp = U->send_package; 64 | while (tmp) { 65 | struct rudp_package *next = tmp->next; 66 | free(tmp); 67 | tmp = next; 68 | } 69 | U->send_package = NULL; 70 | } 71 | 72 | static void 73 | free_message_list(struct message *m) { 74 | while (m) { 75 | struct message *next = m->next; 76 | free(m); 77 | m = next; 78 | } 79 | } 80 | 81 | void 82 | rudp_delete(struct rudp *U) { 83 | free_message_list(U->send_queue.head); 84 | free_message_list(U->recv_queue.head); 85 | free_message_list(U->send_history.head); 86 | free_message_list(U->free_list); 87 | clear_outpackage(U); 88 | free(U->send_again.a); 89 | free(U); 90 | } 91 | 92 | static struct message * 93 | new_message(struct rudp *U, const uint8_t *buffer, int sz) { 94 | struct message * tmp = U->free_list; 95 | if (tmp) { 96 | U->free_list = tmp->next; 97 | if (tmp->cap < sz) { 98 | free(tmp); 99 | tmp = NULL; 100 | } 101 | } 102 | if (tmp == NULL) { 103 | int cap = sz; 104 | if (cap < GENERAL_PACKAGE) { 105 | cap = GENERAL_PACKAGE; 106 | } 107 | tmp = malloc(sizeof(struct message) + cap); 108 | tmp->cap = cap; 109 | } 110 | tmp->sz = sz; 111 | tmp->buffer = (uint8_t *)(tmp+1); 112 | if (sz > 0 && buffer) { 113 | memcpy(tmp->buffer, buffer, sz); 114 | } 115 | tmp->tick = 0; 116 | tmp->id = 0; 117 | tmp->next = NULL; 118 | return tmp; 119 | } 120 | 121 | static void 122 | delete_message(struct rudp *U, struct message *m) { 123 | m->next = U->free_list; 124 | U->free_list = m; 125 | } 126 | 127 | static void 128 | queue_push(struct message_queue *q, struct message *m) { 129 | if (q->tail == NULL) { 130 | q->head = q->tail = m; 131 | } else { 132 | q->tail->next = m; 133 | q->tail = m; 134 | } 135 | } 136 | 137 | static struct message * 138 | queue_pop(struct message_queue *q, int id) { 139 | if (q->head == NULL) 140 | return NULL; 141 | struct message *m = q->head; 142 | if (m->id != id) 143 | return NULL; 144 | q->head = m->next; 145 | m->next = NULL; 146 | if (q->head == NULL) 147 | q->tail = NULL; 148 | return m; 149 | } 150 | 151 | static void 152 | array_insert(struct array *a, int id) { 153 | int i; 154 | for (i=0;in;i++) { 155 | if (a->a[i] == id) 156 | return; 157 | if (a->a[i] > id) { 158 | break; 159 | } 160 | } 161 | // insert before i 162 | if (a->n >= a->cap) { 163 | if (a->cap == 0) { 164 | a->cap = 16; 165 | } else { 166 | a->cap *= 2; 167 | } 168 | a->a = realloc(a->a, sizeof(int) * a->cap); 169 | } 170 | int j; 171 | for (j=a->n;j>i;j--) { 172 | a->a[j] = a->a[j-1]; 173 | } 174 | a->a[i] = id; 175 | ++a->n; 176 | } 177 | 178 | void 179 | rudp_send(struct rudp *U, const char *buffer, int sz) { 180 | assert(sz <= MAX_PACKAGE); 181 | struct message *m = new_message(U, (const uint8_t *)buffer, sz); 182 | m->id = U->send_id++; 183 | m->tick = U->current_tick; 184 | queue_push(&U->send_queue, m); 185 | } 186 | 187 | int 188 | rudp_recv(struct rudp *U, char buffer[MAX_PACKAGE]) { 189 | if (U->corrupt) { 190 | U->corrupt = 0; 191 | return -1; 192 | } 193 | struct message *tmp = queue_pop(&U->recv_queue, U->recv_id_min); 194 | if (tmp == NULL) { 195 | return 0; 196 | } 197 | ++U->recv_id_min; 198 | int sz = tmp->sz; 199 | if (sz > 0) { 200 | memcpy(buffer, tmp->buffer, sz); 201 | } 202 | delete_message(U, tmp); 203 | return sz; 204 | } 205 | 206 | static void 207 | clear_send_expired(struct rudp *U, int tick) { 208 | struct message *m = U->send_history.head; 209 | struct message *last = NULL; 210 | while (m) { 211 | if (m->tick >= tick) { 212 | break; 213 | } 214 | last = m; 215 | m = m->next; 216 | } 217 | if (last) { 218 | // free all the messages before tick 219 | last->next = U->free_list; 220 | U->free_list = U->send_history.head; 221 | } 222 | U->send_history.head = m; 223 | if (m == NULL) { 224 | U->send_history.tail = NULL; 225 | } 226 | } 227 | 228 | static int 229 | get_id(struct rudp *U, const uint8_t * buffer) { 230 | int id = buffer[0] * 256 + buffer[1]; 231 | id |= U->recv_id_max & ~0xffff; 232 | if (id < U->recv_id_max - 0x8000) 233 | id += 0x10000; 234 | else if (id > U->recv_id_max + 0x8000) 235 | id -= 0x10000; 236 | return id; 237 | } 238 | 239 | static void 240 | add_request(struct rudp *U, int id) { 241 | array_insert(&U->send_again, id); 242 | } 243 | 244 | static void 245 | insert_message(struct rudp *U, int id, const uint8_t *buffer, int sz) { 246 | if (id < U->recv_id_min) 247 | return; 248 | if (id > U->recv_id_max || U->recv_queue.head == NULL) { 249 | struct message *m = new_message(U, buffer, sz); 250 | m->id = id; 251 | queue_push(&U->recv_queue, m); 252 | U->recv_id_max = id; 253 | } else { 254 | struct message *m = U->recv_queue.head; 255 | struct message **last = &U->recv_queue.head; 256 | do { 257 | if (m->id == id) { return; } 258 | if (m->id > id) { 259 | // insert here 260 | struct message *tmp = new_message(U, buffer, sz); 261 | tmp->id= id; 262 | tmp->next = m; 263 | *last = tmp; 264 | return; 265 | } 266 | last = &m->next; 267 | m = m->next; 268 | } while(m); 269 | } 270 | } 271 | 272 | static void 273 | add_missing(struct rudp *U, int id) { 274 | insert_message(U, id, NULL, -1); 275 | } 276 | 277 | #define TYPE_IGNORE 0 278 | #define TYPE_CORRUPT 1 279 | #define TYPE_REQUEST 2 280 | #define TYPE_MISSING 3 281 | #define TYPE_NORMAL 4 282 | 283 | static void 284 | extract_package(struct rudp *U, const uint8_t *buffer, int sz) { 285 | while (sz > 0) { 286 | int len = buffer[0]; 287 | if (len > 127) { 288 | if (sz <= 1) { 289 | U->corrupt = 1; 290 | return; 291 | } 292 | len = (len * 256 + buffer[1]) & 0x7fff; 293 | buffer += 2; 294 | sz -= 2; 295 | } else { 296 | buffer += 1; 297 | sz -= 1; 298 | } 299 | switch (len) { 300 | case TYPE_IGNORE: 301 | if (U->send_again.n == 0) { 302 | // request next package id 303 | array_insert(&U->send_again, U->recv_id_min); 304 | } 305 | break; 306 | case TYPE_CORRUPT: 307 | U->corrupt = 1; 308 | return; 309 | case TYPE_REQUEST: 310 | case TYPE_MISSING: 311 | if (sz < 2) { 312 | U->corrupt = 1; 313 | return; 314 | } 315 | (len == TYPE_REQUEST ? add_request : add_missing)(U, get_id(U,buffer)); 316 | buffer += 2; 317 | sz -= 2; 318 | break; 319 | default: 320 | len -= TYPE_NORMAL; 321 | if (sz < len + 2) { 322 | U->corrupt = 1; 323 | return; 324 | } else { 325 | int id = get_id(U, buffer); 326 | insert_message(U, id, buffer+2, len); 327 | } 328 | buffer += len + 2; 329 | sz -= len + 2; 330 | break; 331 | } 332 | } 333 | } 334 | 335 | struct tmp_buffer { 336 | uint8_t buf[GENERAL_PACKAGE]; 337 | int sz; 338 | struct rudp_package *head; 339 | struct rudp_package *tail; 340 | }; 341 | 342 | static void 343 | new_package(struct rudp *U, struct tmp_buffer *tmp) { 344 | struct rudp_package * p = malloc(sizeof(*p) + tmp->sz); 345 | p->next = NULL; 346 | p->buffer = (char *)(p+1); 347 | p->sz = tmp->sz; 348 | memcpy(p->buffer, tmp->buf, tmp->sz); 349 | if (tmp->tail == NULL) { 350 | tmp->head = tmp->tail = p; 351 | } else { 352 | tmp->tail->next = p; 353 | tmp->tail = p; 354 | } 355 | tmp->sz = 0; 356 | } 357 | 358 | static int 359 | fill_header(uint8_t *buf, int len, int id) { 360 | int sz; 361 | if (len < 128) { 362 | buf[0] = len; 363 | ++buf; 364 | sz = 1; 365 | } else { 366 | buf[0] = ((len & 0x7f00) >> 8) | 0x80; 367 | buf[1] = len & 0xff; 368 | buf+=2; 369 | sz = 2; 370 | } 371 | buf[0] = (id & 0xff00) >> 8; 372 | buf[1] = id & 0xff; 373 | return sz + 2; 374 | } 375 | 376 | static void 377 | pack_request(struct rudp *U, struct tmp_buffer *tmp, int id, int tag) { 378 | int sz = GENERAL_PACKAGE - tmp->sz; 379 | if (sz < 3) { 380 | new_package(U, tmp); 381 | } 382 | uint8_t * buffer = tmp->buf + tmp->sz; 383 | tmp->sz += fill_header(buffer, tag, id); 384 | } 385 | 386 | static void 387 | pack_message(struct rudp *U, struct tmp_buffer *tmp, struct message *m) { 388 | int sz = GENERAL_PACKAGE - tmp->sz; 389 | if (m->sz > GENERAL_PACKAGE - 4) { 390 | if (tmp->sz > 0) 391 | new_package(U, tmp); 392 | // big package 393 | sz = 4 + m->sz; 394 | struct rudp_package * p = malloc(sizeof(*p) + sz); 395 | p->next = NULL; 396 | p->buffer = (char *)(p+1); 397 | p->sz = sz; 398 | fill_header((uint8_t *)p->buffer, m->sz + TYPE_NORMAL, m->id); 399 | memcpy(p->buffer+4, m->buffer, m->sz); 400 | if (tmp->tail == NULL) { 401 | tmp->head = tmp->tail = p; 402 | } else { 403 | tmp->tail->next = p; 404 | tmp->tail = p; 405 | } 406 | return; 407 | } 408 | if (sz < 4 + m->sz) { 409 | new_package(U, tmp); 410 | } 411 | uint8_t * buf = tmp->buf+tmp->sz; 412 | int len = fill_header(buf, m->sz + TYPE_NORMAL, m->id); 413 | tmp->sz += len + m->sz; 414 | buf += len; 415 | memcpy(buf, m->buffer, m->sz); 416 | } 417 | 418 | static void 419 | request_missing(struct rudp *U, struct tmp_buffer *tmp) { 420 | int id = U->recv_id_min; 421 | struct message *m = U->recv_queue.head; 422 | while (m) { 423 | assert(m->id >= id); 424 | if (m->id > id) { 425 | int i; 426 | for (i=id;iid;i++) { 427 | pack_request(U, tmp, i, TYPE_REQUEST); 428 | } 429 | } 430 | id = m->id+1; 431 | m = m->next; 432 | } 433 | } 434 | 435 | static void 436 | reply_request(struct rudp *U, struct tmp_buffer *tmp) { 437 | int i; 438 | struct message *history = U->send_history.head; 439 | for (i=0;isend_again.n;i++) { 440 | int id = U->send_again.a[i]; 441 | if (id < U->recv_id_min) { 442 | // alreay recv, ignore 443 | continue; 444 | } 445 | for (;;) { 446 | if (history == NULL || id < history->id) { 447 | // expired 448 | pack_request(U, tmp, id, TYPE_MISSING); 449 | break; 450 | } else if (id == history->id) { 451 | pack_message(U, tmp, history); 452 | break; 453 | } 454 | history = history->next; 455 | } 456 | } 457 | 458 | U->send_again.n = 0; 459 | } 460 | 461 | static void 462 | send_message(struct rudp *U, struct tmp_buffer *tmp) { 463 | struct message *m = U->send_queue.head; 464 | while (m) { 465 | pack_message(U, tmp, m); 466 | m = m->next; 467 | } 468 | if (U->send_queue.head) { 469 | if (U->send_history.tail == NULL) { 470 | U->send_history = U->send_queue; 471 | } else { 472 | U->send_history.tail->next = U->send_queue.head; 473 | U->send_history.tail = U->send_queue.tail; 474 | } 475 | U->send_queue.head = NULL; 476 | U->send_queue.tail = NULL; 477 | } 478 | } 479 | 480 | 481 | /* 482 | 1. request missing ( lookup U->recv_queue ) 483 | 2. reply request ( U->send_again ) 484 | 3. send message ( U->send_queue ) 485 | 4. send heartbeat 486 | */ 487 | static struct rudp_package * 488 | gen_outpackage(struct rudp *U) { 489 | struct tmp_buffer tmp; 490 | tmp.sz = 0; 491 | tmp.head = NULL; 492 | tmp.tail = NULL; 493 | 494 | request_missing(U, &tmp); 495 | reply_request(U, &tmp); 496 | send_message(U, &tmp); 497 | 498 | // close tmp 499 | 500 | if (tmp.head == NULL) { 501 | if (tmp.sz == 0) { 502 | tmp.buf[0] = TYPE_IGNORE; 503 | tmp.sz = 1; 504 | } 505 | } 506 | new_package(U, &tmp); 507 | return tmp.head; 508 | } 509 | 510 | struct rudp_package * 511 | rudp_update(struct rudp *U, const void * buffer, int sz, int tick) { 512 | U->current_tick += tick; 513 | clear_outpackage(U); 514 | extract_package(U, buffer, sz); 515 | if (U->current_tick >= U->last_expired_tick + U->expired) { 516 | clear_send_expired(U, U->last_expired_tick); 517 | U->last_expired_tick = U->current_tick; 518 | } 519 | if (U->current_tick >= U->last_send_tick + U->send_delay) { 520 | U->send_package = gen_outpackage(U); 521 | U->last_send_tick = U->current_tick; 522 | return U->send_package; 523 | } else { 524 | return NULL; 525 | } 526 | } 527 | -------------------------------------------------------------------------------- /rudp.h: -------------------------------------------------------------------------------- 1 | #ifndef reliable_udp_h 2 | #define reliable_udp_h 3 | 4 | #define MAX_PACKAGE (0x7fff-4) 5 | 6 | struct rudp_package { 7 | struct rudp_package *next; 8 | char *buffer; 9 | int sz; 10 | }; 11 | 12 | struct rudp * rudp_new(int send_delay, int expired_time); 13 | void rudp_delete(struct rudp *); 14 | 15 | // return the size of new package, 0 where no new package 16 | // -1 corrupt connection 17 | int rudp_recv(struct rudp *U, char buffer[MAX_PACKAGE]); 18 | // send a new package out 19 | void rudp_send(struct rudp *U, const char *buffer, int sz); 20 | // should call every frame with the time tick, or a new package is coming. 21 | // return the package should be send out. 22 | struct rudp_package * rudp_update(struct rudp *U, const void * buffer, int sz, int tick); 23 | 24 | #endif 25 | --------------------------------------------------------------------------------