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