| @@ -78,6 +78,12 @@ · 77 unmodified lines |
| 78 | 78 | #define UDP_MAX_PKT_SIZE 65536 |
| 79 | 79 | #define UDP_HEADER_SIZE 8 |
| 80 | 80 | |
| 81 | +typedef struct UDPQueuedPacketHeader { |
| 82 | + int pkt_size; |
| 83 | + struct sockaddr_storage addr; |
| 84 | + socklen_t addr_len; |
| 85 | +} UDPQueuedPacketHeader; |
| 86 | + |
| 81 | 87 | typedef struct UDPContext { |
| 82 | 88 | const AVClass *class; |
| 83 | 89 | int udp_fd; |
| @@ -107,7 +113,7 @@ typedef struct UDPContext { · 23 unmodified lines |
| 107 | 113 | pthread_cond_t cond; |
| 108 | 114 | int thread_started; |
| 109 | 115 | #endif |
| 110 | | − uint8_t tmp[UDP_MAX_PKT_SIZE+4]; |
| 116 | + uint8_t tmp[UDP_MAX_PKT_SIZE + sizeof(UDPQueuedPacketHeader)]; |
| 111 | 117 | int remaining_in_dg; |
| 112 | 118 | char *localaddr; |
| 113 | 119 | int timeout; |
| @@ -115,6 +121,8 @@ typedef struct UDPContext { · 1 unmodified line |
| 115 | 121 | char *sources; |
| 116 | 122 | char *block; |
| 117 | 123 | IPSourceFilters filters; |
| 124 | + struct sockaddr_storage last_recv_addr; |
| 125 | + socklen_t last_recv_addr_len; |
| 118 | 126 | } UDPContext; |
| 119 | 127 | |
| 120 | 128 | #define OFFSET(x) offsetof(UDPContext, x) |
| @@ -467,6 +475,13 @@ int ff_udp_get_local_port(URLContext *h) · 346 unmodified lines |
| 467 | 475 | return s->local_port; |
| 468 | 476 | } |
| 469 | 477 | |
| 478 | +void ff_udp_get_last_recv_addr(URLContext *h, struct sockaddr_storage *addr, socklen_t *addr_len) |
| 479 | +{ |
| 480 | + UDPContext *s = h->priv_data; |
| 481 | + *addr = s->last_recv_addr; |
| 482 | + *addr_len = s->last_recv_addr_len; |
| 483 | +} |
| 484 | + |
| 470 | 485 | /** |
| 471 | 486 | * Return the udp file handle for select() usage to wait for several RTP |
| 472 | 487 | * streams at the same time. |
| @@ -495,30 +510,28 @@ static void *circular_buffer_task_rx( void *_URLContext) · 22 unmodified lines |
| 495 | 510 | goto end; |
| 496 | 511 | } |
| 497 | 512 | while(1) { |
| 498 | | − int len; |
| 499 | | − struct sockaddr_storage addr; |
| 500 | | − socklen_t addr_len = sizeof(addr); |
| 513 | + UDPQueuedPacketHeader pkt_header; |
| 501 | 514 | |
| 502 | 515 | pthread_mutex_unlock(&s->mutex); |
| 503 | 516 | /* Blocking operations are always cancellation points; |
| 504 | 517 | see "General Information" / "Thread Cancelation Overview" |
| 505 | 518 | in Single Unix. */ |
| 506 | 519 | pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old_cancelstate); |
| 507 | | − len = recvfrom(s->udp_fd, s->tmp+4, sizeof(s->tmp)-4, 0, (struct sockaddr *)&addr, &addr_len); |
| 520 | + pkt_header.pkt_size = recvfrom(s->udp_fd, s->tmp + sizeof(pkt_header), sizeof(s->tmp) - sizeof(pkt_header), 0, (struct sockaddr *)&pkt_header.addr, &pkt_header.addr_len); |
| 508 | 521 | pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_cancelstate); |
| 509 | 522 | pthread_mutex_lock(&s->mutex); |
| 510 | | − if (len < 0) { |
| 523 | + if (pkt_header.pkt_size < 0) { |
| 511 | 524 | if (ff_neterrno() != AVERROR(EAGAIN) && ff_neterrno() != AVERROR(EINTR)) { |
| 512 | 525 | s->circular_buffer_error = ff_neterrno(); |
| 513 | 526 | goto end; |
| 514 | 527 | } |
| 515 | 528 | continue; |
| 516 | 529 | } |
| 517 | | − if (ff_ip_check_source_lists(&addr, &s->filters)) |
| 530 | + if (ff_ip_check_source_lists(&pkt_header.addr, &s->filters)) |
| 518 | 531 | continue; |
| 519 | | − AV_WL32(s->tmp, len); |
| 532 | + memcpy(s->tmp, &pkt_header, sizeof(pkt_header)); |
| 520 | 533 | |
| 521 | | − if (av_fifo_can_write(s->fifo) < len + 4) { |
| 534 | + if (av_fifo_can_write(s->fifo) < pkt_header.pkt_size + sizeof(pkt_header)) { |
| 522 | 535 | /* No Space left */ |
| 523 | 536 | if (s->overrun_nonfatal) { |
| 524 | 537 | av_log(h, AV_LOG_WARNING, "Circular buffer overrun. " |
| @@ -532,7 +545,7 @@ static void *circular_buffer_task_rx( void *_URLContext) · 7 unmodified lines |
| 532 | 545 | goto end; |
| 533 | 546 | } |
| 534 | 547 | } |
| 535 | | − av_fifo_write(s->fifo, s->tmp, len + 4); |
| 548 | + av_fifo_write(s->fifo, s->tmp, pkt_header.pkt_size + sizeof(pkt_header)); |
| 536 | 549 | pthread_cond_signal(&s->cond); |
| 537 | 550 | } |
| 538 | 551 | |
| @@ -991,8 +1004,6 @@ static int udp_read(URLContext *h, uint8_t *buf, int size) · 452 unmodified lines |
| 991 | 1004 | { |
| 992 | 1005 | UDPContext *s = h->priv_data; |
| 993 | 1006 | int ret; |
| 994 | | − struct sockaddr_storage addr; |
| 995 | | − socklen_t addr_len = sizeof(addr); |
| 996 | 1007 | #if HAVE_PTHREAD_CANCEL |
| 997 | 1008 | int avail, nonblock = h->flags & AVIO_FLAG_NONBLOCK; |
| 998 | 1009 | |
| @@ -1001,17 +1012,21 @@ static int udp_read(URLContext *h, uint8_t *buf, int size) · 2 unmodified lines |
| 1001 | 1012 | do { |
| 1002 | 1013 | avail = av_fifo_can_read(s->fifo); |
| 1003 | 1014 | if (avail) { // >=size) { |
| 1004 | | − uint8_t tmp[4]; |
| 1015 | + UDPQueuedPacketHeader header; |
| 1016 | + |
| 1017 | + av_fifo_read(s->fifo, &header, sizeof(header)); |
| 1018 | + |
| 1019 | + s->last_recv_addr = header.addr; |
| 1020 | + s->last_recv_addr_len = header.addr_len; |
| 1005 | 1021 | |
| 1006 | | − av_fifo_read(s->fifo, tmp, 4); |
| 1007 | | − avail = AV_RL32(tmp); |
| 1022 | + avail = header.pkt_size; |
| 1008 | 1023 | if(avail > size){ |
| 1009 | 1024 | av_log(h, AV_LOG_WARNING, "Part of datagram lost due to insufficient buffer size\n"); |
| 1010 | 1025 | avail = size; |
| 1011 | 1026 | } |
| 1012 | 1027 | |
| 1013 | 1028 | av_fifo_read(s->fifo, buf, avail); |
| 1014 | | − av_fifo_drain2(s->fifo, AV_RL32(tmp) - avail); |
| 1029 | + av_fifo_drain2(s->fifo, header.pkt_size - avail); |
| 1015 | 1030 | pthread_mutex_unlock(&s->mutex); |
| 1016 | 1031 | return avail; |
| 1017 | 1032 | } else if(s->circular_buffer_error){ |
| @@ -1043,10 +1058,11 @@ static int udp_read(URLContext *h, uint8_t *buf, int size) · 25 unmodified lines |
| 1043 | 1058 | if (ret < 0) |
| 1044 | 1059 | return ret; |
| 1045 | 1060 | } |
| 1046 | | − ret = recvfrom(s->udp_fd, buf, size, 0, (struct sockaddr *)&addr, &addr_len); |
| 1061 | + s->last_recv_addr_len = sizeof(s->last_recv_addr); |
| 1062 | + ret = recvfrom(s->udp_fd, buf, size, 0, (struct sockaddr *)&s->last_recv_addr, &s->last_recv_addr_len); |
| 1047 | 1063 | if (ret < 0) |
| 1048 | 1064 | return ff_neterrno(); |
| 1049 | | − if (ff_ip_check_source_lists(&addr, &s->filters)) |
| 1065 | + if (ff_ip_check_source_lists(&s->last_recv_addr, &s->filters)) |
| 1050 | 1066 | return AVERROR(EINTR); |
| 1051 | 1067 | return ret; |
| 1052 | 1068 | } |