]> rtime.felk.cvut.cz Git - frescor/fna.git/blob - src_frescan/frescan_bwres_messages.c
b8f745554a5a47f5aac2f4418d942c86bb6005b6
[frescor/fna.git] / src_frescan / frescan_bwres_messages.c
1 /*!
2  * @file frescan_bwres_messages.c
3  *
4  * @brief FRESCAN bandwidth reservation layer: negotiation messages formating
5  *
6  * This module contains the data types that define the FRESCAN negotiation
7  * message format and operations to convert them into or from negotiation
8  * requests
9  *
10  * @version 0.01
11  *
12  * @date 2-Apr-2008
13  *
14  * @author Daniel Sangorrin <daniel.sangorrin@unican.es>
15  *
16  * @license
17  *
18  * -----------------------------------------------------------------------
19  *  Copyright (C) 2006 - 2008 FRESCOR consortium partners:
20  *
21  *    Universidad de Cantabria,              SPAIN
22  *    University of York,                    UK
23  *    Scuola Superiore Sant'Anna,            ITALY
24  *    Kaiserslautern University,             GERMANY
25  *    Univ. Politécnica  Valencia,           SPAIN
26  *    Czech Technical University in Prague,  CZECH REPUBLIC
27  *    ENEA                                   SWEDEN
28  *    Thales Communication S.A.              FRANCE
29  *    Visual Tools S.A.                      SPAIN
30  *    Rapita Systems Ltd                     UK
31  *    Evidence                               ITALY
32  *
33  *    See http://www.frescor.org for a link to partners' websites
34  *
35  *           FRESCOR project (FP6/2005/IST/5-034026) is funded
36  *        in part by the European Union Sixth Framework Programme
37  *        The European Union is not liable of any use that may be
38  *        made of this code.
39  *
40  *  This file is part of FRESCAN
41  *
42  *  FRESCAN is free software; you can  redistribute it and/or  modify
43  *  it under the terms of  the GNU General Public License as published by
44  *  the Free Software Foundation;  either  version 2, or (at  your option)
45  *  any later version.
46  *
47  *  FRESCAN  is distributed  in  the hope  that  it  will  be useful,  but
48  *  WITHOUT  ANY  WARRANTY;     without  even the   implied   warranty  of
49  *  MERCHANTABILITY  or  FITNESS FOR  A  PARTICULAR PURPOSE. See  the  GNU
50  *  General Public License for more details.
51  *
52  *  You should have  received a  copy of  the  GNU  General Public License
53  *  distributed  with  FRESCAN;  see file COPYING.   If not,  write to the
54  *  Free Software  Foundation,  59 Temple Place  -  Suite 330,  Boston, MA
55  *  02111-1307, USA.
56  *
57  * As a special exception, including FRESCAN header files in a file,
58  * instantiating FRESCAN generics or templates, or linking other files
59  * with FRESCAN objects to produce an executable application, does not
60  * by itself cause the resulting executable application to be covered
61  * by the GNU General Public License. This exception does not
62  * however invalidate any other reasons why the executable file might be
63  * covered by the GNU Public License.
64  * -----------------------------------------------------------------------
65  *
66  */
67
68 #include <string.h>
69 #include "frescan_bwres_messages.h"
70 #include "frescan_bwres_requests.h"
71 #include "frescan.h"
72 #include "frescan_config.h"
73 #include "frescan_debug.h"
74
75 #define FRESCAN_BWRES_MX_MSG_SIZE 3000  // TODO: adjust to the minimum
76
77 /**
78  * frescan_messages_init()
79  */
80
81 static frescan_send_params_t send_params[FRESCAN_MX_NETWORKS];
82 static frescan_recv_params_t recv_params[FRESCAN_MX_NETWORKS];
83
84 int frescan_messages_init(frescan_network_t net)
85 {
86         DEBUG(FRESCAN_MESSAGES_ENABLE_DEBUG, "initialization\n");
87
88         send_params[net].net     = net;
89         send_params[net].channel = FRESCAN_NEG_CHANNEL;
90         send_params[net].flags   = FRESCAN_SS | FRESCAN_ASYNC;
91         send_params[net].ss      = the_networks[net].neg_messages_ss_id;
92         send_params[net].to      = FRESCAN_NEG_MASTER_NODE;
93
94         recv_params[net].net     = net;
95         recv_params[net].channel = FRESCAN_NEG_CHANNEL;
96         recv_params[net].flags   = FRESCAN_SYNC;
97
98         return 0;
99 }
100
101 /**
102  *
103  *  FRESCAN_REQ_NEG MESSAGE
104  *  =======================
105  *  This message is sent from a SLAVE to the MASTER when the slave wants
106  *  to negotiate a new contract. It contains the type (a negotiation 'NEG'
107  *  request), the LOCAL request id (so the MASTER can use it in the reply
108  *  to identify to which request is replying), a preallocated sporadic
109  *  server id (the MASTER will store it in its table together with the
110  *  node so we can perform renegotiations and spare capacity distribution
111  *  in the future) and the contract.
112  *
113  *      1     2     2      N
114  *  +-----------------------------+
115  *  | 'NEG' | REQ | SS | CONTRACT |
116  *  +-----------------------------+
117  *
118  */
119
120 struct frescan_req_neg_message_t {
121         frescan_request_type_t   type;
122         frescan_request_id_t     req;
123         frescan_ss_t             ss;
124 }  __attribute__ ((packed));
125
126 static int frescan_request_to_neg_message(const frescan_request_data_t *data,
127                                           uint8_t *msg)
128 {
129         int ret;
130         struct frescan_req_neg_message_t *neg_msg;
131         size_t req_size, contract_size;
132
133         neg_msg = (struct frescan_req_neg_message_t *)msg;
134         req_size = sizeof(struct frescan_req_neg_message_t);
135
136         neg_msg->type     = FRESCAN_REQ_NEG;
137         neg_msg->req      = data->req;
138         neg_msg->ss       = data->ss;
139
140         ret = frsh_contract_marshal(data->contract,
141                                     msg + req_size,
142                                     FRESCAN_BWRES_MX_MSG_SIZE - req_size,
143                                     &contract_size);
144         if (ret != 0) {
145                 FRESCAN_ERROR("frsh_contract_marshal return -1\n");
146                 return -1;
147         }
148
149         DEBUG(FRESCAN_MESSAGES_ENABLE_DEBUG, "type:%d req:%d ss:%d csize:%u\n",
150               neg_msg->type, neg_msg->req, neg_msg->ss, contract_size);
151
152         return req_size + contract_size;
153 }
154
155 static int frescan_neg_message_to_request(const uint8_t *msg,
156                                           frescan_request_data_t *data,
157                                           size_t size)
158 {
159         int ret;
160         struct frescan_req_neg_message_t *neg_msg;
161         size_t req_size;
162
163         neg_msg = (struct frescan_req_neg_message_t *)msg;
164         req_size = sizeof(struct frescan_req_neg_message_t);
165
166         data->type        = FRESCAN_REQ_NEG;
167         data->req         = neg_msg->req;
168         data->ss          = neg_msg->ss;
169
170         ret = frsh_contract_unmarshal(data->contract,
171                                       msg  + req_size,  // pointer to contract
172                                       size - req_size); // size marshal '   '
173         if (ret != 0) {
174                 FRESCAN_ERROR("frsh_contract_unmarshal return -1\n");
175                 return -1;
176         }
177
178         DEBUG(FRESCAN_MESSAGES_ENABLE_DEBUG, "type:%d req:%d ss:%d\n",
179               data->type, data->req, data->ss);
180
181         return 0;
182 }
183
184 /**
185  *
186  *  FRESCAN_REQ_RENEG MESSAGE
187  *  =========================
188  *  This message is sent from a SLAVE to the MASTER when the slave wants
189  *  to renegotiate a contract. It contains the type (a renegotiation 'RENEG'
190  *  request), the LOCAL request id (so the MASTER can use it in the reply
191  *  to identify to which request is replying), the sporadic server id
192  *  (the MASTER will look up its table together with the node to find the
193  *  appropiate entry) and the contract.
194  *
195  *      1       2     2      N
196  *  +-------------------------------+
197  *  | 'RENEG' | REQ | SS | CONTRACT |
198  *  +-------------------------------+
199  *
200  */
201
202 struct frescan_req_reneg_message_t {
203         frescan_request_type_t   type;
204         frescan_request_id_t     req;
205         frescan_ss_t             ss;
206 }  __attribute__ ((packed));
207
208 static int frescan_request_to_reneg_message(const frescan_request_data_t *data,
209                                             uint8_t *msg)
210 {
211         int ret;
212         size_t req_size, contract_size;
213         struct frescan_req_reneg_message_t *reneg_msg;
214
215         reneg_msg = (struct frescan_req_reneg_message_t *)msg;
216         req_size = sizeof(struct frescan_req_reneg_message_t);
217
218         reneg_msg->type     = FRESCAN_REQ_RENEG;
219         reneg_msg->req      = data->req;
220         reneg_msg->ss       = data->ss;
221
222         ret = frsh_contract_marshal(data->contract,
223                                     msg + req_size,
224                                     FRESCAN_BWRES_MX_MSG_SIZE - req_size,
225                                     &contract_size);
226         if (ret != 0) {
227                 FRESCAN_ERROR("frsh_contract_marshal return -1\n");
228                 return -1;
229         }
230
231         DEBUG(FRESCAN_MESSAGES_ENABLE_DEBUG, "type:%d req:%d ss:%d csize:%u\n",
232               reneg_msg->type, reneg_msg->req, reneg_msg->ss, contract_size);
233
234         return req_size + contract_size;
235 }
236
237 static int frescan_reneg_message_to_request(const uint8_t *msg,
238                                             frescan_request_data_t *data,
239                                             size_t size)
240 {
241         int ret;
242         struct frescan_req_reneg_message_t *reneg_msg;
243         size_t req_size;
244
245         reneg_msg = (struct frescan_req_reneg_message_t *)msg;
246         req_size = sizeof(struct frescan_req_neg_message_t);
247
248         data->type        = FRESCAN_REQ_RENEG;
249         data->req         = reneg_msg->req;
250         data->ss          = reneg_msg->ss;
251
252         ret = frsh_contract_unmarshal(data->contract,
253                                       msg  + req_size,
254                                       size - req_size);
255         if (ret != 0) {
256                 FRESCAN_ERROR("frsh_contract_unmarshal return -1\n");
257                 return -1;
258         }
259
260         DEBUG(FRESCAN_MESSAGES_ENABLE_DEBUG, "type:%d req:%d ss:%d\n",
261               data->type, data->req, data->ss);
262
263         return 0;
264 }
265
266 /**
267  *  FRESCAN_REQ_CANCEL MESSAGE
268  *  ==========================
269  *  This message is sent from a SLAVE to the MASTER to cancel a contract.
270  *  It contains the type, 'CANCEL' and the sporadic server id (the MASTER will
271  *  have to look it up in the table). The MASTER doesnt need to reply this
272  *  message.
273  *
274  *  +---------------+
275  *  | 'CANCEL' | SS |
276  *  +---------------+
277  *
278  */
279
280 struct frescan_req_cancel_message_t {
281         frescan_request_type_t   type;
282         frescan_ss_t             ss;
283 }  __attribute__ ((packed));
284
285 static int frescan_request_to_cancel_message(const frescan_request_data_t *data,
286                                              uint8_t *msg)
287 {
288         struct frescan_req_cancel_message_t *cancel_msg;
289
290         cancel_msg = (struct frescan_req_cancel_message_t *)msg;
291
292         cancel_msg->type     = FRESCAN_REQ_CANCEL;
293         cancel_msg->ss       = data->ss;
294
295         DEBUG(FRESCAN_MESSAGES_ENABLE_DEBUG, "type:%d ss:%d\n",
296               cancel_msg->type, cancel_msg->ss);
297
298         return sizeof(struct frescan_req_cancel_message_t);
299 }
300
301 static int frescan_cancel_message_to_request(const uint8_t *msg,
302                                              frescan_request_data_t *data)
303 {
304         struct frescan_req_cancel_message_t *cancel_msg;
305
306         cancel_msg = (struct frescan_req_cancel_message_t *)msg;
307
308         data->type        = FRESCAN_REQ_CANCEL;
309         data->ss          = cancel_msg->ss;
310
311         DEBUG(FRESCAN_MESSAGES_ENABLE_DEBUG, "type:%d ss:%d\n",
312               data->type, data->ss);
313
314         return 0;
315 }
316
317 /**
318  *
319  *  FRESCAN_REP_INC_BUDGET / FRESCAN_REP_DEC_BUDGET
320  *  ===============================================
321  *  This message is sent from the MASTER to a slave when there is a change
322  *  in the budget value assigned by the spare capacity algorithm.
323  *
324  *  +---------------------------------------------------+
325  *  | 'INC/DEC' | SS | NEW_B | SS | NEW_B |  SS | NEW_B |
326  *  +---------------------------------------------------+
327  *
328  */
329
330 static int frescan_request_to_repchange_message
331                 (const frescan_request_data_t *data, uint8_t *msg)
332 {
333         int bytes_written;
334         struct list_head *the_mode_change_list;
335         frescan_sa_vres_t *vres;
336         uint8_t *msg_begin;
337
338         if (data->type == FRESCAN_REP_INC_BUDGET) {
339                 the_mode_change_list = &the_networks[data->net].
340                                         mode_change_budget_inc_list_head
341                                                         [data->request_node];
342         } else {
343                 the_mode_change_list = &the_networks[data->net].
344                                 mode_change_budget_dec_list_head
345                                                         [data->request_node];
346         }
347
348         if (list_empty(the_mode_change_list)) {
349                 return 0; // nothing to send
350         }
351
352         msg_begin = msg;
353
354         *((frescan_request_type_t *)msg) = data->type;
355         bytes_written = sizeof(frescan_request_type_t);
356         msg = msg + bytes_written;
357
358         list_for_each_entry(vres,
359                             the_mode_change_list,
360                             mode_change_list)
361         {
362                 *((frescan_ss_t *)msg) = vres->ss;
363                 bytes_written = sizeof(frescan_ss_t);
364                 msg = msg + bytes_written;
365
366                 *((frsh_sa_time_t *)msg) = vres->old_c;
367                 bytes_written = sizeof(frsh_sa_time_t);
368                 msg = msg + bytes_written;
369         }
370
371         return (msg - msg_begin);
372 }
373
374 static int frescan_repchange_message_to_request(const uint8_t *msg,
375                                                 frescan_request_data_t *data,
376                                                 size_t size)
377 {
378         struct list_head *the_mode_change_list;
379         frescan_node_t me = the_networks[data->net].local_node;
380         frescan_sa_vres_t *vres;
381         int bytes_read;
382         uint8_t *msg_pointer;
383         frescan_ss_t ss;
384
385         data->type = *((frescan_request_type_t *)msg);
386
387         if (data->type == FRESCAN_REP_INC_BUDGET) {
388                 the_mode_change_list = &the_networks[data->net].
389                                         mode_change_budget_inc_list_head[me];
390         } else {
391                 the_mode_change_list = &the_networks[data->net].
392                                         mode_change_budget_dec_list_head[me];
393         }
394
395         INIT_LIST_HEAD(the_mode_change_list);
396
397         msg_pointer = (uint8_t *)msg;
398
399         while(msg_pointer < msg + size) {
400                 ss = *((frescan_ss_t *)msg_pointer);
401                 bytes_read = sizeof(frescan_ss_t);
402                 msg_pointer = msg_pointer + bytes_read;
403
404                 vres = &the_networks[data->net].scenario.vres_pool[me][ss];
405
406                 vres->old_c = *((frsh_sa_time_t *)msg_pointer);
407                 bytes_read = sizeof(frsh_sa_time_t);
408                 msg_pointer = msg_pointer + bytes_read;
409         }
410
411         return 0;
412 }
413
414 /**
415  *
416  *  FRESCAN_REP_NEG MESSAGE
417  *  =======================
418  *  This message is sent from the MASTER to a slave as a reply to a
419  *  FRESCAN_REQ_NEG or a FRESCAN_REQ_RENEG, to say if they were admited.
420  *  It contains the type 'REPNEG', the request ID of the slave, a
421  *  return value to say if the contract is admited or not, and the final
422  *  values if it was admited
423  *
424  *  +-------------------------------------------+
425  *  | 'REPNEG' | REQ | RET_VALUE | FINAL_VALUES | + FRESCAN_REP_INC/DEC_BUDGET
426  *  +-------------------------------------------+
427  *
428  */
429
430 struct frescan_rep_neg_message_t {
431         frescan_request_type_t    type;
432         frescan_request_id_t      req;
433         frescan_request_retval_t  return_value;
434         frescan_server_params_t   final_values;
435 }  __attribute__ ((packed));
436
437 static int frescan_request_to_repneg_message(const frescan_request_data_t *data,
438                                              uint8_t *msg)
439 {
440         struct frescan_rep_neg_message_t *repneg_msg;
441
442         repneg_msg = (struct frescan_rep_neg_message_t *)msg;
443
444         repneg_msg->type         = FRESCAN_REP_NEG;
445         repneg_msg->req          = data->req;
446         repneg_msg->return_value = data->return_value;
447         repneg_msg->final_values = data->final_values;
448
449         if (data->return_value == FRESCAN_REQ_ACCEPTED) {
450         }
451
452
453         DEBUG(FRESCAN_MESSAGES_ENABLE_DEBUG, "type:%d req:%d ret:%d\n",
454               repneg_msg->type, repneg_msg->req, repneg_msg->return_value);
455
456         return sizeof(struct frescan_rep_neg_message_t);
457 }
458
459 static int frescan_repneg_message_to_request(const uint8_t *msg,
460                                              frescan_request_data_t *data)
461 {
462         struct frescan_rep_neg_message_t *repneg_msg;
463
464         repneg_msg = (struct frescan_rep_neg_message_t *)msg;
465
466         data->type         = FRESCAN_REP_NEG;
467         data->req          = repneg_msg->req;
468         data->return_value = repneg_msg->return_value;
469         // TODO: use final values only if it was accepted!
470         data->final_values = repneg_msg->final_values;
471
472         DEBUG(FRESCAN_MESSAGES_ENABLE_DEBUG, "type:%d req:%d ret:%d\n",
473               data->type, data->req, data->return_value);
474
475         return 0;
476 }
477
478 /**
479  * frescan_messages_send_request()
480  *
481  * this function converts a request with the necessary data into a message
482  * and sends it.
483  *
484  * @req_data: the request to be sent (NOTE: the network is in req_data)
485  *
486  */
487
488 int frescan_messages_send_request(const frescan_request_data_t *req_data)
489 {
490         int ret;
491         uint8_t msg[FRESCAN_BWRES_MX_MSG_SIZE];
492         size_t size;
493
494         switch(req_data->type) {
495                 case FRESCAN_REQ_NEG:
496                         size = frescan_request_to_neg_message(req_data, msg);
497                         send_params[req_data->net].to = FRESCAN_NEG_MASTER_NODE;
498                         break;
499                 case FRESCAN_REQ_RENEG:
500                         size = frescan_request_to_reneg_message(req_data, msg);
501                         send_params[req_data->net].to = FRESCAN_NEG_MASTER_NODE;
502                         break;
503                 case FRESCAN_REQ_CANCEL:
504                         size = frescan_request_to_cancel_message(req_data, msg);
505                         send_params[req_data->net].to = FRESCAN_NEG_MASTER_NODE;
506                         break;
507                 case FRESCAN_REP_DEC_BUDGET:
508                 case FRESCAN_REP_INC_BUDGET:
509                         size = frescan_request_to_repchange_message
510                                         (req_data, msg);
511                         send_params[req_data->net].to = req_data->request_node;
512                         break;
513                 case FRESCAN_REP_NEG:
514                         size = frescan_request_to_repneg_message(req_data, msg);
515                         send_params[req_data->net].to = req_data->request_node;
516                         break;
517                 default:
518                         FRESCAN_ERROR("request type not supported\n");
519                         return -1;
520         }
521
522         ret = frescan_send(&send_params[req_data->net], msg, size);
523         if (ret != 0) return ret;
524
525         DEBUG(FRESCAN_MESSAGES_ENABLE_DEBUG, "sent request, type:%X size:%d\n",
526               *(frescan_request_type_t *)msg, size);
527
528         return 0;
529 }
530
531 /**
532  * frescan_messages_recv_request()
533  *
534  * this function BLOCKS the calling thread until receives a message
535  * and transforms it into a request.
536  *
537  * @req_data: the request data to fill from the message bytes (out)
538  *
539  */
540
541 int frescan_messages_recv_request(frescan_network_t    net,
542                                   frescan_request_id_t *req)
543 {
544         int ret;
545         uint8_t msg[FRESCAN_BWRES_MX_MSG_SIZE];
546         size_t recv_bytes;
547         frescan_node_t from;
548         frescan_prio_t prio;
549         frescan_request_data_t *req_data;
550
551         ret = frescan_requests_alloc(req);
552         if (ret != 0) return ret;
553
554         ret = frescan_requests_get_data(*req, &req_data);
555         if (ret != 0) return ret;
556
557         ret = frescan_recv(&recv_params[net],
558                             msg,
559                             sizeof(msg),
560                             &recv_bytes,
561                             &from,
562                             &prio);
563         if (ret != 0) return ret;
564
565         DEBUG(FRESCAN_MESSAGES_ENABLE_DEBUG,
566               "msg received! from:%u size:%u prio:%u chan:%u flags:%X\n",
567               from, recv_bytes, prio, recv_params[net].channel,
568               recv_params[net].flags);
569
570         req_data->request_node = from;
571         req_data->net = net;
572
573         switch(*((frescan_request_type_t *)msg)) {
574                 case FRESCAN_REQ_NEG:
575                         return frescan_neg_message_to_request(msg,
576                                                               req_data,
577                                                               recv_bytes);
578                 case FRESCAN_REQ_RENEG:
579                         return frescan_reneg_message_to_request(msg,
580                                                                 req_data,
581                                                                 recv_bytes);
582                 case FRESCAN_REQ_CANCEL:
583                         return frescan_cancel_message_to_request(msg, req_data);
584                 case FRESCAN_REP_DEC_BUDGET:
585                 case FRESCAN_REP_INC_BUDGET:
586                         return frescan_repchange_message_to_request(msg,
587                                                                     req_data,
588                                                                     recv_bytes);
589                 case FRESCAN_REP_NEG:
590                         return frescan_repneg_message_to_request(msg, req_data);
591                 default:
592                         FRESCAN_ERROR("request type %X not supported\n",
593                               *(frescan_request_type_t *)msg);
594                         return -1;
595         }
596 }