File: stream_rtp.c

package info (click to toggle)
getstream 20070419-1
  • links: PTS
  • area: main
  • in suites: lenny
  • size: 308 kB
  • ctags: 658
  • sloc: ansic: 4,137; makefile: 58
file content (293 lines) | stat: -rw-r--r-- 7,052 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <time.h>

#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#include "stream.h"


#if 0


static inline void sout_send_tsp_rtp(struct stream_s *s, uint8_t *tsp) {
}

static void sout_sock_read(int fd, short event, void *arg) {
	struct stream_s		*s=arg;
	ssize_t			size;
	struct sockaddr_in	sin;
	socklen_t		sinlen=sizeof(struct sockaddr_in);

	size=recvfrom(fd, s->ctlbuf, MAX_CTL_MSG_SIZE,
			0, (struct sockaddr *) &sin, &sinlen);

	sout_parse_rtcp(s, s->ctlbuf, size, &sin);
}

static int sout_init_socket(struct stream_s *s) {
	struct sockaddr_in	sin;

	memset(&sin, 0, sizeof(struct sockaddr_in));

	s->sockfd=socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);

	sin.sin_port=htons(s->port);
	sin.sin_family=AF_INET;
	sin.sin_addr.s_addr=s->groupinaddr.s_addr;

	if (s->dist == STREAM_DIST_LISTEN) {

		/* Open control aka RTCP socket. I reverse engineered
		 * that this is group socket + 1 */

		s->ctlfd=socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
		sin.sin_port=htons(s->port+1);
		bind(s->ctlfd, (struct sockaddr *) &sin,
				sizeof(struct sockaddr_in));

		/* Add callback for packet receiption on control socket e.g. RTCP */
		event_set(&s->ctlevent, s->ctlfd, EV_READ|EV_PERSIST,
				sout_sock_read, s);
		event_add(&s->ctlevent, NULL);
	} else {
		/* MCAST - Set destination */
		connect(s->sockfd, (struct sockaddr *) &sin, sizeof(struct sockaddr_in));

		if (s->dist == STREAM_DIST_MCAST) {

			/*
			 * Set socket TTL - Be warned - I DoSed a Cisco 5500 RSM by sending
			 * a 60MBit/s stream in 14 Groups all with TTL of 1 and the switch
			 * went to lala land. It seems dropping MCAST traffic is very expensive
			 * in IOS 12.1 land and its even dropped in Layer 3 instead of Layer 2 although
			 * nobody expects ICMP "TTL expired" for MCAST traffic
			 *
			 */

			setsockopt(s->sockfd, IPPROTO_IP, IP_MULTICAST_TTL,
						&s->ttl, sizeof(s->ttl));
		}
	}

	return 1;
}

#endif

int stream_rtp_new_receiver(struct stream_s *s,
		char *addr, int port, uint32_t ssrc) {
	struct rtp_receiver_s	*r;

	r=calloc(1, sizeof(struct rtp_receiver_s));

	/* Copy address and port */
	r->addr=strdup(addr);
	r->port=port;
	r->ssrc=ssrc;
	r->lastrr=time(NULL);

	/* Create sockaddr_in struct for later sendmsg */
	r->sin.sin_family=AF_INET;
	inet_aton(r->addr, &r->sin.sin_addr);
	r->sin.sin_port=htons(r->port);

	r->sinlen=sizeof(struct sockaddr_in);

	/* Prepend receiver to receiver list */
	r->next=s->rtpreceiver;
	s->rtpreceiver=r;

	/* We want to receive packets */
	s->receiver++;

	return 0;
}


static struct rtp_receiver_s *stream_rtp_find_rtpr(struct stream_s *s, uint32_t ssrc) {
	struct rtp_receiver_s	*r;

	for(r=s->rtpreceiver;r;r=r->next)
		if (r->ssrc == ssrc)
			return r;

	return NULL;
}

static void stream_rtp_free_rtpr(struct stream_s *s, uint32_t ssrc) {
	struct rtp_receiver_s	*r, *lr;

	for(r=s->rtpreceiver,lr=NULL;r;r=r->next) {
		if (r->ssrc == ssrc) {
			if (lr)
				lr->next=r->next;
			free(r);
			return;
		}

		lr=r;
	}
}

static void stream_rtp_parse_rtcp(struct stream_s *s, uint8_t *b,
			int len, struct sockaddr_in *sin) {
	struct rtp_receiver_s	*r;
	uint32_t		ssrc;

	logwrite(LOG_DEBUG, "streamrtp: got rtcp packet version %d\n", RTCP_VERSION(b));

	/* Version 2 ? */
	if (RTCP_VERSION(b) != 2)
		return;

	/* Get SSRC from RTCP packet */
	ssrc=b[3]<<24 | b[4]<<16 | b[5]<<8 | b[6];

	switch(RTCP_PT(b)) {
		case(RTP_PT_RR):
			logwrite(LOG_DEBUG, "streamrtp: Got Receiver Report size %d from %s ssrc %08x\n",
						len, inet_ntoa(sin->sin_addr), ssrc);

			r=stream_rtp_find_rtpr(s, ssrc);

			if (!r) {
				logwrite(LOG_INFO, "streamrtp: Createing new RTP Receiver %08x\n", ssrc);

				stream_rtp_new_receiver(s,
					inet_ntoa(sin->sin_addr),
					ntohs(sin->sin_port)-1,
					ssrc);
			} else {
				/* Store last RR timestamp */
				r->lastrr=time(NULL);
			}
			break;

		case(RTP_PT_BYE):
			logwrite(LOG_INFO, "streamrtp: Got Bye size %d from %s ssrc %08x\n",
				len, inet_ntoa(sin->sin_addr), ssrc);

			/* Find receiver struct */
			stream_rtp_free_rtpr(s, ssrc);
			break;
	}
}

