added rtp port range support
[libav.git] / libav / udp.c
CommitLineData
de6d9b64
FB
1/*
2 * UDP prototype streaming system
19720f15 3 * Copyright (c) 2000 Fabrice Bellard.
de6d9b64 4 *
19720f15
FB
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
de6d9b64 9 *
19720f15 10 * This library is distributed in the hope that it will be useful,
de6d9b64 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19720f15
FB
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
de6d9b64 14 *
19720f15
FB
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
de6d9b64 18 */
8be1c656 19#include "avformat.h"
de6d9b64 20#include <unistd.h>
de6d9b64
FB
21#include <sys/types.h>
22#include <sys/socket.h>
23#include <netinet/in.h>
24#include <arpa/inet.h>
25#include <netdb.h>
26
de6d9b64
FB
27typedef struct {
28 int udp_socket;
29 int max_payload_size; /* in bytes */
30} UDPContext;
31
32#define UDP_TX_BUF_SIZE 32768
33
34/* put it in UDP context */
35static struct sockaddr_in dest_addr;
36
37/* return non zero if error */
38static int udp_open(URLContext *h, const char *uri, int flags)
39{
40 int local_port = 0;
41 struct sockaddr_in my_addr;
42 const char *p, *q;
43 char hostname[1024];
44 int port, udp_socket, tmp;
45 struct hostent *hp;
46 UDPContext *s;
47
48 h->is_streamed = 1;
49
50 if (!(flags & URL_WRONLY))
51 return -EIO;
52
53 /* fill the dest addr */
54 p = uri;
55 if (!strstart(p, "udp:", &p))
56 return -1;
57 q = strchr(p, ':');
58 if (!q)
59 return -1;
60 memcpy(hostname, p, q - p);
61 hostname[q - p] = '\0';
62 port = strtol(q+1, NULL, 10);
63 if (port <= 0)
64 return -1;
65
66 dest_addr.sin_family = AF_INET;
67 dest_addr.sin_port = htons(port);
68 if ((inet_aton(hostname, &dest_addr.sin_addr)) == 0) {
69 hp = gethostbyname(hostname);
70 if (!hp)
71 return -1;
72 memcpy ((char *) &dest_addr.sin_addr, hp->h_addr, hp->h_length);
73 }
74
75 udp_socket = socket(PF_INET, SOCK_DGRAM, 0);
76 if (udp_socket < 0)
77 return -1;
78
79 my_addr.sin_family = AF_INET;
80 my_addr.sin_port = htons(local_port);
81 my_addr.sin_addr.s_addr = htonl (INADDR_ANY);
82
83 /* the bind is needed to give a port to the socket now */
84 if (bind(udp_socket,(struct sockaddr *)&my_addr, sizeof(my_addr)) < 0)
85 goto fail;
86
87 /* limit the tx buf size to limit latency */
88
89 tmp = UDP_TX_BUF_SIZE;
90 if (setsockopt(udp_socket, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(tmp)) < 0) {
91 perror("setsockopt sndbuf");
92 goto fail;
93 }
94
1ea4f593 95 s = av_malloc(sizeof(UDPContext));
de6d9b64
FB
96 if (!s)
97 return -ENOMEM;
98 h->priv_data = s;
99 s->udp_socket = udp_socket;
100 h->packet_size = 1500;
101 return 0;
102 fail:
103 return -EIO;
104}
105
106int udp_close(URLContext *h)
107{
108 UDPContext *s = h->priv_data;
109 close(s->udp_socket);
110 return 0;
111}
112
113int udp_write(URLContext *h, UINT8 *buf, int size)
114{
115 UDPContext *s = h->priv_data;
116 int ret, len, size1;
117
118 /* primitive way to avoid big packets */
119 size1 = size;
120 while (size > 0) {
121 len = size;
122 if (len > h->packet_size)
123 len = h->packet_size;
124
125 ret = sendto (s->udp_socket, buf, len, 0,
126 (struct sockaddr *) &dest_addr,
127 sizeof (dest_addr));
128 if (ret < 0)
129 perror("sendto");
130 buf += len;
131 size -= len;
132 }
133 return size1 - size;
134}
135
136URLProtocol udp_protocol = {
137 "udp",
138 udp_open,
139 NULL, /* read */
140 udp_write,
141 NULL, /* seek */
142 udp_close,
143};