transport.c (8046B)
1 #include <stddef.h> 2 #include <stdlib.h> 3 #include <string.h> 4 5 #include <b64/cencode.h> 6 #include <b64/cdecode.h> 7 #include <zlib.h> 8 9 #include "transport.h" 10 #include "ledger.h" 11 #include "debug.h" 12 13 14 static int pack_compress(char *in, size_t in_len, char *out, size_t *out_len) { 15 int r; 16 z_stream z; 17 18 z.zalloc = Z_NULL; 19 z.zfree = Z_NULL; 20 z.opaque = Z_NULL; 21 z.data_type = Z_TEXT; 22 z.next_in = (unsigned char*)in; 23 z.avail_in = in_len; 24 z.next_out = (unsigned char*)out; 25 z.avail_out = *out_len; 26 27 r = deflateInit(&z, Z_BEST_COMPRESSION); 28 if (r != Z_OK) { 29 return 1; 30 } 31 r = deflate(&z, Z_FINISH); 32 if (r != Z_STREAM_END) { 33 return 2; 34 } 35 *out_len = z.total_out; 36 37 return 0; 38 } 39 40 static int pack_encode(char *in, size_t in_len, char *out, size_t *out_len) { 41 char *p; 42 int r; 43 base64_encodestate bst; 44 45 base64_init_encodestate(&bst); 46 47 p = out; 48 r = base64_encode_block(in, in_len, p, &bst); 49 if (r == 0) { 50 return 1; 51 } 52 *out_len = r; 53 p += r; 54 r = base64_encode_blockend(p, &bst); 55 if (r == 0) { 56 return 1; 57 } 58 *out_len += r; 59 60 return 0; 61 62 } 63 64 static int unpack_decompress(char *in, size_t in_len, char *out, size_t *out_len) { 65 int r; 66 z_stream z; 67 68 z.zalloc = Z_NULL; 69 z.zfree = Z_NULL; 70 z.opaque = Z_NULL; 71 z.data_type = Z_TEXT; 72 z.next_in = (unsigned char*)in; 73 z.avail_in = in_len; 74 z.next_out = (unsigned char*)out; 75 z.avail_out = *out_len; 76 77 r = inflateInit(&z); 78 if (r != Z_OK) { 79 return 1; 80 } 81 r = inflate(&z, Z_FINISH); 82 if (r != Z_STREAM_END) { 83 return 2; 84 } 85 *out_len = z.total_out; 86 87 return 0; 88 } 89 90 static int unpack_decode(char *in, size_t in_len, char *out, size_t *out_len) { 91 int r; 92 base64_decodestate dst; 93 94 base64_init_decodestate(&dst); 95 r = base64_decode_block(in, in_len, out, &dst); 96 if (r == 0) { 97 return 1; 98 } 99 *out_len = r; 100 101 return 0; 102 } 103 104 int pack(char *in, size_t in_len, char *out, size_t *out_len) { 105 int r; 106 char *buf; 107 108 buf = malloc(*out_len); 109 110 r = pack_compress(in, in_len, buf, out_len); 111 if (r) { 112 free(buf); 113 return ERR_FAIL; 114 } 115 116 r = pack_encode(buf, *out_len, out, out_len); 117 if (r) { 118 free(buf); 119 return ERR_FAIL; 120 } 121 if (*(out+*out_len-1) == 0x0a) { 122 *(out+*out_len-1) = 0; 123 (*out_len)--; 124 } 125 126 free(buf); 127 return ERR_OK; 128 } 129 130 int unpack(char *in, size_t in_len, char *out, size_t *out_len) { 131 int r; 132 char *buf; 133 size_t c; 134 135 buf = malloc(*out_len); 136 137 c = *out_len; 138 r = unpack_decode(in, in_len, buf, &c); 139 if (r) { 140 free(buf); 141 return ERR_FAIL; 142 } 143 144 r = unpack_decompress(buf, c, out, out_len); 145 if (r) { 146 free(buf); 147 return ERR_FAIL; 148 } 149 150 free(buf); 151 return ERR_OK; 152 } 153 154 /// \todo implement checksum 155 int kee_transport_single(struct kee_transport_t *trans, enum kee_transport_mode_e mode, char cmd, size_t data_len) { 156 memset(trans, 0, sizeof(struct kee_transport_t)); 157 if (cmd >= KEE_N_CMD) { 158 return ERR_INVALID_CMD; 159 } 160 if (data_len == 0) { 161 trans->chunker.data_len = KEE_TRANSPORT_CHUNK_MAX_SIZE; 162 } else { 163 trans->chunker.data_len = data_len + 1; 164 } 165 trans->data = trans->chunker.data; 166 trans->cmd = (char*)trans->data; 167 trans->mode = mode; 168 *(trans->cmd) = cmd; 169 trans->chunker.crsr = 1; 170 171 return ERR_OK; 172 } 173 174 //int kee_transport_import(struct kee_transport_t *trans, enum kee_transport_mode_e mode, const char *data, size_t data_len) { 175 //int kee_transport_import(struct kee_transport_t *trans, enum kee_transport_mode_e mode) { 176 // memset(trans, 0, sizeof(struct kee_transport_t)); 177 // //memcpy(trans->chunker.data, data, data_len); 178 // //if (*data & KEE_CMD_CHUNKED) { 179 // // return ERR_UNSUPPORTED; 180 // //} 181 // trans->chunker.crsr = 1; 182 // trans->chunker.data_len = KEE_TRANSPORT_CHUNK_MAX_SIZE; 183 // trans->mode = mode; 184 // *trans->cmd = KEE_CMD_IMPORT; 185 // 186 // return ERR_OK; 187 //} 188 189 void kee_transport_set_response(struct kee_transport_t *trans) { 190 if (trans->state == 0) { 191 *trans->cmd |= KEE_CMD_SIGN_RESPONSE; 192 } 193 } 194 195 int kee_transport_write(struct kee_transport_t *trans, const char *in, size_t in_len) { 196 if (trans->state) { 197 return ERR_FAIL; 198 } 199 memcpy(trans->data + trans->chunker.crsr, in, in_len); 200 trans->chunker.crsr += in_len; 201 return ERR_OK; 202 } 203 204 /// \todo consider pass validation function 205 /// \todo implement chunking 206 int kee_transport_next(struct kee_transport_t *trans, char *out, size_t *out_len) { 207 int r; 208 size_t l; 209 size_t remaining; 210 211 if (trans->state) { 212 if (trans->state > 1) { 213 return ERR_FAIL; 214 } 215 } else { 216 trans->chunker.data_len = trans->chunker.crsr; 217 trans->chunker.crsr = 0; 218 trans->state = 1; 219 } 220 221 remaining = trans->chunker.data_len - trans->chunker.crsr; 222 if (remaining < KEE_TRANSPORT_CHUNK_MAX_SIZE - 1) { 223 l = remaining; 224 } else { 225 return 1; // unimplemented 226 //l = KEE_TRANSPORT_CHUNK_SIZE; 227 } 228 229 /// \todo when chunking, dont forget this as a separate step before start to chunk 230 switch (trans->mode) { 231 case KEE_TRANSPORT_BASE64: 232 r = pack(trans->chunker.data, l, out, out_len); 233 if (r) { 234 return ERR_FAIL; 235 } 236 break; 237 case KEE_TRANSPORT_RAW: 238 memcpy(out, trans->chunker.data, l); 239 break; 240 default: 241 return ERR_FAIL; 242 } 243 return 0; 244 } 245 246 247 int kee_transport_read(struct kee_transport_t *trans, char *out, size_t *out_len) { 248 int r; 249 250 if (*trans->cmd == KEE_CMD_IMPORT) { 251 trans->data++; 252 } 253 254 switch (trans->mode) { 255 case KEE_TRANSPORT_BASE64: 256 r = unpack(trans->data, trans->chunker.data_len, out, out_len); 257 if (r) { 258 return ERR_FAIL; 259 } 260 break; 261 case KEE_TRANSPORT_RAW: 262 memcpy(out, trans->data, trans->chunker.data_len); 263 break; 264 default: 265 return ERR_FAIL; 266 } 267 268 if (*trans->cmd == KEE_CMD_IMPORT) { 269 /// \todo handle this crop better, should not require any of these copies 270 *trans->cmd = *out; 271 memcpy(trans->data, out+1, *out_len); 272 (*out_len)--; 273 memcpy(out, trans->data, *out_len); 274 } 275 276 return ERR_OK; 277 } 278 279 // 280 //// make sure reported sizes add up to data boundary 281 //static int validate_multi(char *data, size_t data_len) { 282 // char *p; 283 // size_t c; 284 // unsigned short l; 285 // 286 // c = 0; 287 // p = data; 288 // while (c < data_len - 1) { 289 // memcpy(&l, p, sizeof(unsigned short)); 290 // if (l == 0) { 291 // break; 292 // } 293 // if (is_le()) { 294 // flip_endian(2, &l); 295 // } 296 // c += l + sizeof(unsigned short); 297 // p += c; 298 // } 299 // if (p == data) { 300 // return ERR_FAIL; 301 // } 302 // return c != data_len - 1; 303 //} 304 // 305 ///// \todo check state 306 //int kee_transport_validate(struct kee_transport_t *trans) { 307 // int r; 308 // char cmd; 309 // 310 // cmd = *trans->cmd & 0x1f; 311 // 312 // if (cmd == 0) { 313 // r = validate_multi(trans->chunker.data + 1, trans->chunker.data_len); 314 // if (r) { 315 // return ERR_FAIL; 316 // } 317 // } 318 // return ERR_OK; 319 //} 320 321 322 //int kee_transport_encode_ledger(struct kee_transport_t *trans_ledger, struct kee_transport_t *trans_item, struct kee_transport_t *trans_out, enum kee_transport_mode_e mode) { 323 // int r; 324 // char *p; 325 // unsigned short part_length; 326 // size_t l; 327 // size_t c; 328 // char *out; 329 // 330 // l = sizeof(unsigned short); 331 // out = malloc(trans_ledger->chunker.data_len + trans_item->chunker.data_len + (l * 2) + 1); 332 // // only use raw mode for this, since we are joining data 333 // if (trans_ledger->mode != KEE_TRANSPORT_RAW) { 334 // return ERR_FAIL; 335 // } 336 // if (trans_item->mode != KEE_TRANSPORT_RAW) { 337 // return ERR_FAIL; 338 // } 339 // c = 0; 340 // p = out; 341 // part_length = (unsigned short)trans_ledger->chunker.data_len; 342 // r = to_endian(TO_ENDIAN_BIG, 2, &part_length); 343 // if (r) { 344 // return ERR_FAIL; 345 // } 346 // memcpy(p, &part_length, l); 347 // p += sizeof(unsigned short); 348 // c += l; 349 // memcpy(p, trans_ledger->chunker.data, trans_ledger->chunker.data_len); 350 // p += trans_ledger->chunker.data_len; 351 // c += trans_ledger->chunker.data_len; 352 // 353 // part_length = (unsigned short)trans_item->chunker.data_len; 354 // r = to_endian(TO_ENDIAN_BIG, 2, &part_length); 355 // if (r) { 356 // return ERR_FAIL; 357 // } 358 // memcpy(p, &part_length, l); 359 // p += l; 360 // c += l; 361 // memcpy(p, trans_item->chunker.data, trans_item->chunker.data_len); 362 // p += trans_item->chunker.data_len; 363 // c += trans_item->chunker.data_len; 364 // 365 // r = kee_transport_single(trans_out, mode, KEE_CMD_PACKED, c); 366 // if (r) { 367 // return ERR_FAIL; 368 // } 369 // r = kee_transport_write(trans_out, out, c); 370 // if (r) { 371 // return ERR_FAIL; 372 // } 373 // 374 // free(out); 375 // 376 // return ERR_OK; 377 //}