static void stream_rtp_read_rtcp(int fd, short event, void *arg) {
	struct stream_s		*s=arg;
	ssize_t			size;
	struct sockaddr_in	sin;
	socklen_t		sinlen=sizeof(struct sockaddr_in);

	size=recvfrom(fd, s->rtcpbuffer, RTCP_BUFFER_SIZE,
			0, (struct sockaddr *) &sin, &sinlen);

	logwrite(LOG_DEBUG, "streamrtp: got packet size %d\n", size);

	stream_rtp_parse_rtcp(s, s->rtcpbuffer, size, &sin);
}


static void stream_init_rtp_rtcp(struct stream_s *s) {
	struct sockaddr_in	sin;

	/* Allocate the RTCP incoming packet buffer */
	s->rtcpbuffer=malloc(RTCP_BUFFER_SIZE);

	memset(&sin, 0, sizeof(struct sockaddr_in));
	sin.sin_family=AF_INET;
	sin.sin_addr.s_addr=INADDR_ANY;
	sin.sin_port=htons(s->rtcpport);

	/* Create a socket and bind */
	s->rtcpfd=socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
	bind(s->rtcpfd, (struct sockaddr *) &sin, sizeof(struct sockaddr_in));

	/* Install rtcp callback */
	event_set(&s->rtcpevent, s->rtcpfd,
			EV_READ|EV_PERSIST, stream_rtp_read_rtcp, s);
	event_add(&s->rtcpevent, NULL);
}

int stream_init_rtp(struct stream_s *s) {
	struct sockaddr_in	lsin;

	memset(&lsin, 0, sizeof(struct sockaddr_in));

	s->sockfd=socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);

	lsin.sin_family=AF_INET;
	lsin.sin_addr.s_addr=INADDR_ANY;

	if (s->type == STYPE_RTP)
		lsin.sin_port=htons(0);
	else
		lsin.sin_port=htons(s->rtpport);

	bind(s->sockfd, (struct sockaddr *) &lsin, sizeof(struct sockaddr_in));

	/* Do you have a better idea ? */
	s->rtpssrc=(uint32_t) random();
	s->buffer=malloc(RTP_MAX_PAYLOAD+RTP_HEADROOM);

	switch(s->type) {
		case(STYPE_RTP):
			stream_rtp_new_receiver(s,
				s->remoteaddr, s->remoteport, 0);
			break;
		case(STYPE_RTCP):
			stream_init_rtp_rtcp(s);
			break;
	}

	return 0;
}

void stream_send_rtp(struct stream_s *s, uint8_t *tsp) {

	/* Copy TS packet to packet buffer */
	memcpy(&s->buffer[s->buffervalid], tsp, TS_PACKET_SIZE);
	s->buffervalid+=TS_PACKET_SIZE;

	/* check whether another packet would fit ? */
	if (s->buffervalid + TS_PACKET_SIZE > RTP_MAX_PAYLOAD) {
		struct rtp_receiver_s	*r;
		struct timeval		tv;
		long			msec;
		uint8_t			*b=s->buffer;

		gettimeofday(&tv, (struct timezone *) NULL);
		msec=(tv.tv_sec%1000000)*1000 + tv.tv_usec/1000;

		b[RTP_VERSION_OFF]	= 0x80;
		b[RTP_PT_OFF]		= RTP_PT_MP2T;	/* RFC 2250 */

		b[RTP_SEQ_OFF]		= s->rtpseq >> 8 & 0xff;
		b[RTP_SEQ_OFF+1]	= s->rtpseq & 0xff;

		b[RTP_TSTAMP_OFF]	= msec>>24 & 0xff;
		b[RTP_TSTAMP_OFF+1]	= msec>>16 & 0xff;
		b[RTP_TSTAMP_OFF+2]	= msec>>8 & 0xff;
		b[RTP_TSTAMP_OFF+3]	= msec & 0xff;

		b[RTP_SSRC_OFF]		= s->rtpssrc>>24 & 0xff;
		b[RTP_SSRC_OFF+1]	= s->rtpssrc>>16 & 0xff;
		b[RTP_SSRC_OFF+2]	= s->rtpssrc>>8 & 0xff;
		b[RTP_SSRC_OFF+3]	= s->rtpssrc & 0xff;

		for(r=s->rtpreceiver;r;r=r->next) {
			int	len;
			len=sendto(s->sockfd, s->buffer, s->buffervalid,
					MSG_DONTWAIT,
					(struct sockaddr *) &r->sin, r->sinlen);
		}

		s->buffervalid=RTP_HEADROOM;
		s->rtpseq++;
	}
}