Navigation


source: freeDiameter/libfdcore/fdd.y @ 706:4ffbc9f1e922

Last change on this file since 706:4ffbc9f1e922 was 706:4ffbc9f1e922, checked in by Sebastien Decugis <sdecugis@nict.go.jp>, 11 years ago

Large UNTESTED commit with the following changes:

  • Improved DiameterIdentity? handling (esp. interationalization issues), and improve efficiency of some string operations in peers, sessions, and dictionary modules (closes #7)
  • Cleanup in the session module to free only unreferenced sessions (#16)
  • Removed fd_cpu_flush_cache(), replaced by more robust alternatives.
  • Improved peer state machine algorithm to counter SCTP multistream race condition.
File size: 16.4 KB
Line 
1/*********************************************************************************************************
2* Software License Agreement (BSD License)                                                               *
3* Author: Sebastien Decugis <sdecugis@nict.go.jp>                                                        *
4*                                                                                                        *
5* Copyright (c) 2011, WIDE Project and NICT                                                              *
6* All rights reserved.                                                                                   *
7*                                                                                                        *
8* Redistribution and use of this software in source and binary forms, with or without modification, are  *
9* permitted provided that the following conditions are met:                                              *
10*                                                                                                        *
11* * Redistributions of source code must retain the above                                                 *
12*   copyright notice, this list of conditions and the                                                    *
13*   following disclaimer.                                                                                *
14*                                                                                                        *
15* * Redistributions in binary form must reproduce the above                                              *
16*   copyright notice, this list of conditions and the                                                    *
17*   following disclaimer in the documentation and/or other                                               *
18*   materials provided with the distribution.                                                            *
19*                                                                                                        *
20* * Neither the name of the WIDE Project or NICT nor the                                                 *
21*   names of its contributors may be used to endorse or                                                  *
22*   promote products derived from this software without                                                  *
23*   specific prior written permission of WIDE Project and                                                *
24*   NICT.                                                                                                *
25*                                                                                                        *
26* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
27* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
28* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
29* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT     *
30* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS    *
31* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
32* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
33* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                                                             *
34*********************************************************************************************************/
35
36/* Yacc configuration parser.
37 *
38 * This file defines the grammar of the configuration file.
39 * Note that each extension has a separate independant configuration file.
40 *
41 * Note : This module is NOT thread-safe. All processing must be done from one thread only.
42 */
43
44/* For development only : */
45%debug
46%error-verbose
47
48%parse-param {struct fd_config * conf}
49
50/* Keep track of location */
51%locations
52%pure-parser
53
54%{
55#include "fdcore-internal.h"
56#include "fdd.tab.h"    /* bug : bison does not define the YYLTYPE before including this bloc, so... */
57
58/* The Lex parser prototype */
59int fddlex(YYSTYPE *lvalp, YYLTYPE *llocp);
60
61/* Function to report error */
62void yyerror (YYLTYPE *ploc, struct fd_config * conf, char const *s)
63{
64        if (ploc->first_line != ploc->last_line)
65                fprintf(stderr, "%s:%d.%d-%d.%d : %s\n", conf->cnf_file, ploc->first_line, ploc->first_column, ploc->last_line, ploc->last_column, s);
66        else if (ploc->first_column != ploc->last_column)
67                fprintf(stderr, "%s:%d.%d-%d : %s\n", conf->cnf_file, ploc->first_line, ploc->first_column, ploc->last_column, s);
68        else
69                fprintf(stderr, "%s:%d.%d : %s\n", conf->cnf_file, ploc->first_line, ploc->first_column, s);
70}
71
72int got_peer_noip = 0;
73int got_peer_noipv6 = 0;
74int got_peer_notcp = 0;
75int got_peer_nosctp = 0;
76
77struct peer_info fddpi;
78
79%}
80
81/* Values returned by lex for token */
82%union {
83        char             *string;       /* The string is allocated by strdup in lex.*/
84        int               integer;      /* Store integer values */
85}
86
87/* In case of error in the lexical analysis */
88%token          LEX_ERROR
89
90%token <string> QSTRING
91%token <integer> INTEGER
92
93%type <string>  extconf
94
95%token          IDENTITY
96%token          REALM
97%token          PORT
98%token          SECPORT
99%token          NOIP
100%token          NOIP6
101%token          NOTCP
102%token          NOSCTP
103%token          PREFERTCP
104%token          OLDTLS
105%token          NOTLS
106%token          SCTPSTREAMS
107%token          APPSERVTHREADS
108%token          LISTENON
109%token          TCTIMER
110%token          TWTIMER
111%token          NORELAY
112%token          LOADEXT
113%token          CONNPEER
114%token          CONNTO
115%token          TLS_CRED
116%token          TLS_CA
117%token          TLS_CRL
118%token          TLS_PRIO
119%token          TLS_DH_BITS
120%token          TLS_DH_FILE
121
122
123/* -------------------------------------- */
124%%
125
126        /* The grammar definition - Sections blocs. */
127conffile:               /* Empty is OK -- for simplicity here, we reject in daemon later */
128                        | conffile identity
129                        | conffile realm
130                        | conffile tctimer
131                        | conffile twtimer
132                        | conffile port
133                        | conffile secport
134                        | conffile sctpstreams
135                        | conffile listenon
136                        | conffile norelay
137                        | conffile appservthreads
138                        | conffile noip
139                        | conffile noip6
140                        | conffile notcp
141                        | conffile nosctp
142                        | conffile prefertcp
143                        | conffile oldtls
144                        | conffile loadext
145                        | conffile connpeer
146                        | conffile tls_cred
147                        | conffile tls_ca
148                        | conffile tls_crl
149                        | conffile tls_prio
150                        | conffile tls_dh
151                        | conffile errors
152                        {
153                                yyerror(&yylloc, conf, "An error occurred while parsing the configuration file");
154                                return EINVAL;
155                        }
156                        ;
157
158                        /* Lexical or syntax error */
159errors:                 LEX_ERROR
160                        | error
161                        ;
162
163identity:               IDENTITY '=' QSTRING ';'
164                        {
165                                conf->cnf_diamid = $3;
166                        }
167                        ;
168
169realm:                  REALM '=' QSTRING ';'
170                        {
171                                conf->cnf_diamrlm = $3;
172                        }
173                        ;
174
175tctimer:                TCTIMER '=' INTEGER ';'
176                        {
177                                CHECK_PARAMS_DO( ($3 > 0),
178                                        { yyerror (&yylloc, conf, "Invalid value"); YYERROR; } );
179                                conf->cnf_timer_tc = (unsigned int)$3;
180                        }
181                        ;
182
183twtimer:                TWTIMER '=' INTEGER ';'
184                        {
185                                CHECK_PARAMS_DO( ($3 > 5),
186                                        { yyerror (&yylloc, conf, "Invalid value"); YYERROR; } );
187                                conf->cnf_timer_tw = (unsigned int)$3;
188                        }
189                        ;
190
191port:                   PORT '=' INTEGER ';'
192                        {
193                                CHECK_PARAMS_DO( ($3 > 0) && ($3 < 1<<16),
194                                        { yyerror (&yylloc, conf, "Invalid value"); YYERROR; } );
195                                conf->cnf_port = (uint16_t)$3;
196                        }
197                        ;
198
199secport:                SECPORT '=' INTEGER ';'
200                        {
201                                CHECK_PARAMS_DO( ($3 > 0) && ($3 < 1<<16),
202                                        { yyerror (&yylloc, conf, "Invalid value"); YYERROR; } );
203                                conf->cnf_port_tls = (uint16_t)$3;
204                        }
205                        ;
206
207sctpstreams:            SCTPSTREAMS '=' INTEGER ';'
208                        {
209                                CHECK_PARAMS_DO( ($3 > 0) && ($3 < 1<<16),
210                                        { yyerror (&yylloc, conf, "Invalid value"); YYERROR; } );
211                                conf->cnf_sctp_str = (uint16_t)$3;
212                        }
213                        ;
214
215listenon:               LISTENON '=' QSTRING ';'
216                        {
217                                struct addrinfo hints, *ai;
218                                int ret;
219                               
220                                memset(&hints, 0, sizeof(hints));
221                                hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
222                                ret = getaddrinfo($3, NULL, &hints, &ai);
223                                if (ret) { yyerror (&yylloc, conf, gai_strerror(ret)); YYERROR; }
224                                CHECK_FCT_DO( fd_ep_add_merge( &conf->cnf_endpoints, ai->ai_addr, ai->ai_addrlen, EP_FL_CONF ), YYERROR );
225                                freeaddrinfo(ai);
226                                free($3);
227                        }
228                        ;
229
230norelay:                NORELAY ';'
231                        {
232                                conf->cnf_flags.no_fwd = 1;
233                        }
234                        ;
235
236appservthreads:         APPSERVTHREADS '=' INTEGER ';'
237                        {
238                                CHECK_PARAMS_DO( ($3 > 0) && ($3 < 256),
239                                        { yyerror (&yylloc, conf, "Invalid value"); YYERROR; } );
240                                conf->cnf_dispthr = (uint16_t)$3;
241                        }
242                        ;
243
244noip:                   NOIP ';'
245                        {
246                                if (got_peer_noipv6) {
247                                        yyerror (&yylloc, conf, "No_IP conflicts with a ConnectPeer directive No_IPv6.");
248                                        YYERROR;
249                                }
250                                conf->cnf_flags.no_ip4 = 1;
251                        }
252                        ;
253
254noip6:                  NOIP6 ';'
255                        {
256                                if (got_peer_noip) {
257                                        yyerror (&yylloc, conf, "No_IP conflicts with a ConnectPeer directive No_IP.");
258                                        YYERROR;
259                                }
260                                conf->cnf_flags.no_ip6 = 1;
261                        }
262                        ;
263
264notcp:                  NOTCP ';'
265                        {
266                                #ifdef DISABLE_SCTP
267                                yyerror (&yylloc, conf, "No_TCP cannot be specified for daemon compiled with DISABLE_SCTP option.");
268                                YYERROR;
269                                #endif
270                                if (conf->cnf_flags.no_sctp)
271                                {
272                                        yyerror (&yylloc, conf, "No_TCP conflicts with No_SCTP directive." );
273                                        YYERROR;
274                                }
275                                if (got_peer_nosctp) {
276                                        yyerror (&yylloc, conf, "No_TCP conflicts with a ConnectPeer directive No_SCTP.");
277                                        YYERROR;
278                                }
279                                conf->cnf_flags.no_tcp = 1;
280                        }
281                        ;
282
283nosctp:                 NOSCTP ';'
284                        {
285                                if (conf->cnf_flags.no_tcp)
286                                {
287                                        yyerror (&yylloc, conf, "No_SCTP conflicts with No_TCP directive." );
288                                        YYERROR;
289                                }
290                                if (got_peer_notcp) {
291                                        yyerror (&yylloc, conf, "No_SCTP conflicts with a ConnectPeer directive No_TCP.");
292                                        YYERROR;
293                                }
294                                conf->cnf_flags.no_sctp = 1;
295                        }
296                        ;
297
298prefertcp:              PREFERTCP ';'
299                        {
300                                conf->cnf_flags.pr_tcp = 1;
301                        }
302                        ;
303
304oldtls:                 OLDTLS ';'
305                        {
306                                conf->cnf_flags.tls_alg = 1;
307                        }
308                        ;
309
310loadext:                LOADEXT '=' QSTRING extconf ';'
311                        {
312                                char * fname;
313                                char * cfname;
314                                FILE * fd;
315                               
316                                /* Try and open the extension file */
317                                fname = $3;
318                                fd = fopen(fname, "r");
319                                if ((fd == NULL) && (*fname != '/')) {
320                                        char * bkp = fname;
321                                        CHECK_MALLOC_DO( fname = malloc( strlen(bkp) + strlen(DEFAULT_EXTENSIONS_PATH) + 2 ),
322                                                { yyerror (&yylloc, conf, "Not enough memory"); YYERROR; } );
323                                        sprintf(fname, DEFAULT_EXTENSIONS_PATH "/%s", bkp);
324                                        free(bkp);
325                                        fd = fopen(fname, "r");
326                                }
327                                if (fd == NULL) {
328                                        int ret = errno;
329                                        TRACE_DEBUG(INFO, "Unable to open extension file %s for reading: %s\n", fname, strerror(ret));
330                                        yyerror (&yylloc, conf, "Error adding extension");
331                                        YYERROR;
332                                }
333                                fclose(fd);
334                               
335                                /* Try and open the configuration file (optional) */
336                                cfname = $4;
337                                if (cfname) {
338                                        fd = fopen(cfname, "r");
339                                        if ((fd == NULL) && (*cfname != '/')) {
340                                                char * test;
341                                                CHECK_MALLOC_DO( test = malloc( strlen(cfname) + strlen(DEFAULT_CONF_PATH) + 2 ),
342                                                        { yyerror (&yylloc, conf, "Not enough memory"); YYERROR; } );
343                                                sprintf(test, DEFAULT_CONF_PATH "/%s", cfname);
344                                                fd = fopen(test, "r");
345                                                if (fd) {
346                                                        free(cfname);
347                                                        cfname=test;
348                                                } else {
349                                                        /* This is not an error, we allow an extension to wait for something else than a real conf file. */
350                                                        free(test);
351                                                }
352                                        }
353                                        if (fd)
354                                                fclose(fd);
355                                }
356                               
357                                CHECK_FCT_DO( fd_ext_add( fname, cfname ),
358                                        { yyerror (&yylloc, conf, "Error adding extension"); YYERROR; } );
359                        }
360                        ;
361                       
362extconf:                /* empty */
363                        {
364                                $$ = NULL;
365                        }
366                        | ':' QSTRING
367                        {
368                                $$ = $2;
369                        }
370                        ;
371                       
372connpeer:               {
373                                memset(&fddpi, 0, sizeof(fddpi));
374                                fddpi.config.pic_flags.persist = PI_PRST_ALWAYS;
375                                fd_list_init( &fddpi.pi_endpoints, NULL );
376                        }
377                        CONNPEER '=' QSTRING peerinfo ';'
378                        {
379                                fddpi.pi_diamid = $4;
380                                CHECK_FCT_DO( fd_peer_add ( &fddpi, conf->cnf_file, NULL, NULL ),
381                                        { yyerror (&yylloc, conf, "Error adding ConnectPeer information"); YYERROR; } );
382                                       
383                                /* Now destroy any content in the structure */
384                                free(fddpi.pi_diamid);
385                                free(fddpi.config.pic_realm);
386                                free(fddpi.config.pic_priority);
387                                while (!FD_IS_LIST_EMPTY(&fddpi.pi_endpoints)) {
388                                        struct fd_list * li = fddpi.pi_endpoints.next;
389                                        fd_list_unlink(li);
390                                        free(li);
391                                }
392                        }
393                        ;
394                       
395peerinfo:               /* empty */
396                        | '{' peerparams '}'
397                        ;
398                       
399peerparams:             /* empty */
400                        | peerparams NOIP ';'
401                        {
402                                if ((conf->cnf_flags.no_ip6) || (fddpi.config.pic_flags.pro3 == PI_P3_IP)) {
403                                        yyerror (&yylloc, conf, "No_IP conflicts with a No_IPv6 directive.");
404                                        YYERROR;
405                                }
406                                got_peer_noip++;
407                                fddpi.config.pic_flags.pro3 = PI_P3_IPv6;
408                        }
409                        | peerparams NOIP6 ';'
410                        {
411                                if ((conf->cnf_flags.no_ip4) || (fddpi.config.pic_flags.pro3 == PI_P3_IPv6)) {
412                                        yyerror (&yylloc, conf, "No_IPv6 conflicts with a No_IP directive.");
413                                        YYERROR;
414                                }
415                                got_peer_noipv6++;
416                                fddpi.config.pic_flags.pro3 = PI_P3_IP;
417                        }
418                        | peerparams NOTCP ';'
419                        {
420                                #ifdef DISABLE_SCTP
421                                        yyerror (&yylloc, conf, "No_TCP cannot be specified in daemon compiled with DISABLE_SCTP option.");
422                                        YYERROR;
423                                #endif
424                                if ((conf->cnf_flags.no_sctp) || (fddpi.config.pic_flags.pro4 == PI_P4_TCP)) {
425                                        yyerror (&yylloc, conf, "No_TCP conflicts with a No_SCTP directive.");
426                                        YYERROR;
427                                }
428                                got_peer_notcp++;
429                                fddpi.config.pic_flags.pro4 = PI_P4_SCTP;
430                        }
431                        | peerparams NOSCTP ';'
432                        {
433                                if ((conf->cnf_flags.no_tcp) || (fddpi.config.pic_flags.pro4 == PI_P4_SCTP)) {
434                                        yyerror (&yylloc, conf, "No_SCTP conflicts with a No_TCP directive.");
435                                        YYERROR;
436                                }
437                                got_peer_nosctp++;
438                                fddpi.config.pic_flags.pro4 = PI_P4_TCP;
439                        }
440                        | peerparams PREFERTCP ';'
441                        {
442                                fddpi.config.pic_flags.alg = PI_ALGPREF_TCP;
443                        }
444                        | peerparams OLDTLS ';'
445                        {
446                                fddpi.config.pic_flags.sec |= PI_SEC_TLS_OLD;
447                        }
448                        | peerparams NOTLS ';'
449                        {
450                                fddpi.config.pic_flags.sec |= PI_SEC_NONE;
451                        }
452                        | peerparams REALM '=' QSTRING ';'
453                        {
454                                fddpi.config.pic_realm = $4;
455                        }
456                        | peerparams PORT '=' INTEGER ';'
457                        {
458                                CHECK_PARAMS_DO( ($4 > 0) && ($4 < 1<<16),
459                                        { yyerror (&yylloc, conf, "Invalid port value"); YYERROR; } );
460                                fddpi.config.pic_port = (uint16_t)$4;
461                        }
462                        | peerparams TCTIMER '=' INTEGER ';'
463                        {
464                                fddpi.config.pic_tctimer = $4;
465                        }
466                        | peerparams TWTIMER '=' INTEGER ';'
467                        {
468                                fddpi.config.pic_twtimer = $4;
469                        }
470                        | peerparams TLS_PRIO '=' QSTRING ';'
471                        {
472                                fddpi.config.pic_priority = $4;
473                        }
474                        | peerparams CONNTO '=' QSTRING ';'
475                        {
476                                struct addrinfo hints, *ai;
477                                int ret;
478                                int disc = 0;
479                               
480                                memset(&hints, 0, sizeof(hints));
481                                hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST;
482                                ret = getaddrinfo($4, NULL, &hints, &ai);
483                                if (ret == EAI_NONAME) {
484                                        /* The name was maybe not numeric, try again */
485                                        disc = EP_FL_DISC;
486                                        hints.ai_flags &= ~ AI_NUMERICHOST;
487                                        ret = getaddrinfo($4, NULL, &hints, &ai);
488                                }
489                                if (ret) { yyerror (&yylloc, conf, gai_strerror(ret)); YYERROR; }
490                               
491                                CHECK_FCT_DO( fd_ep_add_merge( &fddpi.pi_endpoints, ai->ai_addr, ai->ai_addrlen, EP_FL_CONF | disc ), YYERROR );
492                                free($4);
493                                freeaddrinfo(ai);
494                        }
495                        ;
496
497tls_cred:               TLS_CRED '=' QSTRING ',' QSTRING ';'
498                        {
499                                FILE * fd;
500                                fd = fopen($3, "r");
501                                if (fd == NULL) {
502                                        int ret = errno;
503                                        TRACE_DEBUG(INFO, "Unable to open certificate file %s for reading: %s\n", $3, strerror(ret));
504                                        yyerror (&yylloc, conf, "Error on file name");
505                                        YYERROR;
506                                }
507                                fclose(fd);
508                                fd = fopen($5, "r");
509                                if (fd == NULL) {
510                                        int ret = errno;
511                                        TRACE_DEBUG(INFO, "Unable to open private key file %s for reading: %s\n", $5, strerror(ret));
512                                        yyerror (&yylloc, conf, "Error on file name");
513                                        YYERROR;
514                                }
515                                fclose(fd);
516                                conf->cnf_sec_data.cert_file = $3;
517                                conf->cnf_sec_data.key_file = $5;
518                               
519                                CHECK_GNUTLS_DO( gnutls_certificate_set_x509_key_file(
520                                                        conf->cnf_sec_data.credentials,
521                                                        conf->cnf_sec_data.cert_file,
522                                                        conf->cnf_sec_data.key_file,
523                                                        GNUTLS_X509_FMT_PEM),
524                                                { yyerror (&yylloc, conf, "Error opening certificate or private key file."); YYERROR; } );
525                        }
526                        ;
527
528tls_ca:                 TLS_CA '=' QSTRING ';'
529                        {
530                                FILE * fd;
531                                fd = fopen($3, "r");
532                                if (fd == NULL) {
533                                        int ret = errno;
534                                        TRACE_DEBUG(INFO, "Unable to open CA file %s for reading: %s\n", $3, strerror(ret));
535                                        yyerror (&yylloc, conf, "Error on file name");
536                                        YYERROR;
537                                }
538                                fclose(fd);
539                                conf->cnf_sec_data.ca_file = $3;
540                                CHECK_GNUTLS_DO( conf->cnf_sec_data.ca_file_nr += gnutls_certificate_set_x509_trust_file(
541                                                        conf->cnf_sec_data.credentials,
542                                                        conf->cnf_sec_data.ca_file,
543                                                        GNUTLS_X509_FMT_PEM),
544                                                { yyerror (&yylloc, conf, "Error setting CA parameters."); YYERROR; } );
545                        }
546                        ;
547                       
548tls_crl:                TLS_CRL '=' QSTRING ';'
549                        {
550                                FILE * fd;
551                                fd = fopen($3, "r");
552                                if (fd == NULL) {
553                                        int ret = errno;
554                                        TRACE_DEBUG(INFO, "Unable to open CRL file %s for reading: %s\n", $3, strerror(ret));
555                                        yyerror (&yylloc, conf, "Error on file name");
556                                        YYERROR;
557                                }
558                                fclose(fd);
559                                conf->cnf_sec_data.crl_file = $3;
560                                CHECK_GNUTLS_DO( gnutls_certificate_set_x509_crl_file(
561                                                        conf->cnf_sec_data.credentials,
562                                                        conf->cnf_sec_data.ca_file,
563                                                        GNUTLS_X509_FMT_PEM),
564                                                { yyerror (&yylloc, conf, "Error setting CRL parameters."); YYERROR; } );
565                        }
566                        ;
567                       
568tls_prio:               TLS_PRIO '=' QSTRING ';'
569                        {
570                                const char * err_pos = NULL;
571                                conf->cnf_sec_data.prio_string = $3;
572                                CHECK_GNUTLS_DO( gnutls_priority_init(
573                                                        &conf->cnf_sec_data.prio_cache,
574                                                        conf->cnf_sec_data.prio_string,
575                                                        &err_pos),
576                                                { yyerror (&yylloc, conf, "Error setting Priority parameter.");
577                                                  fprintf(stderr, "Error at position : %s\n", err_pos);
578                                                  YYERROR; } );
579                        }
580                        ;
581                       
582tls_dh:                 TLS_DH_BITS '=' INTEGER ';'
583                        {
584                                conf->cnf_sec_data.dh_bits = $3;
585                        }
586                        | TLS_DH_FILE '=' QSTRING ';'
587                        {
588                                FILE * fd;
589                                free(conf->cnf_sec_data.dh_file);
590                                conf->cnf_sec_data.dh_file = $3;
591                                fd = fopen($3, "r");
592                                if (fd == NULL) {
593                                        int ret = errno;
594                                        TRACE_DEBUG(INFO, "Unable to open DH file %s for reading: %s\n", $3, strerror(ret));
595                                        yyerror (&yylloc, conf, "Error on file name");
596                                        YYERROR;
597                                }
598                                fclose(fd);
599                        }
600                        ;
Note: See TracBrowser for help on using the repository browser.