source: roaraudio/libroar/proto.c @ 4439:2a5894489fab

Last change on this file since 4439:2a5894489fab was 4439:2a5894489fab, checked in by phi, 13 years ago

don't assume NULL to be a false value

File size: 8.8 KB
Line 
1//proto.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2008-2010
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_errno = ROAR_ERROR_UNKNOWN;
68
69 ROAR_DBG("roar_send_message(*): try to send an request...");
70
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.
76
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    // ...
89    roar_errno = ROAR_ERROR_NOTSUP;
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 ) {
98     *(uint64_t*)(buf+8) = ROAR_HOST2NET16(mes->pos64);
99     bufptr = buf+16;
100     headerlen          += 4;
101    } else {
102     *(uint32_t*)(buf+8) = ROAR_HOST2NET16(mes->pos);
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:
109    roar_errno = ROAR_ERROR_NOTSUP;
110    return -1;
111 }
112
113 if ( roar_vio_write(vio, buf, headerlen) != headerlen ) {
114  roar_errno = ROAR_ERROR_PIPE;
115  return -1;
116 }
117
118 if ( mes->datalen != 0 ) {
119  if ( roar_vio_write(vio, data == NULL ? mes->data : data, mes->datalen) != mes->datalen ) {
120   roar_errno = ROAR_ERROR_PIPE;
121   return -1;
122  }
123 }
124
125 if ( crclen != 0 ) {
126  if ( roar_vio_write(vio, crc, crclen) != crclen ) {
127   roar_errno = ROAR_ERROR_PIPE;
128   return -1;
129  }
130 }
131
132 roar_errno = ROAR_ERROR_NONE;
133
134 ROAR_DBG("roar_send_message(*) = 0");
135 return 0;
136}
137
138int roar_recv_message (struct roar_connection * con, struct roar_message * mes, char ** data) {
139 struct roar_vio_calls * vio;
140
141 if ( (vio = roar_get_connection_vio2(con)) == NULL )
142  return -1;
143
144 return roar_vrecv_message(vio, mes, data);
145}
146
147int roar_vrecv_message(struct roar_vio_calls * vio, struct roar_message * mes, char ** data) {
148 // TODO: add CRC support.
149 char buf[_ROAR_MESS_BUF_LEN_MAX];
150// char crc[_ROAR_MESS_CRC_LEN_MAX];
151 size_t headerlen = 0;
152// size_t crclen    = 0;
153 size_t needlen;
154 char * bufptr;
155
156 roar_errno = ROAR_ERROR_UNKNOWN;
157
158 ROAR_DBG("roar_recv_message(*): try to get a response form the server...");
159
160 if ( mes == NULL )
161  return -1;
162
163 if ( data != NULL )
164  *data = NULL;
165
166 memset(mes, 0, sizeof(struct roar_message));
167
168 if ( roar_vio_read(vio, buf, _ROAR_MESS_BUF_LEN_V0) != _ROAR_MESS_BUF_LEN_V0 ) {
169  roar_errno = ROAR_ERROR_PROTO;
170  return -1;
171 }
172
173 ROAR_DBG("roar_recv_message(*): Got a header");
174
175 mes->version = buf[0];
176 headerlen    = _ROAR_MESS_BUF_LEN_V0;
177
178 switch (mes->version) {
179  case 0:
180    // we already have all data, so create the struct
181    mes->cmd     = (unsigned char)buf[1];
182    mes->stream  = ROAR_NET2HOST16(*(uint16_t*)(buf+2));
183    mes->pos     = ROAR_NET2HOST32(*(uint32_t*)(buf+4));
184    mes->datalen = ROAR_NET2HOST16(*(uint16_t*)(buf+8));
185   break;
186  case 2:
187    mes->cmd     = (unsigned char)buf[1];
188    mes->stream  = ROAR_NET2HOST16(*(uint16_t*)(buf+2));
189    mes->flags   = ROAR_NET2HOST32(*(uint32_t*)(buf+4));
190    if ( mes->flags & ROAR_MF_LSPOS ) {
191     headerlen = 20;
192    } else {
193     headerlen = 16;
194    }
195   break;
196  default:
197    roar_errno = ROAR_ERROR_PROTO;
198    return -1;
199   break;
200 }
201
202 // check specal case where headerlen < _ROAR_MESS_BUF_LEN_V0, this means that we need to put
203 // some data we read as header into the data part of the message.
204 if ( headerlen > _ROAR_MESS_BUF_LEN_V0 ) {
205  needlen = headerlen - _ROAR_MESS_BUF_LEN_V0;
206  if ( roar_vio_read(vio, buf+_ROAR_MESS_BUF_LEN_V0, needlen) != (ssize_t)needlen ) {
207   roar_errno = ROAR_ERROR_PROTO;
208   return -1;
209  }
210 }
211
212 switch (mes->version) {
213  case 2:
214    if ( mes->flags & ROAR_MF_LSPOS ) {
215     mes->pos64   = ROAR_NET2HOST32(*(uint64_t*)(buf+8));
216     bufptr       = buf+16;
217    } else {
218     mes->pos     = ROAR_NET2HOST32(*(uint32_t*)(buf+8));
219     bufptr       = buf+12;
220    }
221    mes->datalen = ROAR_NET2HOST16(*(uint16_t*)(bufptr+0));
222    mes->seq     = ROAR_NET2HOST16(*(uint16_t*)(bufptr+1));
223   break;
224 }
225
226 if ( (int16_t)mes->stream == -1 )
227  mes->stream = -1;
228
229 ROAR_DBG("roar_recv_message(*): command=%i(%s)", mes->cmd,
230           mes->cmd == ROAR_CMD_OK ? "OK" : (mes->cmd == ROAR_CMD_ERROR ? "ERROR" : "UNKNOWN"));
231
232// Below we only have data handling, handling of header is finished:
233
234 if ( mes->datalen == 0 ) {
235  ROAR_DBG("roar_recv_message(*): no data in this pkg");
236  ROAR_DBG("roar_recv_message(*) = 0");
237  roar_errno = ROAR_ERROR_NONE;
238  return 0;
239 }
240
241 if ( mes->datalen <= LIBROAR_BUFFER_MSGDATA ) {
242  if ( roar_vio_read(vio, mes->data, mes->datalen) == mes->datalen ) {
243   ROAR_DBG("roar_recv_message(*): Got data!");
244   ROAR_DBG("roar_recv_message(*) = 0");
245   roar_errno = ROAR_ERROR_NONE;
246   return 0;
247  }
248
249  roar_errno = ROAR_ERROR_PIPE;
250  return -1;
251 } else {
252  if ( data == NULL ) {
253   roar_errno = ROAR_ERROR_MSGSIZE;
254   return -1;
255  }
256
257  if ( (*data = malloc(mes->datalen)) == NULL ) {
258   roar_errno = ROAR_ERROR_NOMEM;
259   return -1;
260  }
261
262  if ( mes->datalen == 0 ) {
263   roar_errno = ROAR_ERROR_NONE;
264   return 0;
265  }
266
267  if ( roar_vio_read(vio, *data, mes->datalen) == mes->datalen ) {
268   ROAR_DBG("roar_recv_message(*): Got data!");
269   ROAR_DBG("roar_recv_message(*) = 0");
270   roar_errno = ROAR_ERROR_NONE;
271   return 0;
272  }
273
274  roar_errno = ROAR_ERROR_PIPE;
275  return -1;
276 }
277
278 // what happened here?
279 return -1;
280}
281
282int roar_req (struct roar_connection * con, struct roar_message * mes, char ** data) {
283 struct roar_vio_calls * vio;
284
285 if ( (vio = roar_get_connection_vio2(con)) == NULL )
286  return -1;
287
288 return roar_vreq(vio, mes, data);
289}
290
291int roar_vreq         (struct roar_vio_calls * vio, struct roar_message * mes, char ** data) {
292 if ( roar_vsend_message(vio, mes, data ? *data : NULL) != 0 )
293  return -1;
294
295 if ( data != NULL )
296  free(*data);
297
298 roar_vio_sync(vio); // we need to do this becasue of ssl/compressed links
299
300 return roar_vrecv_message(vio, mes, data);
301}
302
303//ll
Note: See TracBrowser for help on using the repository browser.