| 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 |
|
| 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 |
|
| 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 |
|
| 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 |
|
| 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 |
|
| 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 |
|
| 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 } |
|