tizen 2.3 release
[framework/appfw/com-core.git] / src / packet.c
1 /*
2  * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16 */
17
18 #include <stdio.h>
19 #include <stdarg.h>
20 #include <stdlib.h>
21 #include <errno.h>
22 #include <string.h>
23 #include <sys/time.h>
24
25 #include <dlog.h>
26
27 #include "debug.h"
28 #include "packet.h"
29 #include "util.h"
30
31 int errno;
32
33 struct data {
34     struct {
35         int version;
36         int payload_size;
37         char command[PACKET_MAX_CMD];
38         enum packet_type type;
39         enum packet_flag flag;
40         double seq;
41         unsigned long source;
42         unsigned long destination;
43         unsigned long mask;
44         int fd;
45     } head;
46
47     char payload[];
48 };
49
50 struct packet {
51     enum {
52         VALID = 0xbeefbeef,
53         INVALID = 0xdeaddead
54     } state;
55     int refcnt;
56     struct data *data;
57 };
58
59 EAPI const enum packet_type const packet_type(const struct packet *packet)
60 {
61     if (!packet || packet->state != VALID || !packet->data) {
62         return PACKET_ERROR;
63     }
64
65     return packet->data->head.type;
66 }
67
68 EAPI unsigned long packet_mask(const struct packet *packet)
69 {
70     if (!packet || packet->state != VALID || !packet->data) {
71         return 0;
72     }
73
74     return packet->data->head.mask;
75 }
76
77 EAPI int packet_set_mask(struct packet *packet, unsigned long mask)
78 {
79     if (!packet || packet->state != VALID || !packet->data) {
80         return -EINVAL;
81     }
82
83     packet->data->head.mask = mask;
84     return 0;
85 }
86
87 EAPI const enum packet_flag const packet_flag(const struct packet *packet)
88 {
89     if (!packet || packet->state != VALID || !packet->data) {
90         return PACKET_FLAG_ERROR;
91     }
92
93     return packet->data->head.flag;
94 }
95
96 EAPI int packet_set_flag(struct packet *packet, enum packet_flag flag)
97 {
98     if (!packet || packet->state != VALID || !packet->data) {
99         return -EINVAL;
100     }
101
102     packet->data->head.flag = flag;
103     return 0;
104 }
105
106 EAPI const unsigned long const packet_source(const struct packet *packet)
107 {
108     if (!packet || packet->state != VALID || !packet->data) {
109         return 0;
110     }
111
112     return packet->data->head.source;
113 }
114
115 EAPI int packet_set_source(struct packet *packet, unsigned long source)
116 {
117     if (!packet || packet->state != VALID || !packet->data || !source) {
118         return -EINVAL;
119     }
120
121     packet->data->head.source = source;
122     return 0;
123 }
124
125 EAPI int packet_set_fd(struct packet *packet, int fd)
126 {
127     if (!packet || packet->state != VALID || !packet->data || fd < 0) {
128         return -EINVAL;
129     }
130
131     packet->data->head.fd = fd;
132     return 0;
133 }
134
135 EAPI int packet_fd(const struct packet *packet)
136 {
137     if (!packet || packet->state != VALID || !packet->data) {
138         return -EINVAL;
139     }
140
141     return packet->data->head.fd;
142 }
143
144 EAPI const unsigned long const packet_destination(const struct packet *packet)
145 {
146     if (!packet || packet->state != VALID || !packet->data) {
147         return 0;
148     }
149
150     return packet->data->head.destination;
151 }
152
153 EAPI int packet_set_destination(struct packet *packet, unsigned long destination)
154 {
155     if (!packet || packet->state != VALID || !packet->data || !destination) {
156         return -EINVAL;
157     }
158
159     packet->data->head.destination = destination;
160     return 0;
161 }
162
163 EAPI const int const packet_version(const struct packet *packet)
164 {
165     if (!packet || packet->state != VALID || !packet->data) {
166         return PACKET_ERROR;
167     }
168
169     return packet->data->head.version;
170 }
171
172 EAPI const int const packet_header_size(void)
173 {
174     struct data payload; /* Only for getting the size of header of packet */
175
176     return sizeof(payload.head);
177 }
178
179 EAPI const int const packet_size(const struct packet *packet)
180 {
181     if (!packet || packet->state != VALID || !packet->data) {
182         return -EINVAL;
183     }
184
185     return sizeof(*packet->data) + packet->data->head.payload_size;
186 }
187
188 EAPI const double const packet_seq(const struct packet *packet)
189 {
190     if (!packet || packet->state != VALID || !packet->data) {
191         return 0;
192     }
193
194     return packet->data->head.seq;
195 }
196
197 EAPI const int const packet_payload_size(const struct packet *packet)
198 {
199     if (!packet || packet->state != VALID || !packet->data) {
200         return -EINVAL;
201     }
202
203     return packet->data->head.payload_size;
204 }
205
206 EAPI const char * const packet_command(const struct packet *packet)
207 {
208     if (!packet || packet->state != VALID || !packet->data) {
209         return NULL;
210     }
211
212     return packet->data->head.command;
213 }
214
215 EAPI const void * const packet_data(const struct packet *packet)
216 {
217     if (!packet || packet->state != VALID) {
218         return NULL;
219     }
220
221     return packet->data;
222 }
223
224 static inline __attribute__((always_inline)) struct data *check_and_expand_packet(struct data *packet, int *payload_size)
225 {
226     struct data *new_packet;
227
228     if (packet->head.payload_size < *payload_size) {
229         return packet;
230     }
231
232     new_packet = realloc(packet, sizeof(*packet) + *payload_size + BUFSIZ); /*!< Expanding to +BUFSIZ */
233     if (!new_packet) {
234         ErrPrint("Heap: %s\n", strerror(errno));
235         free(packet);
236         return NULL;
237     }
238
239     *payload_size += BUFSIZ;
240     return new_packet;
241 }
242
243 static inline struct packet *packet_body_filler(struct packet *packet, int payload_size, const char *ptr, va_list va)
244 {
245     char *payload;
246     char *str;
247     int align;
248
249     while (*ptr) {
250         payload = packet->data->payload + packet->data->head.payload_size;
251
252         switch (*ptr) {
253             case 'i':
254             case 'I':
255                 align = (unsigned long)payload & (sizeof(int) - 1);
256                 if (align) {
257                     align = sizeof(int) - align;
258                 }
259
260                 packet->data->head.payload_size += sizeof(int) + align;
261                 packet->data = check_and_expand_packet(packet->data, &payload_size);
262                 if (!packet->data) {
263                     packet->state = INVALID;
264                     free(packet);
265                     packet = NULL;
266                     goto out;
267                 }
268
269                 *((int *)(payload + align)) = (int)va_arg(va, int);
270                 break;
271             case 's':
272             case 'S':
273                 str = (char *)va_arg(va, char *);
274
275                 if (str) {
276                     packet->data->head.payload_size += strlen(str) + 1; /*!< Including NIL */
277                     packet->data = check_and_expand_packet(packet->data, &payload_size);
278                     if (!packet->data) {
279                         packet->state = INVALID;
280                         free(packet);
281                         packet = NULL;
282                         goto out;
283                     }
284
285                     strcpy(payload, str); /*!< Including NIL */
286                 } else {
287                     packet->data->head.payload_size += 1;
288                     packet->data = check_and_expand_packet(packet->data, &payload_size);
289                     if (!packet->data) {
290                         packet->state = INVALID;
291                         free(packet);
292                         packet = NULL;
293                         goto out;
294                     }
295
296                     payload[0] = '\0';
297                 }
298                 break;
299             case 'd':
300             case 'D':
301                 align = (unsigned long)payload & (sizeof(double) - 1);
302                 if (align) {
303                     align = sizeof(double) - align;
304                 }
305
306                 packet->data->head.payload_size += sizeof(double) + align;
307                 packet->data = check_and_expand_packet(packet->data, &payload_size);
308                 if (!packet->data) {
309                     packet->state = INVALID;
310                     free(packet);
311                     packet = NULL;
312                     goto out;
313                 }
314
315                 *((double *)(payload + align)) = (double)va_arg(va, double);
316                 break;
317             default:
318                 ErrPrint("Invalid type [%c]\n", *ptr);
319                 packet->state = INVALID;
320                 free(packet->data);
321                 free(packet);
322                 packet = NULL;
323                 goto out;
324         }
325
326         ptr++;
327     }
328
329 out:
330     return packet;
331 }
332
333 EAPI struct packet *packet_create_reply(const struct packet *packet, const char *fmt, ...)
334 {
335     int payload_size;
336     struct packet *result;
337     va_list va;
338
339     if (!packet || packet->state != VALID) {
340         return NULL;
341     }
342
343     result = malloc(sizeof(*result));
344     if (!result) {
345         ErrPrint("Heap: %s\n", strerror(errno));
346         return NULL;
347     }
348
349     payload_size = sizeof(*result->data) + BUFSIZ;
350     result->refcnt = 0;
351     result->data = calloc(1, payload_size);
352     if (!result->data) {
353         ErrPrint("Heap: %s\n", strerror(errno));
354         result->state = INVALID;
355         free(result);
356         return NULL;
357     }
358
359     result->state = VALID;
360     result->data->head.source = packet->data->head.destination;
361     result->data->head.destination = packet->data->head.source;
362     result->data->head.mask = 0xFFFFFFFF;
363
364     result->data->head.seq = packet->data->head.seq;
365     result->data->head.type = PACKET_ACK;
366     result->data->head.version = packet->data->head.version;
367     result->data->head.fd = -1;
368     if (packet->data->head.command[0] == PACKET_CMD_INT_TAG) {
369         unsigned int *head_cmd = (unsigned int *)result->data->head.command;
370         unsigned int *packet_cmd = (unsigned int *)packet->data->head.command;
371
372         *head_cmd = *packet_cmd;
373     } else {
374         strcpy(result->data->head.command, packet->data->head.command); /* we don't need to use strncmp */
375     }
376     result->data->head.payload_size = 0;
377     payload_size -= sizeof(*result->data);
378
379     va_start(va, fmt);
380     result = packet_body_filler(result, payload_size, fmt, va);
381     va_end(va);
382
383     return packet_ref(result);
384 }
385
386 EAPI int packet_swap_address(struct packet *packet)
387 {
388     unsigned long tmp;
389
390     if (!packet || packet->state != VALID) {
391         return -EINVAL;
392     }
393
394     tmp = packet->data->head.source;
395     packet->data->head.source = packet->data->head.destination;
396     packet->data->head.destination = tmp;
397
398     return 0;
399 }
400
401 EAPI struct packet *packet_create(const char *cmd, const char *fmt, ...)
402 {
403     struct packet *packet;
404     int payload_size;
405     va_list va;
406
407     if (strlen(cmd) >= PACKET_MAX_CMD) {
408         ErrPrint("Command is too long\n");
409         return NULL;
410     }
411
412     packet = malloc(sizeof(*packet));
413     if (!packet) {
414         ErrPrint("Heap: %s\n", strerror(errno));
415         return NULL;
416     }
417
418     payload_size = sizeof(*packet->data) + BUFSIZ;
419     packet->refcnt = 0;
420     packet->data = calloc(1, payload_size);
421     if (!packet->data) {
422         ErrPrint("Heap: %s\n", strerror(errno));
423         packet->state = INVALID;
424         free(packet);
425         return NULL;
426     }
427
428     packet->state = VALID;
429     packet->data->head.source = 0lu;
430     packet->data->head.destination = 0lu;
431     packet->data->head.mask = 0xFFFFFFFF;
432     packet->data->head.seq = util_timestamp();
433     packet->data->head.type = PACKET_REQ;
434     packet->data->head.version = PACKET_VERSION;
435     packet->data->head.fd = -1;
436     if (cmd[0] == PACKET_CMD_INT_TAG) {
437         unsigned int *head_cmd = (unsigned int *)packet->data->head.command;
438         unsigned int *in_cmd = (unsigned int *)cmd;
439
440         *head_cmd = *in_cmd;
441     } else {
442         strncpy(packet->data->head.command, cmd, sizeof(packet->data->head.command));
443     }
444     packet->data->head.payload_size = 0;
445     payload_size -= sizeof(*packet->data); /*!< Usable payload size (except head size) */
446
447     va_start(va, fmt);
448     packet = packet_body_filler(packet, payload_size, fmt, va);
449     va_end(va);
450
451     return packet_ref(packet);
452 }
453
454 EAPI struct packet *packet_create_noack(const char *cmd, const char *fmt, ...)
455 {
456     int payload_size;
457     struct packet *result;
458     va_list va;
459
460     if (strlen(cmd) >= PACKET_MAX_CMD) {
461         ErrPrint("Command is too long\n");
462         return NULL;
463     }
464
465     result = malloc(sizeof(*result));
466     if (!result) {
467         ErrPrint("Heap: %s\n", strerror(errno));
468         return NULL;
469     }
470
471     payload_size = sizeof(*result->data) + BUFSIZ;
472     result->refcnt = 0;
473     result->data = calloc(1, payload_size);
474     if (!result->data) {
475         ErrPrint("Heap: %s\n", strerror(errno));
476         result->state = INVALID;
477         free(result);
478         return NULL;
479     }
480
481     result->state = VALID;
482     result->data->head.source = 0lu;
483     result->data->head.destination = 0lu;
484     result->data->head.mask = 0xFFFFFFFF;
485     result->data->head.seq = util_timestamp();
486     result->data->head.type = PACKET_REQ_NOACK;
487     result->data->head.version = PACKET_VERSION;
488     result->data->head.fd = -1;
489     if (cmd[0] == PACKET_CMD_INT_TAG) {
490         unsigned int *head_cmd = (unsigned int *)result->data->head.command;
491         unsigned int *cmd_in = (unsigned int *)cmd;
492         *head_cmd = *cmd_in;
493     } else {
494         strncpy(result->data->head.command, cmd, sizeof(result->data->head.command));
495     }
496     result->data->head.payload_size = 0;
497     payload_size -= sizeof(*result->data);
498
499     va_start(va, fmt);
500     result = packet_body_filler(result, payload_size, fmt, va);
501     va_end(va);
502
503     return packet_ref(result);
504 }
505
506 EAPI int packet_get(const struct packet *packet, const char *fmt, ...)
507 {
508     const char *ptr;
509     va_list va;
510     int ret = 0;
511     char *payload;
512     int offset = 0;
513     int *int_ptr;
514     double *double_ptr;
515     char **str_ptr;
516     int align;
517
518     if (!packet || packet->state != VALID) {
519         return -EINVAL;
520     }
521
522     va_start(va, fmt);
523
524     ptr = fmt;
525     while (*ptr && offset < packet->data->head.payload_size) {
526         payload = packet->data->payload + offset;
527         switch (*ptr) {
528             case 'i':
529             case 'I':
530                 align = (unsigned long)payload & (sizeof(int) - 1);
531                 if (align) {
532                     align = sizeof(int) - align;
533                 }
534
535                 int_ptr = (int *)va_arg(va, int *);
536                 *int_ptr = *((int *)(payload + align));
537                 offset += (sizeof(int) + align);
538                 ret++;
539                 break;
540             case 'd':
541             case 'D':
542                 align = (unsigned long)payload & (sizeof(double) - 1);
543                 if (align) {
544                     align = sizeof(double) - align;
545                 }
546                 double_ptr = (double *)va_arg(va, double *);
547                 *double_ptr = *((double *)(payload + align));
548                 offset += (sizeof(double) + align);
549                 ret++;
550                 break;
551             case 's':
552             case 'S':
553                 str_ptr = (char **)va_arg(va, char **);
554                 *str_ptr = payload;
555                 offset += (strlen(*str_ptr) + 1); /*!< Including NIL */
556                 ret++;
557                 break;
558             default:
559                 ret = -EINVAL;
560                 goto out;
561         }
562         ptr++;
563     }
564
565 out:
566     va_end(va);
567     return ret;
568 }
569
570 EAPI struct packet *packet_ref(struct packet *packet)
571 {
572     if (!packet || packet->state != VALID) {
573         return NULL;
574     }
575
576     packet->refcnt++;
577     return packet;
578 }
579
580 EAPI struct packet *packet_unref(struct packet *packet)
581 {
582     if (!packet || packet->state != VALID) {
583         return NULL;
584     }
585
586     packet->refcnt--;
587     if (packet->refcnt < 0) {
588         ErrPrint("Invalid refcnt\n");
589         return NULL;
590     }
591
592     if (packet->refcnt == 0) {
593         packet->state = INVALID;
594         free(packet->data);
595         free(packet);
596         return NULL;
597     }
598
599     return packet;
600 }
601
602 EAPI int packet_destroy(struct packet *packet)
603 {
604     packet_unref(packet);
605     return 0;
606 }
607
608 EAPI struct packet *packet_build(struct packet *packet, int offset, void *data, int size)
609 {
610     char *ptr;
611
612     if (packet == NULL) {
613         if (offset) {
614             ErrPrint("Invalid argument\n");
615             return NULL;
616         }
617
618         packet = malloc(sizeof(*packet));
619         if (!packet) {
620             ErrPrint("Heap: %s\n", strerror(errno));
621             return NULL;
622         }
623
624         packet->refcnt = 1;
625         packet->data = calloc(1, size);
626         if (!packet->data) {
627             ErrPrint("Heap: %s\n", strerror(errno));
628             packet->state = INVALID;
629             free(packet);
630             return NULL;
631         }
632
633         packet->state = VALID;
634         memcpy(packet->data, data, size);
635         packet->data->head.mask = 0xFFFFFFFF;
636         return packet;
637     }
638
639     ptr = realloc(packet->data, offset + size);
640     if (!ptr) {
641         ErrPrint("Heap: %s\n", strerror(errno));
642         packet->state = INVALID;
643         free(packet->data);
644         free(packet);
645         return NULL;
646     }
647
648     packet->data = (struct data *)ptr;
649     memcpy(ptr + offset, data, size);
650
651     return packet;
652 }
653
654 /* End of a file */