source: roaraudio/libroar/caps.c @ 6029:c25f9d9f78a6

Last change on this file since 6029:c25f9d9f78a6 was 6029:c25f9d9f78a6, checked in by phi, 10 years ago

some smaller improvements in error handling

File size: 7.1 KB
Line 
1//caps.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010-2014
5 *
6 *  This file is part of libroar a part of RoarAudio,
7 *  a cross-platform sound system for both, home and professional use.
8 *  See README for details.
9 *
10 *  This file is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 3
12 *  as published by the Free Software Foundation.
13 *
14 *  libroar is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this software; see the file COPYING.  If not, write to
21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
23 *
24 *  NOTE for everyone want's to change something and send patches:
25 *  read README and HACKING! There a addition information on
26 *  the license of this document you need to read before you send
27 *  any patches.
28 *
29 *  NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc
30 *  or libpulse*:
31 *  The libs libroaresd, libroararts and libroarpulse link this lib
32 *  and are therefore GPL. Because of this it may be illigal to use
33 *  them with any software that uses libesd, libartsc or libpulse*.
34 */
35
36#include "libroar.h"
37
38const struct roar_stds * libroar_libstds(void) {
39 static const uint32_t std[] = {
40  ROAR_STD_MAKE(ROAR_STDV_ROARAUDIO, 0, 0)  // ra-msg-v0
41 };
42 static const struct roar_stds stds = {.stds_len = sizeof(std)/sizeof(*std), .stds = (uint32_t*)std};
43 return &stds;
44}
45
46int roar_caps_to_msg(struct roar_message * mes,  struct roar_caps    * caps, void ** data) {
47 char * datap;
48 size_t needlen = 4;
49
50 if ( mes == NULL || caps == NULL ) {
51  roar_err_set(ROAR_ERROR_FAULT);
52  return -1;
53 }
54
55 needlen += caps->len;
56
57 if ( needlen > sizeof(mes->data) ) {
58  if ( data == NULL ) {
59   roar_err_set(ROAR_ERROR_FAULT);
60   return -1;
61  }
62
63  if ( (*data = roar_mm_malloc(needlen)) == NULL )
64   return -1;
65
66  datap = *data;
67 } else {
68  datap = mes->data;
69 }
70
71 datap[0] = caps->version;
72 datap[1] = caps->type;
73 datap[2] = (caps->flags & 0xFF00) >> 8;
74 datap[3] = caps->flags & 0xFF;
75
76 if ( caps->len != 0 ) {
77  memcpy(&(datap[4]), caps->data, caps->len);
78 }
79
80 mes->datalen = needlen;
81
82 return 0;
83}
84
85int roar_caps_from_msg(struct roar_caps  * caps, struct roar_message * mes,  void  * data) {
86 char * datap;
87
88 if ( mes == NULL || caps == NULL ) {
89  roar_err_set(ROAR_ERROR_FAULT);
90  return -1;
91 }
92
93 if ( data != NULL ) {
94  datap = data;
95 } else {
96  datap = mes->data;
97 }
98
99 // versin check.
100 if ( datap[0] != 0 ) {
101  roar_err_set(ROAR_ERROR_NSVERSION);
102  return -1;
103 }
104
105 if ( mes->datalen < 4 ) {
106  roar_err_set(ROAR_ERROR_PROTO);
107  return -1;
108 }
109
110 memset(caps, 0, sizeof(struct roar_caps));
111
112 caps->version = datap[0];
113 caps->type    = datap[1];
114 caps->flags   = (datap[2] << 8) | datap[3];
115
116 if ( mes->datalen == 4 ) {
117  caps->data    = NULL;
118  caps->len     = 0;
119 } else {
120  caps->data    = &(datap[4]);
121  caps->len     = mes->datalen - 4;
122 }
123
124 return 0;
125}
126
127int roar_caps_stds(struct roar_connection * con, struct roar_stds ** out, struct roar_stds * in, int flags) {
128 struct roar_message mes;
129 struct roar_caps caps;
130 void * data = NULL;
131 char * data_char;
132 size_t i;
133
134 ROAR_DBG("roar_caps_stds(con=%p, out=%p, in=%p, flags=0x%.4x) = ?", con, out, in, flags);
135
136 if ( flags == -1 )
137  flags = 0;
138
139 if ( con == NULL ) {
140  roar_err_set(ROAR_ERROR_FAULT);
141  return -1;
142 }
143
144 if ( out != NULL )
145  flags |= ROAR_CF_REQUEST;
146
147 if ( (flags & ROAR_CF_REQUEST) && out == NULL ) {
148  roar_err_set(ROAR_ERROR_FAULT);
149  return -1;
150 }
151
152 if ( in != NULL )
153  if ( in->stds_len == 0 )
154   in = NULL;
155
156 memset(&caps, 0, sizeof(caps));
157
158 caps.version = 0;
159 caps.type    = ROAR_CT_STANDARDS;
160 caps.flags   = flags;
161
162 memset(&mes, 0, sizeof(mes));
163
164 if ( in != NULL ) {
165  // we use a hack here to avoid double alloc:
166  // first pass the data in native byte order.
167  // after we got a buffer swap in-buffer.
168  caps.data = in->stds;
169  caps.len  = in->stds_len * 4;
170 }
171
172 if ( roar_caps_to_msg(&mes, &caps, &data) == -1 )
173  return -1;
174
175 if ( in != NULL ) {
176  if ( data == NULL ) {
177   for (i = 0; i < in->stds_len; i++) {
178    ((uint32_t*)mes.data)[i] = ROAR_HOST2NET32(((uint32_t*)mes.data)[i]);
179   }
180  } else {
181   for (i = 0; i < in->stds_len; i++) {
182    ((uint32_t*)data)[i] = ROAR_HOST2NET32(((uint32_t*)data)[i]);
183   }
184  }
185 }
186
187 mes.cmd = ROAR_CMD_CAPS;
188
189 data_char = data;
190 if ( roar_req(con, &mes, &data_char) == -1 )
191  return -1;
192 data = data_char;
193
194 if ( mes.cmd != ROAR_CMD_OK ) {
195  if ( data != NULL )
196   roar_mm_free_noerror(data);
197  return -1;
198 }
199
200 if ( roar_caps_from_msg(&caps, &mes, data) == -1 ) {
201  if ( data != NULL )
202   roar_mm_free_noerror(data);
203  return -1;
204 }
205
206 // check if response matches the request:
207 if ( caps.version != 0 || caps.type != ROAR_CT_STANDARDS || (caps.len & 0x3) != 0 ) {
208  if ( data != NULL )
209   roar_mm_free(data);
210  roar_err_set(ROAR_ERROR_PROTO);
211  return -1;
212 }
213
214 if ( out != NULL ) {
215  *out = roar_stds_new(caps.len/4);
216  if ( *out == NULL ) {
217   if ( data != NULL )
218    roar_mm_free_noerror(data);
219   return -1;
220  }
221
222  ROAR_DBG("roar_caps_stds(con=%p, out=%p, in=%p, flags=0x%.4x): (*out)->stds_len=%llu", con, out, in, flags, (long long unsigned int)(*out)->stds_len);
223
224  for (i = 0; i < (*out)->stds_len; i++) {
225   (*out)->stds[i] = ROAR_NET2HOST32(((uint32_t*)caps.data)[i]);
226   ROAR_DBG("roar_caps_stds(con=%p, out=%p, in=%p, flags=0x%.4x): (*out)->stds[%llu] = 0x%.8x", con, out, in, flags, (long long unsigned int)i, (*out)->stds[i]);
227  }
228 }
229
230 if ( data != NULL )
231  roar_mm_free(data);
232
233 return 0;
234}
235
236struct roar_stds * roar_stds_new(size_t len) {
237 struct roar_stds * ret;
238
239 if ( len == 0 ) {
240  roar_err_set(ROAR_ERROR_INVAL);
241  return NULL;
242 }
243
244 ret = roar_mm_malloc(sizeof(struct roar_stds));
245
246 if ( ret == NULL )
247  return NULL;
248
249 memset(ret, 0, sizeof(struct roar_stds));
250
251 ret->stds_len = len;
252 ret->stds     = roar_mm_malloc(len*sizeof(uint32_t));
253
254 if ( ret->stds == NULL ) {
255  roar_mm_free_noerror(ret);
256  return NULL;
257 }
258
259 memset(ret->stds, 0, len*sizeof(uint32_t));
260
261 return ret;
262}
263
264int roar_stds_free(struct roar_stds * stds) {
265 if ( stds == NULL ) {
266  roar_err_set(ROAR_ERROR_FAULT);
267  return -1;
268 }
269
270 if ( stds->stds != NULL )
271  roar_mm_free(stds->stds);
272
273 roar_mm_free(stds);
274
275 return 0;
276}
277
278
279static struct {
280 const int    vendor;
281 const char * name;
282} _libroar_std_vendors[] = {
283 {ROAR_STDV_ROARAUDIO, "RoarAudio"},
284 {ROAR_STDV_PROTO,     "Protocols"},
285 {ROAR_STDV_RFC,       "RFC"},
286 {-1, NULL}
287};
288
289int roar_stds_str2vendor(const char * vendor) {
290 int i;
291
292 if ( vendor == NULL ) {
293  roar_err_set(ROAR_ERROR_FAULT);
294  return -1;
295 }
296
297 for (i = 0; _libroar_std_vendors[i].name != NULL; i++)
298  if ( !strcasecmp(_libroar_std_vendors[i].name, vendor) )
299   return _libroar_std_vendors[i].vendor;
300
301 roar_err_set(ROAR_ERROR_NOENT);
302 return -1;
303}
304
305const char * roar_stds_vendor2str(const int vendor) {
306 int i;
307
308 for (i = 0; _libroar_std_vendors[i].name != NULL; i++)
309  if ( _libroar_std_vendors[i].vendor == vendor )
310   return _libroar_std_vendors[i].name;
311
312 roar_err_set(ROAR_ERROR_NOENT);
313 return NULL;
314}
315
316
317//ll
Note: See TracBrowser for help on using the repository browser.