More work towards 1.2.0
[umurmur.git] / src / messages.c
1 /* Copyright (C) 2009, Martin Johansson <martin@fatbob.nu>
2    Copyright (C) 2005-2009, Thorvald Natvig <thorvald@natvig.com>
3
4    All rights reserved.
5
6    Redistribution and use in source and binary forms, with or without
7    modification, are permitted provided that the following conditions
8    are met:
9
10    - Redistributions of source code must retain the above copyright notice,
11      this list of conditions and the following disclaimer.
12    - Redistributions in binary form must reproduce the above copyright notice,
13      this list of conditions and the following disclaimer in the documentation
14      and/or other materials provided with the distribution.
15    - Neither the name of the Developers nor the names of its contributors may
16      be used to endorse or promote products derived from this software without
17      specific prior written permission.
18
19    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22    A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
23    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <arpa/inet.h>
36
37 #include "messages.h"
38 #include "client.h"
39 #include "pds.h"
40 #include "log.h"
41
42
43 void dumpmsg(uint8_t *data, int size);
44
45 void Msg_addPreamble(uint8_t *buffer, uint16_t type, uint32_t len)
46 {
47         uint16_t *msgType = (uint16_t *) &buffer[0];
48         uint32_t *msgLen = (uint32_t *) &buffer[2];
49         
50         *msgType = htons(type);
51         *msgLen = htonl(len);
52 }
53
54 static void Msg_getPreamble(uint8_t *buffer, int *type, int *len)
55 {
56         uint16_t *msgType = (uint16_t *) &buffer[0];
57         uint32_t *msgLen = (uint32_t *) &buffer[2];
58         
59         *type = (int)ntohs(*msgType);
60         *len = (int)ntohl(*msgLen);
61 }
62
63 #define MAX_MSGSIZE (BUFSIZE - 6)
64 int Msg_messageToNetwork(message_t *msg, uint8_t *buffer)
65 {
66         int len;
67         uint8_t *bufptr = buffer + 6;
68                 
69         Log_debug("To net: msg type %d", msg->messageType);
70         switch (msg->messageType) {
71         case Version:
72                 len = mumble_proto__version__get_packed_size(msg->payload.version);
73                 if (len > MAX_MSGSIZE) {
74                         Log_warn("Too big tx message. Discarding");
75                         break;
76                 }
77                 Msg_addPreamble(buffer, msg->messageType, len);
78                 Log_debug("To net: Version->release: %s Version->os: %s",
79                                   msg->payload.version->release, msg->payload.version->os);
80                 mumble_proto__version__pack(msg->payload.version, bufptr);
81                 break;
82         case UDPTunnel:
83                 len = mumble_proto__udptunnel__get_packed_size(msg->payload.UDPTunnel);
84                 if (len > MAX_MSGSIZE) {
85                         Log_warn("Too big tx message. Discarding");
86                         break;
87                 }
88                 Msg_addPreamble(buffer, msg->messageType, len);
89                 mumble_proto__udptunnel__pack(msg->payload.UDPTunnel, bufptr);          
90                 break;
91         case Authenticate:
92                 len = mumble_proto__authenticate__get_packed_size(msg->payload.authenticate);
93                 if (len > MAX_MSGSIZE) {
94                         Log_warn("Too big tx message. Discarding");
95                         break;
96                         }
97                 Msg_addPreamble(buffer, msg->messageType, len);
98                 mumble_proto__authenticate__pack(msg->payload.authenticate, bufptr);
99                 break;
100         case Ping:
101                 len = mumble_proto__ping__get_packed_size(msg->payload.ping);
102                 if (len > MAX_MSGSIZE) {
103                         Log_warn("Too big tx message. Discarding");
104                         break;
105                         }
106                 Msg_addPreamble(buffer, msg->messageType, len);
107                 mumble_proto__ping__pack(msg->payload.ping, bufptr);
108                 break;
109         case Reject:
110                 len = mumble_proto__reject__get_packed_size(msg->payload.reject);
111                 if (len > MAX_MSGSIZE) {
112                         Log_warn("Too big tx message. Discarding");
113                         break;
114                         }
115                 Msg_addPreamble(buffer, msg->messageType, len);
116                 mumble_proto__reject__pack(msg->payload.reject, bufptr);
117                 break;
118         case ServerSync:
119                 len = mumble_proto__server_sync__get_packed_size(msg->payload.serverSync);
120                 if (len > MAX_MSGSIZE) {
121                         Log_warn("Too big tx message. Discarding");
122                         break;
123                         }
124                 Msg_addPreamble(buffer, msg->messageType, len);
125                 mumble_proto__server_sync__pack(msg->payload.serverSync, bufptr);
126                 break;
127         case TextMessage:
128                 len = mumble_proto__text_message__get_packed_size(msg->payload.textMessage);
129                 if (len > MAX_MSGSIZE) {
130                         Log_warn("Too big tx message. Discarding");
131                         break;
132                         }
133                 Msg_addPreamble(buffer, msg->messageType, len);
134                 mumble_proto__text_message__pack(msg->payload.textMessage, bufptr);
135                 break;
136         case PermissionDenied:
137                 len = mumble_proto__permission_denied__get_packed_size(msg->payload.permissionDenied);
138                 if (len > MAX_MSGSIZE) {
139                         Log_warn("Too big tx message. Discarding");
140                         break;
141                         }
142                 Msg_addPreamble(buffer, msg->messageType, len);
143                 mumble_proto__permission_denied__pack(msg->payload.permissionDenied, bufptr);
144                 break;
145         case CryptSetup:
146                 len = mumble_proto__crypt_setup__get_packed_size(msg->payload.cryptSetup);
147                 if (len > MAX_MSGSIZE) {
148                         Log_warn("Too big tx message. Discarding");
149                         break;
150                         }
151                 Msg_addPreamble(buffer, msg->messageType, len);
152                 mumble_proto__crypt_setup__pack(msg->payload.cryptSetup, bufptr);
153                 break;
154         case UserList:
155                 len = mumble_proto__user_list__get_packed_size(msg->payload.userList);
156                 if (len > MAX_MSGSIZE) {
157                         Log_warn("Too big tx message. Discarding");
158                         break;
159                         }
160                 Msg_addPreamble(buffer, msg->messageType, len);
161                 mumble_proto__user_list__pack(msg->payload.userList, bufptr);
162                 break;
163         case UserState:
164                 len = mumble_proto__user_state__get_packed_size(msg->payload.userState);
165                 if (len > MAX_MSGSIZE) {
166                         Log_warn("Too big tx message. Discarding");
167                         break;
168                         }
169                 Msg_addPreamble(buffer, msg->messageType, len);
170                 mumble_proto__user_state__pack(msg->payload.userState, bufptr);
171                 break;
172         case ChannelState:
173                 len = mumble_proto__channel_state__get_packed_size(msg->payload.channelState);
174                 if (len > MAX_MSGSIZE) {
175                         Log_warn("Too big tx message. Discarding");
176                         break;
177                         }
178                 Msg_addPreamble(buffer, msg->messageType, len);
179                 mumble_proto__channel_state__pack(msg->payload.channelState, bufptr);
180                 break;
181         case VoiceTarget:
182                 len = mumble_proto__voice_target__get_packed_size(msg->payload.voiceTarget);
183                 if (len > MAX_MSGSIZE) {
184                         Log_warn("Too big tx message. Discarding");
185                         break;
186                         }
187                 Msg_addPreamble(buffer, msg->messageType, len);
188                 mumble_proto__voice_target__pack(msg->payload.voiceTarget, bufptr);
189                 break;
190         case CodecVersion:
191                 len = mumble_proto__codec_version__get_packed_size(msg->payload.codecVersion);
192                 if (len > MAX_MSGSIZE) {
193                         Log_warn("Too big tx message. Discarding");
194                         break;
195                         }
196                 Msg_addPreamble(buffer, msg->messageType, len);
197                 mumble_proto__codec_version__pack(msg->payload.codecVersion, bufptr);
198                 break;
199
200         default:
201                 Log_warn("Unsupported message %d", msg->messageType);
202                 return 0;
203         }
204         return len + 6;
205 }
206
207 message_t *Msg_create(messageType_t messageType)
208 {
209         message_t *msg = malloc(sizeof(message_t));
210
211         if (msg == NULL)
212                 Log_fatal("Out of memory");
213         memset(msg, 0, sizeof(message_t));
214         msg->refcount = 1;
215         msg->messageType = messageType;
216         init_list_entry(&msg->node);
217         
218         switch (messageType) {
219         case Version:
220                 msg->payload.version = malloc(sizeof(MumbleProto__Version));
221                 mumble_proto__version__init(msg->payload.version);
222                 break;
223         case UDPTunnel:
224                 msg->payload.UDPTunnel = malloc(sizeof(MumbleProto__UDPTunnel));
225                 mumble_proto__udptunnel__init(msg->payload.UDPTunnel);
226                 break;
227         case Authenticate:
228                 msg->payload.authenticate = malloc(sizeof(MumbleProto__Authenticate));
229                 mumble_proto__authenticate__init(msg->payload.authenticate);
230                 break;
231         case Ping:
232                 msg->payload.ping = malloc(sizeof(MumbleProto__Ping));
233                 mumble_proto__ping__init(msg->payload.ping);
234                 break;
235         case Reject:
236                 msg->payload.reject = malloc(sizeof(MumbleProto__Reject));
237                 mumble_proto__reject__init(msg->payload.reject);
238                 break;
239         case ServerSync:
240                 msg->payload.serverSync = malloc(sizeof(MumbleProto__ServerSync));
241                 mumble_proto__server_sync__init(msg->payload.serverSync);
242                 break;
243         case TextMessage:
244                 msg->payload.textMessage = malloc(sizeof(MumbleProto__TextMessage));
245                 mumble_proto__text_message__init(msg->payload.textMessage);
246                 break;
247         case PermissionDenied:
248                 msg->payload.permissionDenied = malloc(sizeof(MumbleProto__PermissionDenied));
249                 mumble_proto__permission_denied__init(msg->payload.permissionDenied);
250                 break;
251         case CryptSetup:
252                 msg->payload.cryptSetup = malloc(sizeof(MumbleProto__CryptSetup));
253                 mumble_proto__crypt_setup__init(msg->payload.cryptSetup);
254                 break;
255         case UserList:
256                 msg->payload.userList = malloc(sizeof(MumbleProto__UserList));
257                 mumble_proto__user_list__init(msg->payload.userList);
258                 break;
259         case UserState:
260                 msg->payload.userState = malloc(sizeof(MumbleProto__UserState));
261                 mumble_proto__user_state__init(msg->payload.userState);
262                 break;
263         case UserRemove:
264                 msg->payload.userRemove = malloc(sizeof(MumbleProto__UserRemove));
265                 mumble_proto__user_remove__init(msg->payload.userRemove);
266                 break;
267         case VoiceTarget:
268                 msg->payload.voiceTarget = malloc(sizeof(MumbleProto__VoiceTarget));
269                 mumble_proto__voice_target__init(msg->payload.voiceTarget);
270                 break;
271         case CodecVersion:
272                 msg->payload.codecVersion = malloc(sizeof(MumbleProto__CodecVersion));
273                 mumble_proto__codec_version__init(msg->payload.codecVersion);
274                 break;
275         case ChannelState:
276                 msg->payload.channelState = malloc(sizeof(MumbleProto__ChannelState));
277                 mumble_proto__channel_state__init(msg->payload.channelState);
278                 break;
279
280         default:
281                 Log_warn("Msg_create: Unsupported message %d", msg->messageType);
282                 break;
283         }
284
285         return msg;
286 }
287
288 void Msg_inc_ref(message_t *msg)
289 {
290         msg->refcount++;
291 }
292
293 void Msg_free(message_t *msg)
294 {
295         if (msg->refcount) msg->refcount--;
296         if (msg->refcount > 0)
297                 return;
298
299         switch (msg->messageType) {
300         case Version:
301                 if (msg->unpacked)
302                         mumble_proto__version__free_unpacked(msg->payload.version, NULL);
303                 else {
304                         if (msg->payload.version->release)
305                                 free(msg->payload.version->release);
306                         if (msg->payload.version->os)
307                                 free(msg->payload.version->os);
308                         if (msg->payload.version->os_version)
309                                 free(msg->payload.version->os_version);
310                         free(msg->payload.version);
311                 }
312                 break;
313         case UDPTunnel:
314                 if (msg->unpacked)
315                         mumble_proto__udptunnel__free_unpacked(msg->payload.UDPTunnel, NULL);
316                 else {
317                         free(msg->payload.UDPTunnel->packet.data);
318                         free(msg->payload.UDPTunnel);
319                 }
320                 break;
321         case Authenticate:
322                 if (msg->unpacked)
323                         mumble_proto__authenticate__free_unpacked(msg->payload.authenticate, NULL);
324                 break;
325         case Ping:
326                 if (msg->unpacked)
327                         mumble_proto__ping__free_unpacked(msg->payload.ping, NULL);
328                 else {
329                         free(msg->payload.ping);
330                 }
331                 break;
332         case Reject:
333                 if (msg->unpacked)
334                         mumble_proto__reject__free_unpacked(msg->payload.reject, NULL);
335                 else {
336                         free(msg->payload.reject->reason);
337                         free(msg->payload.reject);
338                 }
339                 break;
340         case ServerSync:
341                 if (msg->unpacked)
342                         mumble_proto__server_sync__free_unpacked(msg->payload.serverSync, NULL);
343                 else {
344                         free(msg->payload.serverSync->welcome_text);
345                         free(msg->payload.serverSync);
346                 }
347                 break;
348         case TextMessage:
349                 if (msg->unpacked)
350                         mumble_proto__text_message__free_unpacked(msg->payload.textMessage, NULL);
351                 else {
352                         free(msg->payload.textMessage);
353                 }
354                 break;
355         case PermissionDenied:
356                 if (msg->unpacked)
357                         mumble_proto__permission_denied__free_unpacked(msg->payload.permissionDenied, NULL);
358                 else {
359                         free(msg->payload.permissionDenied->reason);
360                         free(msg->payload.permissionDenied);
361                 }
362                 break;
363         case CryptSetup:
364                 if (msg->unpacked)
365                         mumble_proto__crypt_setup__free_unpacked(msg->payload.cryptSetup, NULL);
366                 else {
367                         free(msg->payload.cryptSetup);
368                 }
369                 break;
370         case UserList:
371                 if (msg->unpacked)
372                         mumble_proto__user_list__free_unpacked(msg->payload.userList, NULL);
373                 else {
374                         free(msg->payload.userList);
375                 }
376                 break;
377         case UserState:
378                 if (msg->unpacked)
379                         mumble_proto__user_state__free_unpacked(msg->payload.userState, NULL);
380                 else {
381                         free(msg->payload.userState->name);
382                         free(msg->payload.userState);
383                 }
384                 break;
385         case UserRemove:
386                 if (msg->unpacked)
387                         mumble_proto__user_remove__free_unpacked(msg->payload.userRemove, NULL);
388                 else {
389                         free(msg->payload.userRemove);
390                 }
391                 break;
392         case VoiceTarget:
393                 if (msg->unpacked)
394                         mumble_proto__voice_target__free_unpacked(msg->payload.voiceTarget, NULL);
395                 else {
396                         free(msg->payload.voiceTarget);
397                 }
398                 break;
399         case CodecVersion:
400                 if (msg->unpacked)
401                         mumble_proto__codec_version__free_unpacked(msg->payload.codecVersion, NULL);
402                 else {
403                         free(msg->payload.codecVersion);
404                 }
405                 break;
406         case ChannelState:
407                 if (msg->unpacked)
408                         mumble_proto__channel_state__free_unpacked(msg->payload.channelState, NULL);
409                 else {
410                         if (msg->payload.channelState->description)
411                                 free(msg->payload.channelState->description);
412                         free(msg->payload.channelState->name);
413                         free(msg->payload.channelState);
414                 }
415                 break;
416
417         default:
418                 Log_warn("Msg_free: Unsupported message %d", msg->messageType);
419                 break;
420         }
421         free(msg);
422 }
423
424 void dumpmsg(uint8_t *data, int size)
425 {
426         int i, r = 0, offset = 0;
427         char buf[512];
428         
429         while (r * 8 + i < size) {
430                 for (i = 0; i < 8 && r * 8 + i < size; i++) {
431                         offset += sprintf(buf + offset, "%x ", data[r * 8 + i]);
432                 }
433                 sprintf(buf + offset, "\n");
434                 printf(buf);
435                 offset = 0;
436                 r++;
437                 i = 0;
438         } 
439 }
440
441 message_t *Msg_networkToMessage(uint8_t *data, int size)
442 {
443         message_t *msg = NULL;
444         uint8_t *msgData = &data[6];
445         int messageType, msgLen;
446
447         Msg_getPreamble(data, &messageType, &msgLen);
448
449         Log_debug("Message type %d size %d", messageType, msgLen);
450         dumpmsg(data, size);
451         
452         switch (messageType) {
453         case Version:
454         {
455                 msg = Msg_create(Version);
456                 msg->unpacked = true;
457                 msg->payload.version = mumble_proto__version__unpack(NULL, msgLen, msgData);
458                 break;
459         }
460         case UDPTunnel:
461         {
462                 msg = Msg_create(UDPTunnel);
463                 msg->unpacked = true;
464                 msg->payload.UDPTunnel = mumble_proto__udptunnel__unpack(NULL, msgLen, msgData);
465                 break;
466         }
467         case Authenticate:
468         {
469                 msg = Msg_create(Authenticate);
470                 msg->unpacked = true;
471                 msg->payload.authenticate = mumble_proto__authenticate__unpack(NULL, msgLen, msgData);
472                 break;
473         }
474         case Ping:
475         {
476                 msg = Msg_create(Ping);
477                 msg->unpacked = true;
478                 msg->payload.ping = mumble_proto__ping__unpack(NULL, msgLen, msgData);
479                 break;
480         }
481         case Reject:
482         {
483                 msg = Msg_create(Reject);
484                 msg->unpacked = true;
485                 msg->payload.reject = mumble_proto__reject__unpack(NULL, msgLen, msgData);
486                 break;
487         }
488         case ServerSync:
489         {
490                 msg = Msg_create(ServerSync);
491                 msg->unpacked = true;
492                 msg->payload.serverSync = mumble_proto__server_sync__unpack(NULL, msgLen, msgData);
493                 break;
494         }
495         case TextMessage:
496         {
497                 msg = Msg_create(TextMessage);
498                 msg->unpacked = true;
499                 msg->payload.textMessage = mumble_proto__text_message__unpack(NULL, msgLen, msgData);
500                 break;
501         }
502         case PermissionDenied:
503         {
504                 msg = Msg_create(PermissionDenied);
505                 msg->unpacked = true;
506                 msg->payload.permissionDenied = mumble_proto__permission_denied__unpack(NULL, msgLen, msgData);
507                 break;
508         }
509         case CryptSetup:
510         {
511                 msg = Msg_create(CryptSetup);
512                 msg->unpacked = true;
513                 msg->payload.cryptSetup = mumble_proto__crypt_setup__unpack(NULL, msgLen, msgData);
514                 break;
515         }
516         case UserList:
517         {
518                 msg = Msg_create(UserList);
519                 msg->unpacked = true;
520                 msg->payload.userList = mumble_proto__user_list__unpack(NULL, msgLen, msgData);
521                 break;
522         }
523         case UserState:
524         {
525                 msg = Msg_create(UserState);
526                 msg->unpacked = true;
527                 msg->payload.userState = mumble_proto__user_state__unpack(NULL, msgLen, msgData);
528                 break;
529         }
530         case VoiceTarget:
531         {
532                 msg = Msg_create(VoiceTarget);
533                 msg->unpacked = true;
534                 msg->payload.voiceTarget = mumble_proto__voice_target__unpack(NULL, msgLen, msgData);
535                 break;
536         }
537         case CodecVersion:
538         {
539                 msg = Msg_create(CodecVersion);
540                 msg->unpacked = true;
541                 msg->payload.codecVersion = mumble_proto__codec_version__unpack(NULL, msgLen, msgData);
542                 break;
543         }
544
545         default:
546                 Log_warn("Unsupported message %d", messageType);
547                 break;
548         }
549         return msg;
550 }