source: roaraudio/libroar/proto.c @ 5823:f9f70dbaa376

Last change on this file since 5823:f9f70dbaa376 was 5823:f9f70dbaa376, checked in by phi, 11 years ago

updated copyright

File size: 11.2 KB
Line 
1//proto.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2008-2013
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
38#define _ROAR_MESS_BUF_LEN_V0  (1 /* version */ + 1 /* cmd */ + 2 /* stream */ + 4 /* pos */ + 2 /* datalen */)
39#define _ROAR_MESS_BUF_LEN_V1  (1 /* version */ + 1 /* cmd */ + 2 /* stream */ + 4 /* pos */ + 2 /* datalen */ + \
40                                1 /* flags */)
41#define _ROAR_MESS_BUF_LEN_V2  (1 /* version */ + 1 /* cmd */ + 2 /* stream */ + 8 /* pos */ + 2 /* datalen */ + \
42                                4 /* flags */   + 2 /* seq */)
43#define _ROAR_MESS_BUF_LEN     _ROAR_MESS_BUF_LEN_V0
44#define _ROAR_MESS_BUF_LEN_MAX ROAR_MAX3(_ROAR_MESS_BUF_LEN_V0, _ROAR_MESS_BUF_LEN_V1, _ROAR_MESS_BUF_LEN_V2)
45
46#define _ROAR_MESS_CRC_LEN_V0  0 /* No CRC */
47#define _ROAR_MESS_CRC_LEN_V1  1
48#define _ROAR_MESS_CRC_LEN_V2  4
49#define _ROAR_MESS_CRC_LEN_MAX ROAR_MAX3(_ROAR_MESS_CRC_LEN_V0, _ROAR_MESS_CRC_LEN_V1, _ROAR_MESS_CRC_LEN_V2)
50
51int roar_send_message (struct roar_connection * con, struct roar_message * mes, char * data) {
52 struct roar_vio_calls * vio;
53
54 if ( (vio = roar_get_connection_vio2(con)) == NULL )
55  return -1;
56
57 return roar_vsend_message(vio, mes, data);
58}
59
60int roar_vsend_message(struct roar_vio_calls * vio, struct roar_message * mes, char *  data) {
61 char buf[_ROAR_MESS_BUF_LEN_MAX];
62 char crc[_ROAR_MESS_CRC_LEN_MAX];
63 size_t headerlen = 0;
64 size_t crclen    = 0;
65 char * bufptr;
66
67 roar_err_set(ROAR_ERROR_UNKNOWN);
68
69 ROAR_DBG("roar_send_message(*): try to send an request...");
70
71 headerlen = _ROAR_MESS_BUF_LEN;
72
73 buf[0] = mes->version; // first byte is always the version.
74
75 switch (mes->version) {
76  case 0:
77    buf[1]              = (unsigned char) mes->cmd;
78    *(uint16_t*)(buf+2) = ROAR_HOST2NET16(mes->stream);
79    *(uint32_t*)(buf+4) = ROAR_HOST2NET32(mes->pos);
80    *(uint16_t*)(buf+8) = ROAR_HOST2NET16(mes->datalen);
81    headerlen           = _ROAR_MESS_BUF_LEN_V0;
82   break;
83  case 1:
84    buf[1]              = (unsigned char) (mes->flags & 0xFF);
85    buf[2]              = (unsigned char)  mes->cmd;
86    // ...
87    roar_err_set(ROAR_ERROR_NSVERSION);
88    return -1;
89   break;
90  case 2:
91    headerlen           = 16;
92    buf[1]              = (unsigned char) mes->cmd;
93    *(uint16_t*)(buf+2) = ROAR_HOST2NET16(mes->stream);
94    *(uint32_t*)(buf+4) = ROAR_HOST2NET32(mes->flags);
95    if ( mes->flags & ROAR_MF_LSPOS ) {
96     *(uint64_t*)(buf+8) = ROAR_HOST2NET64(mes->pos64);
97     bufptr = buf+16;
98     headerlen          += 4;
99    } else {
100     *(uint32_t*)(buf+8) = ROAR_HOST2NET32(mes->pos);
101     bufptr = buf+12;
102    }
103    *(uint16_t*)(bufptr+0) = ROAR_HOST2NET16(mes->datalen);
104    *(uint16_t*)(bufptr+2) = ROAR_HOST2NET16(mes->seq);
105   break;
106  default:
107    roar_err_set(ROAR_ERROR_BADVERSION);
108    return -1;
109 }
110
111 if ( roar_vio_write(vio, buf, headerlen) != (ssize_t)headerlen ) {
112  return -1;
113 }
114
115 if ( mes->datalen != 0 ) {
116  if ( roar_vio_write(vio, data == NULL ? mes->data : data, mes->datalen) != (ssize_t)mes->datalen ) {
117   return -1;
118  }
119 }
120
121 if ( crclen != 0 ) {
122  if ( roar_vio_write(vio, crc, crclen) != (ssize_t)crclen ) {
123   return -1;
124  }
125 }
126
127 roar_err_clear();
128
129 ROAR_DBG("roar_send_message(*) = 0");
130 return 0;
131}
132
133int roar_recv_message (struct roar_connection * con, struct roar_message * mes, char ** data) {
134 return roar_recv_message2(con, mes, data, NULL);
135}
136int roar_recv_message2 (struct roar_connection * con, struct roar_message * mes, char ** data,
137                        struct roar_error_frame * errorframe) {
138 struct roar_vio_calls * vio;
139
140 if ( (vio = roar_get_connection_vio2(con)) == NULL )
141  return -1;
142
143 return roar_vrecv_message2(vio, mes, data, errorframe);
144}
145
146int roar_vrecv_message(struct roar_vio_calls * vio, struct roar_message * mes, char ** data) {
147 return roar_vrecv_message2(vio, mes, data, NULL);
148}
149
150static inline int _libroar_msgresyncer(struct roar_vio_calls  * vio, size_t len) {
151 char buffer[2*LIBROAR_BUFFER_MSGDATA]; // this is always called with len > LIBROAR_BUFFER_MSGDATA.
152 ssize_t ret;
153 size_t errorc = 0;
154
155 while (len && errorc < 4) {
156  ret = roar_vio_read(vio, buffer, len > sizeof(buffer) ? sizeof(buffer) : len);
157  if ( ret == (size_t)-1 ) {
158   errorc++;
159  } else {
160   errorc = 0;
161   len -= ret;
162  }
163 }
164
165 if ( len )
166  return -1; // last error is still set.
167 return 0;
168}
169
170int roar_vrecv_message2(struct roar_vio_calls  * vio, struct roar_message * mes, char ** data,
171                        struct roar_error_frame * errorframe) {
172 // TODO: add CRC support.
173 char buf[_ROAR_MESS_BUF_LEN_MAX];
174// char crc[_ROAR_MESS_CRC_LEN_MAX];
175 size_t headerlen = 0;
176// size_t crclen    = 0;
177 size_t needlen;
178 char * bufptr;
179
180 roar_err_set(ROAR_ERROR_UNKNOWN);
181
182 ROAR_DBG("roar_vrecv_message2(vio=%p, mes=%p, data=%p, errorframe=%p) = ?", vio, mes, data, errorframe);
183
184 ROAR_DBG("roar_vrecv_message2(*): try to get a response form the server...");
185
186 if ( vio == NULL || mes == NULL ) {
187  roar_err_set(ROAR_ERROR_FAULT);
188  return -1;
189 }
190
191 if ( data != NULL )
192  *data = NULL;
193
194 memset(mes, 0, sizeof(struct roar_message));
195
196 if ( roar_vio_read(vio, buf, _ROAR_MESS_BUF_LEN_V0) != _ROAR_MESS_BUF_LEN_V0 ) {
197  roar_err_set(ROAR_ERROR_PROTO);
198  return -1;
199 }
200
201 ROAR_DBG("roar_vrecv_message2(*): Got a header");
202
203 mes->version = buf[0];
204 headerlen    = _ROAR_MESS_BUF_LEN_V0;
205
206 switch (mes->version) {
207  case 0:
208    // we already have all data, so create the struct
209    mes->cmd     = (unsigned char)buf[1];
210    mes->stream  = ROAR_NET2HOST16(*(uint16_t*)(buf+2));
211    mes->pos     = ROAR_NET2HOST32(*(uint32_t*)(buf+4));
212    mes->pos64   = mes->pos;
213    mes->datalen = ROAR_NET2HOST16(*(uint16_t*)(buf+8));
214   break;
215  case 2:
216    mes->cmd     = (unsigned char)buf[1];
217    mes->stream  = ROAR_NET2HOST16(*(uint16_t*)(buf+2));
218    mes->flags   = ROAR_NET2HOST32(*(uint32_t*)(buf+4));
219    if ( mes->flags & ROAR_MF_LSPOS ) {
220     headerlen = 20;
221    } else {
222     headerlen = 16;
223    }
224   break;
225  default:
226    roar_err_set(ROAR_ERROR_NSVERSION);
227    return -1;
228   break;
229 }
230
231 // check special case where headerlen < _ROAR_MESS_BUF_LEN_V0, this means that we need to put
232 // some data we read as header into the data part of the message.
233 if ( headerlen > _ROAR_MESS_BUF_LEN_V0 ) {
234  needlen = headerlen - _ROAR_MESS_BUF_LEN_V0;
235  if ( roar_vio_read(vio, buf+_ROAR_MESS_BUF_LEN_V0, needlen) != (ssize_t)needlen ) {
236   roar_err_set(ROAR_ERROR_PROTO);
237   return -1;
238  }
239 }
240
241 switch (mes->version) {
242  case 2:
243    if ( mes->flags & ROAR_MF_LSPOS ) {
244     mes->pos64   = ROAR_NET2HOST32(*(uint64_t*)(buf+8));
245     mes->pos     = mes->pos64 & (uint64_t)0x0FFFFFFFFLLU;
246     bufptr       = buf+16;
247    } else {
248     mes->pos     = ROAR_NET2HOST32(*(uint32_t*)(buf+8));
249     mes->pos64   = mes->pos;
250     bufptr       = buf+12;
251    }
252    mes->datalen = ROAR_NET2HOST16(*(uint16_t*)(bufptr+0));
253    mes->seq     = ROAR_NET2HOST16(*(uint16_t*)(bufptr+2));
254   break;
255 }
256
257 if ( (int16_t)mes->stream == -1 )
258  mes->stream = -1;
259
260 ROAR_DBG("roar_vrecv_message2(*): command=%i(%s)", mes->cmd,
261           mes->cmd == ROAR_CMD_OK ? "OK" : (mes->cmd == ROAR_CMD_ERROR ? "ERROR" : "UNKNOWN"));
262
263// Below we only have data handling, handling of header is finished:
264
265 if ( mes->datalen == 0 ) {
266  ROAR_DBG("roar_vrecv_message2(*): no data in this pkg");
267  if ( mes->cmd == ROAR_CMD_ERROR && errorframe != NULL ) {
268   roar_err_init(errorframe);
269  }
270  roar_err_clear();
271  ROAR_DBG("roar_vrecv_message2(*) = 0");
272  return 0;
273 }
274
275 if ( mes->datalen <= LIBROAR_BUFFER_MSGDATA ) {
276  if ( roar_vio_read(vio, mes->data, mes->datalen) == (ssize_t)mes->datalen ) {
277   ROAR_DBG("roar_vrecv_message2(*): Got data!");
278   roar_err_clear();
279   if ( mes->cmd == ROAR_CMD_ERROR && errorframe != NULL ) {
280    if ( roar_err_parsemsg(mes, *data, errorframe) != 0 ) {
281     roar_err_init(errorframe);
282    }
283   }
284   ROAR_DBG("roar_vrecv_message2(*) = 0");
285   return 0;
286  }
287
288  return -1;
289 } else {
290  if ( data == NULL ) {
291   if ( _libroar_msgresyncer(vio, mes->datalen) == -1 ) {
292    roar_err_set(ROAR_ERROR_BADCKSUM);
293   } else {
294    roar_err_set(ROAR_ERROR_MSGSIZE);
295   }
296   return -1;
297  }
298
299  if ( (*data = roar_mm_malloc(mes->datalen)) == NULL ) {
300   if ( _libroar_msgresyncer(vio, mes->datalen) == -1 ) {
301    roar_err_set(ROAR_ERROR_BADCKSUM);
302   } else {
303    roar_err_set(ROAR_ERROR_NOMEM);
304   }
305   return -1;
306  }
307
308  if ( mes->datalen == 0 ) {
309   roar_err_clear();
310   if ( mes->cmd == ROAR_CMD_ERROR && errorframe != NULL ) {
311    roar_err_init(errorframe);
312   }
313   return 0;
314  }
315
316  if ( roar_vio_read(vio, *data, mes->datalen) == (ssize_t)mes->datalen ) {
317   ROAR_DBG("roar_vrecv_message2(*): Got data!");
318
319   roar_err_clear();
320   if ( mes->cmd == ROAR_CMD_ERROR && errorframe != NULL ) {
321    if ( roar_err_parsemsg(mes, *data, errorframe) != 0 ) {
322     roar_err_init(errorframe);
323    }
324   }
325   ROAR_DBG("roar_vrecv_message2(*) = 0");
326   return 0;
327  }
328
329  // error is still set (by roar_vio_read()).
330  return -1;
331 }
332
333 // what happened here?
334 return -1;
335}
336
337int roar_req (struct roar_connection * con, struct roar_message * mes, char ** data) {
338 return roar_req2(con, mes, data, NULL);
339}
340
341int roar_req2          (struct roar_connection * con, struct roar_message * mes, char ** data,
342                        struct roar_error_frame * errorframe) {
343 struct roar_vio_calls * vio;
344
345 if ( (vio = roar_get_connection_vio2(con)) == NULL )
346  return -1;
347
348 if ( mes->version == _ROAR_MESSAGE_VERSION )
349  mes->version = con->version;
350
351 if ( mes->version == 2 ) {
352  mes->seq = roar_message_genseq(con, -1);
353 }
354
355 return roar_vreq2(vio, mes, data, errorframe);
356}
357
358int roar_vreq         (struct roar_vio_calls * vio, struct roar_message * mes, char ** data) {
359 return roar_vreq2(vio, mes, data, NULL);
360}
361
362int roar_vreq2         (struct roar_vio_calls  * vio, struct roar_message * mes, char ** data,
363                        struct roar_error_frame * errorframe) {
364 if ( roar_vsend_message(vio, mes, data != NULL ? *data : NULL) != 0 )
365  return -1;
366
367 if ( data != NULL )
368  roar_mm_free(*data);
369
370 roar_vio_sync(vio); // we need to do this becasue of ssl/compressed links
371
372 return roar_vrecv_message2(vio, mes, data, errorframe);
373}
374
375//ll
Note: See TracBrowser for help on using the repository browser.