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