root/trunk/src/proto/PINT-reqproto-encode.c @ 4617

Revision 4617, 10.4 KB (checked in by robl, 8 years ago)

[pcarns]: add protocol versioning to PVFS2. Major version changes are
incompatible up or down. New clients can't talk to old servers, but new
servers can talk to old clients.

Line 
1/*
2 * (C) 2001 Clemson University and The University of Chicago
3 *
4 * See COPYING in top-level directory.
5 */
6
7#include <stdlib.h>
8#include <errno.h>
9#include <string.h>
10
11#include "bmi.h"
12#include "gossip.h"
13#include "pvfs2-req-proto.h"
14#include "PINT-reqproto-encode.h"
15#include "PINT-reqproto-module.h"
16#include "bmi-byteswap.h"
17#include "pint-event.h"
18#include "id-generator.h"
19
20#define ENCODING_TABLE_SIZE 5
21
22/* macros for logging encode and decode events */
23#define ENCODE_EVENT_START(__enctype, __reqtype, __ptr) \
24do { \
25    PVFS_id_gen_t __tmp_id; \
26    id_gen_fast_register(&__tmp_id, (__ptr)); \
27    PINT_event_timestamp(__enctype, \
28    (int32_t)(__reqtype), 0, __tmp_id, \
29    PVFS_EVENT_FLAG_START); \
30} while(0)
31#define ENCODE_EVENT_STOP(__enctype, __reqtype, __ptr, __size) \
32do { \
33    PVFS_id_gen_t __tmp_id; \
34    id_gen_fast_register(&__tmp_id, (__ptr)); \
35    PINT_event_timestamp(__enctype, \
36    (int32_t)(__reqtype), (__size), __tmp_id, \
37    PVFS_EVENT_FLAG_END); \
38} while(0)
39
40extern PINT_encoding_table_values le_bytefield_table;
41int g_admin_mode = 0;
42
43static PINT_encoding_table_values *PINT_encoding_table[
44    ENCODING_TABLE_SIZE] = {NULL};
45
46/* PINT_encode_initialize()
47 *
48 * starts up the protocol encoding interface
49 *
50 * returns 0 on success, -PVFS_error on failure
51 */
52int PINT_encode_initialize(void)
53{
54    int ret = -PVFS_EINVAL;
55
56    gossip_debug(GOSSIP_ENDECODE_DEBUG,"PINT_encode_initialize\n");
57    if (ENCODING_IS_SUPPORTED(ENCODING_LE_BFIELD))
58    {
59        /* setup little endian bytefield encoding */
60        PINT_encoding_table[ENCODING_LE_BFIELD] = &le_bytefield_table;
61        le_bytefield_table.init_fun();
62
63        /* header prepended to all messages of this type */
64        *((int32_t*)&(le_bytefield_table.generic_header[0])) =
65            htobmi32(PVFS2_PROTO_VERSION);
66        *((int32_t*)&(le_bytefield_table.generic_header[4])) =
67            htobmi32(ENCODING_LE_BFIELD);
68
69        le_bytefield_table.enc_type = ENCODING_LE_BFIELD;
70        ret = 0;
71    }
72    return ret;
73}
74
75/* PINT_encode_finalize()
76 *
77 * shuts down the protocol encoding interface
78 *
79 * no return value
80 */
81void PINT_encode_finalize(void)
82{
83    gossip_debug(GOSSIP_ENDECODE_DEBUG,"PINT_encode_finalize\n");
84    return;
85}
86
87
88/* PINT_encode()
89 *
90 * encodes a buffer (containing a PVFS2 request or response) to be
91 * sent over the network
92 *
93 * returns 0 on success, -PVFS_error on failure
94 */
95int PINT_encode(void* input_buffer,
96                enum PINT_encode_msg_type input_type,
97                struct PINT_encoded_msg* target_msg,
98                PVFS_BMI_addr_t target_addr,
99                enum PVFS_encoding_type enc_type)
100{
101    int ret = -PVFS_EINVAL;
102    target_msg->dest = target_addr;
103    target_msg->enc_type = enc_type;
104
105    gossip_debug(GOSSIP_ENDECODE_DEBUG,"PINT_encode\n");
106    switch(enc_type)
107    {
108        case ENCODING_LE_BFIELD:
109            if (input_type == PINT_ENCODE_REQ)
110            {
111                struct PVFS_server_req* tmp_req = input_buffer;
112                ENCODE_EVENT_START(PVFS_EVENT_API_ENCODE_REQ,
113                    tmp_req->op, tmp_req);
114                ret =  PINT_encoding_table[enc_type]->op->encode_req(
115                    input_buffer, target_msg);
116                ENCODE_EVENT_STOP(PVFS_EVENT_API_ENCODE_REQ,
117                    tmp_req->op, tmp_req, target_msg->total_size);
118            }
119            else if (input_type == PINT_ENCODE_RESP)
120            {
121                struct PVFS_server_resp* tmp_resp = input_buffer;
122                ENCODE_EVENT_START(PVFS_EVENT_API_ENCODE_RESP,
123                    tmp_resp->op, tmp_resp);
124                ret =  PINT_encoding_table[enc_type]->op->encode_resp(
125                    input_buffer, target_msg);
126                ENCODE_EVENT_STOP(PVFS_EVENT_API_ENCODE_RESP,
127                    tmp_resp->op, tmp_resp, target_msg->total_size);
128            }
129            break;
130        default:
131            gossip_lerr("Error: encoding type not supported.\n");
132            ret = -PVFS_EINVAL;
133            break;
134    }
135    return(ret);
136}
137
138/* PINT_decode()
139 *
140 * decodes a buffer (containing a PVFS2 request or response) that
141 * has been received from the network
142 *
143 * Parameters:
144 * input_buffer - encoded input
145 * input_type   - PINT_DECODE_REQ or PINT_DECODE_RESP
146 * target_msg   - pointer to struct PINT_decoded_msg, hold pointer to
147 *                allocated memory holding decoded message, etc.
148 * size         - size of encoded input
149 *
150 * Notes:
151 * - One must call PINT_decode_release(target_msg, input_type, 0)
152 *   in order for the memory allocated during the decode process to be
153 *   freed.
154 *
155 * returns 0 on success, -PVFS_error on failure
156 */
157int PINT_decode(void* input_buffer,
158                enum PINT_encode_msg_type input_type,
159                struct PINT_decoded_msg* target_msg,
160                PVFS_BMI_addr_t target_addr,
161                PVFS_size size)
162{
163    int i=0;
164    char* buffer_index = (char*)input_buffer + PINT_ENC_GENERIC_HEADER_SIZE;
165    int size_index = (int)size - PINT_ENC_GENERIC_HEADER_SIZE;
166    char* enc_type_ptr = (char*)input_buffer + 4;
167    int ret;
168    int32_t enc_type_recved, proto_ver_recved;
169    int proto_major_recved, proto_minor_recved;
170
171    gossip_debug(GOSSIP_ENDECODE_DEBUG,"PINT_decode\n");
172
173    /* sanity check size */
174    if(size < PINT_ENC_GENERIC_HEADER_SIZE)
175    {
176        gossip_err("Error: poorly formatted protocol message received.\n");
177        gossip_err("   Too small: message only %Ld bytes.\n",
178            Ld(size));
179        return(-PVFS_EPROTO);
180    }
181   
182    /* pull the encoding type and protocol version out */
183    proto_ver_recved = (int)bmitoh32(*((int32_t*)input_buffer));
184    enc_type_recved = bmitoh32(*((int32_t*)enc_type_ptr));
185    proto_major_recved = proto_ver_recved / 1000;
186    proto_minor_recved = proto_ver_recved - (proto_major_recved*1000);
187
188    /* check encoding type */
189    if(enc_type_recved != ENCODING_LE_BFIELD)
190    {
191        gossip_err("Error: poorly formatted protocol message received.\n");
192        gossip_err("   Encoding type mismatch: received type %d when "
193            "expecting %d.\n", (int)enc_type_recved,
194            ENCODING_LE_BFIELD);
195        return(-PVFS_EPROTONOSUPPORT);
196    }
197
198    /* check various protocol version possibilities */
199    if(proto_major_recved != PVFS2_PROTO_MAJOR)
200    {
201        gossip_err("Error: poorly formatted protocol message received.\n");
202        gossip_err("   Protocol version mismatch: received major version %d when "
203            "expecting %d.\n", (int)proto_major_recved,
204            PVFS2_PROTO_MAJOR);
205        gossip_err("   Please verify your PVFS2 installation and make sure "
206        "that the version is\n   consistent.\n");
207        return(-PVFS_EPROTONOSUPPORT);
208    }
209
210    if((input_type == PINT_DECODE_REQ) &&
211        (proto_minor_recved > PVFS2_PROTO_MINOR))
212    {
213        gossip_err("Error: poorly formatted protocol message received.\n");
214        gossip_err("   Protocol version mismatch: request has minor version %d when "
215            "expecting %d or lower.\n", (int)proto_minor_recved,
216            PVFS2_PROTO_MINOR);
217        gossip_err("   Client is too new for server.\n");
218        gossip_err("   Please verify your PVFS2 installation and make sure "
219        "that the version is\n   consistent.\n");
220        return(-PVFS_EPROTONOSUPPORT);
221    }
222
223    if((input_type == PINT_DECODE_RESP) &&
224        (proto_minor_recved < PVFS2_PROTO_MINOR))
225    {
226        gossip_err("Error: poorly formatted protocol message received.\n");
227        gossip_err("   Protocol version mismatch: request has minor version %d when "
228            "expecting %d or higher.\n", (int)proto_minor_recved,
229            PVFS2_PROTO_MINOR);
230        gossip_err("   Server is too old for client.\n");
231        gossip_err("   Please verify your PVFS2 installation and make sure "
232        "that the version is\n   consistent.\n");
233        return(-PVFS_EPROTONOSUPPORT);
234    }
235
236    for(i=0; i<ENCODING_TABLE_SIZE; i++)
237    {
238        if(PINT_encoding_table[i] && (PINT_encoding_table[i]->enc_type
239            == enc_type_recved))
240        {
241            struct PVFS_server_req* tmp_req;
242            struct PVFS_server_req* tmp_resp;
243            target_msg->enc_type = enc_type_recved;
244            if(input_type == PINT_DECODE_REQ)
245            {
246                ENCODE_EVENT_START(PVFS_EVENT_API_DECODE_REQ,
247                    0, input_buffer);
248                ret = PINT_encoding_table[i]->op->decode_req(buffer_index,
249                    size_index,
250                    target_msg,
251                    target_addr);
252                tmp_req = target_msg->buffer;
253                ENCODE_EVENT_STOP(PVFS_EVENT_API_DECODE_REQ,
254                    tmp_req->op, input_buffer, size);
255                return(ret);
256            }
257            else if(input_type == PINT_DECODE_RESP)
258            {
259                ENCODE_EVENT_START(PVFS_EVENT_API_DECODE_RESP,
260                    0, input_buffer);
261                ret = PINT_encoding_table[i]->op->decode_resp(buffer_index,
262                    size_index,
263                    target_msg,
264                    target_addr);
265                tmp_resp = target_msg->buffer;
266                ENCODE_EVENT_STOP(PVFS_EVENT_API_DECODE_RESP,
267                    tmp_resp->op, input_buffer, size);
268                return(ret);
269            }
270            else
271            {
272                return(-PVFS_EINVAL);
273            }
274        }
275    }
276
277    gossip_err("Error: poorly formatted protocol message received.\n");
278
279    return(-PVFS_EPROTONOSUPPORT);
280}
281       
282/* PINT_encode_release()
283 *
284 * frees all resources associated with a message that has been
285 * encoded
286 *
287 * no return value
288 */
289void PINT_encode_release(struct PINT_encoded_msg* input_buffer,
290                         enum PINT_encode_msg_type input_type)
291{
292    gossip_debug(GOSSIP_ENDECODE_DEBUG,"PINT_encode_release\n");
293    if (ENCODING_IS_SUPPORTED(input_buffer->enc_type))
294    {
295        PINT_encoding_table[input_buffer->enc_type]->op->encode_release(
296            input_buffer, input_type);
297    }
298    else
299    {
300        gossip_err("PINT_encode_release: Encoder type %d is not "
301                   "supported.\n", input_buffer->enc_type);
302    }
303}
304
305/* PINT_decode_release()
306 *
307 * frees all resources associated with a message that has been
308 * decoded
309 *
310 * no return value
311 */
312void PINT_decode_release(struct PINT_decoded_msg* input_buffer,
313                         enum PINT_encode_msg_type input_type)
314{
315    gossip_debug(GOSSIP_ENDECODE_DEBUG,"PINT_decode_release\n");
316    if (ENCODING_IS_SUPPORTED(input_buffer->enc_type))
317    {
318        PINT_encoding_table[input_buffer->enc_type]->op->decode_release(
319            input_buffer, input_type);
320    }
321    else
322    {
323        gossip_err("PINT_decode_release: Encoder type %d is not "
324                   "supported.\n", input_buffer->enc_type);
325    }
326}
327
328
329/* PINT_encode_calc_max_size()
330 *
331 * calculates maximum size of the encoded version of a protocol message.
332 *
333 * returns max size of encoded buffer on success, -PVFS_error on failure
334 */
335int PINT_encode_calc_max_size(
336    enum PINT_encode_msg_type input_type,
337    enum PVFS_server_op op_type,
338    enum PVFS_encoding_type enc_type)
339{   
340    int ret = -PVFS_EINVAL;
341
342    gossip_debug(GOSSIP_ENDECODE_DEBUG,"PINT_encode_calc_max_size\n");
343    switch(enc_type)
344    {
345        case ENCODING_LE_BFIELD:
346            ret = PINT_encoding_table[enc_type]->op->encode_calc_max_size
347                (input_type, op_type);
348            break;
349        default:
350            gossip_lerr("Error: encoding type not supported.\n");
351            break;
352    }
353
354    return(ret);
355}
356
357/*
358 * Local variables:
359 *  c-indent-level: 4
360 *  c-basic-offset: 4
361 * End:
362 *
363 * vim: ts=8 sts=4 sw=4 expandtab
364 */
Note: See TracBrowser for help on using the browser.