Git init
[pkgs/e/elektra.git] / src / backends / daemon / protocol.c
1 /***************************************************************************
2                 protocol.c  -  Class for a protocol
3                              -------------------
4     begin                : Sun Mar 12 2006
5     copyright            : (C) 2006 by Yannick Lecaillez, Avi Alkalay
6     email                : sizon5@gmail.com, avi@unix.sh
7  ***************************************************************************/
8
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the BSD License (revised).                      *
13  *                                                                         *
14  ***************************************************************************/
15
16 /***************************************************************************
17  *                                                                         *
18  * Class for messages, to be passed over a protocol line.                  *
19  *                                                                         *
20  ***************************************************************************/
21
22
23
24 /* Subversion stuff
25
26 $Id$
27
28 */
29
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33
34 #include <assert.h>
35
36 #include <errno.h>
37 #ifdef HAVE_SYS_TYPES_H
38 #include <sys/types.h>
39 #endif
40 #ifdef HAVE_UNISTD_H
41 #include <unistd.h>
42 #endif
43 #include <stdio.h>
44 #ifdef HAVE_STDLIB_H
45 #include <stdlib.h>
46 #endif
47 #include <stdarg.h>
48 #ifdef HAVE_STRING_H
49 #include <string.h>
50 #endif
51
52 #include "datatype.h"
53 #include "message.h"
54
55 #include "protocol.h"
56
57 /* Magic: Magic number for protocol header. Elektra written like l33t ;-) */
58 #define PROTO_MAGIC     0x0E1E374AL
59 #define PROTO_VERSION   1
60
61 static int     protocolCheckHeader         (const ProtocolHeader *header);
62
63
64 /**
65  * @defgroup protocol Protocol
66  * @brief Protocol provide methods for transport Message throught a medium.
67  * 
68  * Protocol allow to send & receive @link message Message@endlink securely. It does some sanity check
69  * like checking protocol version & a magic number user for verify @link message message@endlink boundaries.
70  *
71  */
72
73 /**
74  * Read a message from file/socket fd 
75  * This methods check header, read data and
76  * create a new Message object from data.
77  *
78  * @param fd File Descriptor where data should be readen
79  * @return a newly allocated message (which must be freed
80  * using messageDel()) or NULL if error occured.
81  *
82  * @see protocolCheckHeader()
83  * @see protocolSendMessage()
84  *
85  * @ingroup protocol
86  */
87 Message *protocolReadMessage(int fd)
88 {
89         Message         *msg;
90         char            *buf;
91         ProtocolHeader  header;
92         size_t          toRead;
93         ssize_t          ret;
94         
95         /* read header */
96         memset(&header, 0, sizeof(header));
97         if ( (ret = read(fd, &header, sizeof(header))) == -1 ) {
98                 return NULL;
99         }
100         
101         if ( protocolCheckHeader(&header) ) { 
102                 return NULL;
103         }
104
105         /* read message */
106         msg = (Message *) malloc(header.dataLen);
107         if ( msg == NULL ) {
108                 return NULL;
109         }
110         
111         buf = (char *) msg;
112         toRead = header.dataLen;
113         while ( toRead > 0 ) {
114                 if ( (ret = read(fd, buf, toRead)) == -1 ) {
115                         return NULL;
116                 }
117
118                 toRead -= ret;
119                 buf += ret;
120         }
121
122         return msg;
123 }
124
125 /**
126  * Write a specified message to a file/socket
127  * This methods build a header, and write message to the descriptor.
128  * 
129  * @param fd File Descriptor where data should be written
130  * @param message Message to send.
131  * @return 0 if OK, -1 otherwise
132  *
133  * @see protocolReadMessage()
134  * @ingroup protocol
135  */
136 int protocolSendMessage(int fd, const Message *message)
137 {
138         ProtocolHeader header;
139         const char      *buf;
140         size_t  toWrite;
141         ssize_t ret;
142
143         assert(message != NULL);
144         
145         /* Send header */
146         memset(&header, 0, sizeof(header));
147         header.magic    = PROTO_MAGIC;
148         header.version  = PROTO_VERSION;
149         header.dataLen  = message->size;
150         if ( (ret = write(fd, &header, sizeof(header))) == -1 ) {
151                 return -1;
152         }
153         
154         /* Send message */
155         toWrite = message->size;
156         buf = (const char *) message;
157         while ( toWrite > 0 ) {
158                 if ( (ret = write(fd, buf, message->size)) == -1 ) {
159                         return -1;
160                 }
161
162                 toWrite -= ret;
163                 buf += ret;
164         }
165         
166         return 0;
167 }
168
169 /**
170  * Check header validity
171  * This methods check a magic number for detect data boundaries.
172  * Check a version number for compatibility between protocol version.
173  *
174  * @param header Header to check
175  * @return 0 if OK, -1 otherwise
176  *
177  * @see protocolReadMessage()
178  */
179 static int protocolCheckHeader(const ProtocolHeader *header)
180 {
181         assert(header != NULL);
182
183         if ( header->magic != PROTO_MAGIC ) {
184                 errno = EINVAL;
185                 return -1;
186         }
187
188         if ( header->version < PROTO_VERSION ) {
189                 errno = EINVAL;
190                 return -1;
191         }       
192
193         return 0;
194 }