Remove unnecessary #includes
[profile/ivi/pulseaudio.git] / src / modules / rtp / sap.c
1 /***
2   This file is part of PulseAudio.
3
4   Copyright 2006 Lennart Poettering
5
6   PulseAudio is free software; you can redistribute it and/or modify
7   it under the terms of the GNU Lesser General Public License as published
8   by the Free Software Foundation; either version 2.1 of the License,
9   or (at your option) any later version.
10
11   PulseAudio is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with PulseAudio; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19   USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdlib.h>
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #include <errno.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <sys/ioctl.h>
34
35 #ifdef HAVE_SYS_FILIO_H
36 #include <sys/filio.h>
37 #endif
38
39 #ifdef HAVE_SYS_UIO_H
40 #include <sys/uio.h>
41 #endif
42
43 #include <pulse/xmalloc.h>
44
45 #include <pulsecore/core-error.h>
46 #include <pulsecore/core-util.h>
47 #include <pulsecore/log.h>
48 #include <pulsecore/macro.h>
49 #include <pulsecore/arpa-inet.h>
50
51 #include "sap.h"
52 #include "sdp.h"
53
54 #define MIME_TYPE "application/sdp"
55
56 pa_sap_context* pa_sap_context_init_send(pa_sap_context *c, int fd, char *sdp_data) {
57     pa_assert(c);
58     pa_assert(fd >= 0);
59     pa_assert(sdp_data);
60
61     c->fd = fd;
62     c->sdp_data = sdp_data;
63     c->msg_id_hash = (uint16_t) (rand()*rand());
64
65     return c;
66 }
67
68 void pa_sap_context_destroy(pa_sap_context *c) {
69     pa_assert(c);
70
71     pa_close(c->fd);
72     pa_xfree(c->sdp_data);
73 }
74
75 int pa_sap_send(pa_sap_context *c, pa_bool_t goodbye) {
76     uint32_t header;
77     struct sockaddr_storage sa_buf;
78     struct sockaddr *sa = (struct sockaddr*) &sa_buf;
79     socklen_t salen = sizeof(sa_buf);
80     struct iovec iov[4];
81     struct msghdr m;
82     ssize_t k;
83
84     if (getsockname(c->fd, sa, &salen) < 0) {
85         pa_log("getsockname() failed: %s\n", pa_cstrerror(errno));
86         return -1;
87     }
88
89 #ifdef HAVE_IPV6
90     pa_assert(sa->sa_family == AF_INET || sa->sa_family == AF_INET6);
91 #else
92     pa_assert(sa->sa_family == AF_INET);
93 #endif
94
95     header = htonl(((uint32_t) 1 << 29) |
96 #ifdef HAVE_IPV6
97                    (sa->sa_family == AF_INET6 ? (uint32_t) 1 << 28 : 0) |
98 #endif
99                    (goodbye ? (uint32_t) 1 << 26 : 0) |
100                    (c->msg_id_hash));
101
102     iov[0].iov_base = &header;
103     iov[0].iov_len = sizeof(header);
104
105     if (sa->sa_family == AF_INET) {
106         iov[1].iov_base = (void*) &((struct sockaddr_in*) sa)->sin_addr;
107         iov[1].iov_len = 4U;
108 #ifdef HAVE_IPV6
109     } else {
110         iov[1].iov_base = (void*) &((struct sockaddr_in6*) sa)->sin6_addr;
111         iov[1].iov_len = 16U;
112 #endif
113     }
114
115     iov[2].iov_base = (char*) MIME_TYPE;
116     iov[2].iov_len = sizeof(MIME_TYPE);
117
118     iov[3].iov_base = c->sdp_data;
119     iov[3].iov_len = strlen(c->sdp_data);
120
121     m.msg_name = NULL;
122     m.msg_namelen = 0;
123     m.msg_iov = iov;
124     m.msg_iovlen = 4;
125     m.msg_control = NULL;
126     m.msg_controllen = 0;
127     m.msg_flags = 0;
128
129     if ((k = sendmsg(c->fd, &m, MSG_DONTWAIT)) < 0)
130         pa_log_warn("sendmsg() failed: %s\n", pa_cstrerror(errno));
131
132     return (int) k;
133 }
134
135 pa_sap_context* pa_sap_context_init_recv(pa_sap_context *c, int fd) {
136     pa_assert(c);
137     pa_assert(fd >= 0);
138
139     c->fd = fd;
140     c->sdp_data = NULL;
141     return c;
142 }
143
144 int pa_sap_recv(pa_sap_context *c, pa_bool_t *goodbye) {
145     struct msghdr m;
146     struct iovec iov;
147     int size;
148     char *buf = NULL, *e;
149     uint32_t header;
150     unsigned six, ac, k;
151     ssize_t r;
152
153     pa_assert(c);
154     pa_assert(goodbye);
155
156     if (ioctl(c->fd, FIONREAD, &size) < 0) {
157         pa_log_warn("FIONREAD failed: %s", pa_cstrerror(errno));
158         goto fail;
159     }
160
161     buf = pa_xnew(char, (unsigned) size+1);
162     buf[size] = 0;
163
164     iov.iov_base = buf;
165     iov.iov_len = (size_t) size;
166
167     m.msg_name = NULL;
168     m.msg_namelen = 0;
169     m.msg_iov = &iov;
170     m.msg_iovlen = 1;
171     m.msg_control = NULL;
172     m.msg_controllen = 0;
173     m.msg_flags = 0;
174
175     if ((r = recvmsg(c->fd, &m, 0)) != size) {
176         pa_log_warn("recvmsg() failed: %s", r < 0 ? pa_cstrerror(errno) : "size mismatch");
177         goto fail;
178     }
179
180     if (size < 4) {
181         pa_log_warn("SAP packet too short.");
182         goto fail;
183     }
184
185     memcpy(&header, buf, sizeof(uint32_t));
186     header = ntohl(header);
187
188     if (header >> 29 != 1) {
189         pa_log_warn("Unsupported SAP version.");
190         goto fail;
191     }
192
193     if ((header >> 25) & 1) {
194         pa_log_warn("Encrypted SAP not supported.");
195         goto fail;
196     }
197
198     if ((header >> 24) & 1) {
199         pa_log_warn("Compressed SAP not supported.");
200         goto fail;
201     }
202
203     six = (header >> 28) & 1U;
204     ac = (header >> 16) & 0xFFU;
205
206     k = 4 + (six ? 16U : 4U) + ac*4U;
207     if ((unsigned) size < k) {
208         pa_log_warn("SAP packet too short (AD).");
209         goto fail;
210     }
211
212     e = buf + k;
213     size -= (int) k;
214
215     if ((unsigned) size >= sizeof(MIME_TYPE) && !strcmp(e, MIME_TYPE)) {
216         e += sizeof(MIME_TYPE);
217         size -= (int) sizeof(MIME_TYPE);
218     } else if ((unsigned) size < sizeof(PA_SDP_HEADER)-1 || strncmp(e, PA_SDP_HEADER, sizeof(PA_SDP_HEADER)-1)) {
219         pa_log_warn("Invalid SDP header.");
220         goto fail;
221     }
222
223     if (c->sdp_data)
224         pa_xfree(c->sdp_data);
225
226     c->sdp_data = pa_xstrndup(e, (unsigned) size);
227     pa_xfree(buf);
228
229     *goodbye = !!((header >> 26) & 1);
230
231     return 0;
232
233 fail:
234     pa_xfree(buf);
235
236     return -1;
237 }