sync/gen_message_func.ysl2
author Volker Birk <vb@pep-project.org>
Wed, 29 May 2019 23:17:19 +0200
branchsync
changeset 3779 c6898c703a27
parent 3775 e690ea388036
child 3780 e4d673d3038e
permissions -rw-r--r--
update logic
     1 // This file is under GNU General Public License 3.0
     2 // see LICENSE.txt
     3 
     4 // generate message functions
     5 
     6 // Copyleft (c) 2017-2019, p≡p foundation
     7 
     8 // Written by Volker Birk
     9 
    10 include yslt.yml2
    11 
    12 tstylesheet {
    13 
    14 include standardlib.ysl2
    15 include ./functions.ysl2
    16 
    17 template "/" {
    18     apply "protocol", 0, mode=header;
    19     apply "protocol", 0, mode=impl;
    20 }
    21 
    22 template "protocol", mode=header
    23     document "generated/{@name}_func.h", "text"
    24 ||
    25 // This file is under GNU General Public License 3.0
    26 // see LICENSE.txt
    27 
    28 #pragma once
    29 
    30 #ifdef __cplusplus
    31 extern "C" {
    32 #endif
    33 
    34 #include <stdbool.h>
    35 
    36 #include "../asn.1/«@name».h"
    37 `` for "func:distinctType(fsm/message/field[not(func:basicType())])" | #include "../asn.1/«@type».h"
    38 
    39 // state
    40 
    41 struct «@name»_state_s {
    42     // own state
    43 
    44     struct own_«@name»_state_s {
    45         stringlist_t *keys;
    46         identity_list *identities;
    47 
    48         // TIDs we're using ourselves
    49         `` for "func:distinctName(fsm/message/field[@type='TID'])" |>> «func:ctype()» «@name»;
    50     } own;
    51 
    52     // state we learned about our communication partner
    53 
    54     struct comm_partner_state_s {
    55         // transport data we expect
    56         char *sender_fpr;
    57 
    58         // TIDs our comm partner wants to have
    59         `` for "func:distinctName(fsm/message/field[@type='TID'])" |>> «func:ctype()» «@name»;
    60     } comm_partner;
    61 
    62     // input buffer for actual transport data coming in
    63 
    64     struct transport_data_s {
    65         // transport data we got
    66         pEp_identity *from;
    67         char *sender_fpr;
    68     } transport;
    69     `` apply "fsm", mode=state
    70 };
    71 
    72 void free_«@name»_state(PEP_SESSION session);
    73 
    74 // functions for protocol «@name»
    75 
    76 «@name»_t *new_«@name»_message(«@name»_PR fsm, int message_type);
    77 void free_«@name»_message(«@name»_t *msg);
    78 
    79 PEP_STATUS update_«@name»_state(PEP_SESSION session, «@name»_t *msg,
    80         «@name»_PR *fsm, int *message_type);
    81 
    82 PEP_STATUS update_«@name»_message(PEP_SESSION session, «@name»_t *msg);
    83 
    84 #ifdef __cplusplus
    85 }
    86 #endif
    87 
    88 ||
    89 
    90 template "fsm", mode=state
    91 ||
    92 
    93 // input/output buffer for «@name» messages
    94 
    95 struct _«@name»_state_s {
    96     int state;
    97 
    98     `` for "func:distinctName(message/field)" |> «func:ctype()» «@name»;
    99 } «yml:lcase(@name)»;
   100 ||
   101 
   102 template "protocol", mode=impl
   103     document "generated/{@name}_func.c", "text" {
   104 ||
   105 // This file is under GNU General Public License 3.0
   106 // see LICENSE.txt
   107 
   108 #include <assert.h>
   109 #include <stdlib.h>
   110 #include "pEp_internal.h"
   111 #include "map_asn1.h"
   112 #include "«@name»_func.h"
   113 `` for "fsm" | #include "«@name»_fsm.h"
   114 
   115 void free_«@name»_state(PEP_SESSION session)
   116 {
   117     if (!session)
   118         return;
   119 
   120     // own state
   121 
   122     free_stringlist(session->«yml:lcase(@name)»_state.own.keys);
   123     session->«yml:lcase(@name)»_state.own.keys = NULL;
   124     free_identity_list(session->«yml:lcase(@name)»_state.own.identities);
   125     session->«yml:lcase(@name)»_state.own.identities = NULL;
   126 
   127     // TIDs we're using ourselves
   128 ||
   129     for "func:distinctName(fsm/message/field[@type='TID'])"
   130         |> ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_«@type», &session->«yml:lcase(../../../@name)»_state.own.«@name»);
   131 ||
   132 
   133     // state we learned about our communication partner
   134 
   135     free(session->«yml:lcase(@name)»_state.comm_partner.sender_fpr);
   136     session->«yml:lcase(@name)»_state.comm_partner.sender_fpr = NULL;
   137 
   138     // TIDs our comm partner wants to have
   139 ||
   140     for "func:distinctName(fsm/message/field[@type='TID'])"
   141         |> ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_«@type», &session->«yml:lcase(../../../@name)»_state.comm_partner.«@name»);
   142 ||
   143 
   144     // buffer for transport data
   145 
   146     free_identity(session->«yml:lcase(@name)»_state.transport.from);
   147     session->«yml:lcase(@name)»_state.transport.from = NULL;
   148     free(session->«yml:lcase(@name)»_state.transport.sender_fpr);
   149     session->«yml:lcase(@name)»_state.transport.sender_fpr = NULL;
   150 
   151     // message buffers
   152 
   153 ||
   154     for "fsm" {
   155         for "func:distinctName(message/field[not(substring(@type,1,1)=yml:lcase(substring(@type,1,1)))])"
   156             |> ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_«@type», &session->«yml:lcase(../../../@name)»_state.«yml:lcase(../../@name)».«@name»);
   157         |
   158     }
   159 ||
   160     memset(&session->«yml:lcase(@name)»_state, 0, sizeof(session->«yml:lcase(@name)»_state));
   161 }
   162 
   163 «@name»_t *new_«@name»_message(«@name»_PR fsm, int message_type)
   164 {
   165     «@name»_t *msg = calloc(sizeof(«@name»_t), 1);
   166     assert(msg);
   167     if (!msg)
   168         return NULL;
   169 
   170     if (fsm) {
   171         msg->present = fsm;
   172         if (message_type) {
   173             switch (fsm) {
   174                 `` apply "fsm", 4, mode=impl
   175                 default:
   176                     free(msg);
   177                     return NULL;
   178             }
   179         }
   180     }
   181 
   182     return msg;
   183 }
   184 
   185 void free_«@name»_message(«@name»_t *msg)
   186 {
   187     ASN_STRUCT_FREE(asn_DEF_«@name», msg);
   188 }
   189 
   190 PEP_STATUS update_«@name»_state(PEP_SESSION session, «@name»_t *msg,
   191         «@name»_PR *fsm, int *message_type)
   192 {
   193     int result = 0;
   194 
   195     assert(session && msg && fsm && message_type);
   196     if (!(session && msg && fsm && message_type))
   197         return PEP_ILLEGAL_VALUE;
   198 
   199     *fsm = 0;
   200     *message_type = None;
   201 
   202     switch (msg->present) {
   203         case «@name»_PR_NOTHING:
   204             return PEP_ILLEGAL_VALUE;
   205 
   206         `` apply "fsm", 2, mode=update_state
   207         default:
   208             return PEP_ILLEGAL_VALUE;
   209     }
   210 
   211     *fsm = msg->present;
   212     return PEP_STATUS_OK;
   213 }
   214 
   215 PEP_STATUS update_«@name»_message(PEP_SESSION session, «@name»_t *msg)
   216 {
   217     assert(session && msg);
   218     if (!(session && msg))
   219         return PEP_ILLEGAL_VALUE;
   220 
   221     int fsm = msg->present;
   222     switch (fsm) {
   223         case «@name»_PR_NOTHING:
   224             return PEP_ILLEGAL_VALUE;
   225 
   226         `` apply "fsm", 2, mode=update_message
   227         default:
   228             return PEP_ILLEGAL_VALUE;
   229     }
   230 
   231     return PEP_STATUS_OK;
   232 }
   233 
   234 ||
   235 }
   236 
   237 template "fsm", mode=update_message
   238 ||
   239 case «../@name»_PR_«yml:lcase(@name)»:
   240     {
   241         int message_type = msg->choice.«yml:lcase(@name)».present;
   242         switch (message_type) {
   243             case «@name»_PR_NOTHING:
   244                 return PEP_ILLEGAL_VALUE;
   245 
   246             `` apply "message", 2, mode=update_message
   247             default:
   248                 return PEP_ILLEGAL_VALUE;
   249         }
   250         break;
   251     }
   252 ||
   253 
   254 template "message", mode=update_message {
   255     ||
   256     case «../@name»_PR_«yml:mixedCase(@name)»:
   257         `` apply "auto"
   258         `` apply "field", mode=update_message
   259         break;
   260 
   261     ||
   262 }
   263 
   264 template "auto" choose {
   265     when "@type = 'Version'" {
   266         const "fsm", "ancestor::fsm";
   267         ||
   268         {
   269             long *major = (long *) malloc(sizeof(long));
   270             long *minor = (long *) malloc(sizeof(long));
   271             assert(major && minor);
   272             if (!(major && minor))
   273                 return PEP_OUT_OF_MEMORY;
   274 
   275             *major = «$fsm/version/@major»;
   276             *minor = «$fsm/version/@minor»;
   277 
   278             msg->choice.«yml:lcase($fsm/@name)».choice.«yml:mixedCase(../@name)».«@name».major = major;
   279             msg->choice.«yml:lcase($fsm/@name)».choice.«yml:mixedCase(../@name)».«@name».minor = minor;
   280         }
   281 
   282         ||
   283     }
   284 
   285     otherwise
   286         error "unkown type for auto in message: {@type}; allowed types: Version";
   287 }
   288 
   289 template "field", mode=update_message {
   290     const "message_name", "yml:mixedCase(../@name)";
   291     const "state" choose {
   292         when "@type='TID'"
   293             > «yml:lcase(ancestor::protocol/@name)»_state.own
   294         otherwise
   295             > «yml:lcase(ancestor::protocol/@name)»_state.«yml:lcase(ancestor::fsm/@name)»
   296     }
   297 
   298     choose {
   299         when "func:basicType()" // copyable
   300         ||
   301         msg->choice.«yml:lcase(../../@name)».choice.«$message_name».«@name»
   302                  = session->«$state».«@name»;
   303 
   304         ||
   305         when "@type='IdentityList'"
   306         ||
   307         {
   308             identity_list *il = IdentityList_to_identity_list(
   309                     &session->«$state».«@name», NULL);
   310             if (!il)
   311                 return PEP_OUT_OF_MEMORY;
   312             IdentityList_t *_il = IdentityList_from_identity_list(il,
   313                     &msg->choice.«yml:lcase(../../@name)».choice.«$message_name».«@name»);
   314             free_identity_list(il);
   315             if (!_il)
   316                 return PEP_OUT_OF_MEMORY;
   317         }
   318 
   319         ||
   320         otherwise // string based
   321         ||
   322         {
   323             int result = OCTET_STRING_fromBuf(
   324                     &msg->choice.«yml:lcase(../../@name)».choice.«$message_name».«@name»,
   325                     (char *) session->«$state».«@name».buf,
   326                     session->«$state».«@name».size
   327                 );
   328             if (result)
   329                 return PEP_OUT_OF_MEMORY;
   330         }
   331         ||
   332     }
   333 }
   334 
   335 template "fsm", mode=update_state
   336 ||
   337 case «../@name»_PR_«yml:lcase(@name)»:
   338     switch (msg->choice.«yml:lcase(@name)».present) {
   339         case «@name»_PR_NOTHING:
   340             return PEP_ILLEGAL_VALUE;
   341 
   342         `` apply "message", 2, mode=update_state
   343         default:
   344             return PEP_ILLEGAL_VALUE;
   345     }
   346     break;
   347 
   348 ||
   349 
   350 template "message", mode=update_state {
   351     const "message_name", "concat(yml:lcase(substring(@name,1,1)), substring(@name,2))";
   352     ||
   353     case «../@name»_PR_«$message_name»:
   354         `` apply "field", mode=update_state with "message_name", "$message_name"
   355         *message_type = «yml:capit($message_name)»;
   356         break;
   357 
   358     ||
   359 }
   360 
   361 template "field", mode=update_state {
   362     param "message_name";
   363     choose {
   364         when "func:basicType()" // copyable
   365         ||
   366         session->«yml:lcase(../../../@name)»_state.«yml:lcase(../../@name)».«@name» = msg->choice.«yml:lcase(../../@name)»
   367                 .choice.«$message_name».«@name»;
   368 
   369         ||
   370         when "@type='IdentityList'"
   371         ||
   372         {
   373             identity_list *il = IdentityList_to_identity_list(
   374                     &msg->choice.«yml:lcase(../../@name)».choice.«$message_name».«@name», NULL);
   375             if (!il)
   376                 return PEP_OUT_OF_MEMORY;
   377             IdentityList_t *_il = IdentityList_from_identity_list(il,
   378                     &session->«yml:lcase(../../../@name)»_state.«yml:lcase(../../@name)».«@name»);
   379             free_identity_list(il);
   380             if (!_il)
   381                 return PEP_OUT_OF_MEMORY;
   382         }
   383 
   384         ||
   385         otherwise // string based
   386         ||
   387         result = OCTET_STRING_fromBuf(&session->«yml:lcase(../../../@name)»_state.«yml:lcase(../../@name)».«@name»,
   388                 (char *) msg->choice.«yml:lcase(../../@name)».choice.«$message_name».«@name».buf,
   389                 msg->choice.«yml:lcase(../../@name)».choice.«$message_name».«@name».size);
   390         if (result)
   391             return PEP_OUT_OF_MEMORY;
   392 
   393         ||
   394     }
   395 }
   396 
   397 template "fsm", mode=impl
   398 ||
   399 case «../@name»_PR_«yml:lcase(@name)»:
   400     msg->choice.«yml:lcase(@name)».present = message_type;
   401         break;
   402 
   403 ||
   404 
   405 }
   406