source: roaraudio/libroar/proto.c @ 5463:f11febcac1de

Last change on this file since 5463:f11febcac1de was 5463:f11febcac1de, checked in by phi, 12 years ago

corrected handling of pos in v2 messages

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