1 /* $Id$ */
2
3 /*
4 * (C) Copyright 2012 Tomek Wasilczyk <www.wasilczyk.pl>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License Version
8 * 2.1 as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
18 * USA.
19 */
20
21 /**
22 * \file protobuf.c
23 *
24 * \brief Funkcje pomocnicze do obsługi formatu protocol buffers
25 */
26
27 #include "protobuf.h"
28
29 #define GG_PROTOBUFF_UIN_MAXLEN 15
30 struct _gg_protobuf_uin_buff
31 {
32 char data[GG_PROTOBUFF_UIN_MAXLEN + 1 + 2];
33 };
34
gg_protobuf_expected(struct gg_session * gs,const char * field_name,uint32_t value,uint32_t expected)35 void gg_protobuf_expected(struct gg_session *gs, const char *field_name,
36 uint32_t value, uint32_t expected)
37 {
38 if (value == expected) {
39 return;
40 }
41 gg_debug_session(gs, GG_DEBUG_WARNING, "// gg_packet: field %s was "
42 "expected to be %#x, but its value was %#x\n",
43 field_name, expected, value);
44 }
45
gg_protobuf_valid_chknull(struct gg_session * gs,const char * msg_name,int isNull)46 int gg_protobuf_valid_chknull(struct gg_session *gs, const char *msg_name,
47 int isNull)
48 {
49 if (isNull) {
50 gg_debug_session(gs, GG_DEBUG_ERROR, "// gg_protobuf: couldn't "
51 "unpack %s message\n", msg_name);
52 }
53 return !isNull;
54 }
55
gg_protobuf_valid_chkunknown(struct gg_session * gs,const char * msg_name,ProtobufCMessage * base)56 int gg_protobuf_valid_chkunknown(struct gg_session *gs, const char *msg_name,
57 ProtobufCMessage *base)
58 {
59 if (base->n_unknown_fields > 0) {
60 gg_debug_session(gs, GG_DEBUG_WARNING, "// gg_protobuf: message"
61 " %s had %d unknown field(s)\n",
62 msg_name, base->n_unknown_fields);
63 }
64 return 1;
65 }
66
gg_protobuf_send_ex(struct gg_session * gs,struct gg_event * ge,int type,void * msg,gg_protobuf_size_cb_t size_cb,gg_protobuf_pack_cb_t pack_cb)67 int gg_protobuf_send_ex(struct gg_session *gs, struct gg_event *ge, int type,
68 void *msg, gg_protobuf_size_cb_t size_cb,
69 gg_protobuf_pack_cb_t pack_cb)
70 {
71 void *buffer;
72 size_t len;
73 int succ = 1;
74 enum gg_failure_t failure;
75
76 len = size_cb(msg);
77 buffer = malloc(len);
78 if (buffer == NULL) {
79 gg_debug_session(gs, GG_DEBUG_ERROR, "// gg_protobuf_send: out "
80 "of memory - tried to allocate %" GG_SIZE_FMT
81 " bytes for %#x packet\n", len, type);
82 succ = 0;
83 failure = GG_FAILURE_INTERNAL;
84 } else {
85 pack_cb(msg, buffer);
86 succ = (-1 != gg_send_packet(gs, type, buffer, len, NULL));
87 free(buffer);
88 buffer = NULL;
89 if (!succ) {
90 failure = GG_FAILURE_WRITING;
91 gg_debug_session(gs, GG_DEBUG_ERROR,
92 "// gg_protobuf_send: sending packet %#x "
93 "failed. (errno=%d, %s)\n", type, errno,
94 strerror(errno));
95 }
96 }
97
98 if (!succ) {
99 gg_connection_failure(gs, ge, failure);
100 }
101
102 return succ;
103 }
104
gg_protobuf_set_uin(ProtobufCBinaryData * dst,uin_t uin,gg_protobuf_uin_buff_t * buff)105 void gg_protobuf_set_uin(ProtobufCBinaryData *dst, uin_t uin, gg_protobuf_uin_buff_t *buff)
106 {
107 char *uin_str;
108 int uin_len;
109 static gg_protobuf_uin_buff_t static_buffer;
110
111 if (buff == NULL) {
112 buff = &static_buffer;
113 }
114
115 uin_str = buff->data + 2;
116 uin_len = snprintf(uin_str, GG_PROTOBUFF_UIN_MAXLEN + 1, "%u", uin);
117
118 buff->data[0] = 0x01; /* magic: 0x00 lub 0x01 */
119 buff->data[1] = uin_len;
120
121 dst->len = uin_len + 2;
122 dst->data = (uint8_t*)&buff->data;
123 }
124
gg_protobuf_get_uin(ProtobufCBinaryData uin_data)125 uin_t gg_protobuf_get_uin(ProtobufCBinaryData uin_data)
126 {
127 uint8_t magic;
128 size_t uin_len;
129 const char *uin_str;
130 uin_t uin;
131
132 magic = (uin_data.len > 0) ? uin_data.data[0] : 0;
133 uin_len = (uin_data.len > 1) ? uin_data.data[1] : 0;
134
135 if (uin_data.len != uin_len + 2 || uin_len > 10) {
136 gg_debug(GG_DEBUG_ERROR, "// gg_protobuf_get_uin: "
137 "invalid length\n");
138 return 0;
139 }
140 if (magic != 0) {
141 gg_debug(GG_DEBUG_WARNING, "// gg_protobuf_get_uin: "
142 "unexpected magic value=%#x\n", magic);
143 }
144
145 uin_str = (char*)(uin_data.data + 2);
146 uin = gg_str_to_uin(uin_str, uin_len);
147
148 if (uin == 0) {
149 gg_debug(GG_DEBUG_ERROR, "// gg_protobuf_get_uin: "
150 "invalid uin\n");
151 }
152 return uin;
153 }
154