- simplify parameters
[oweals/gnunet.git] / src / regex / regex_block_lib.c
1 /*
2      This file is part of GNUnet.
3      (C) 2012,2013 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20 /**
21  * @author Bartlomiej Polot
22  * @file regex/regex_block_lib.c
23  */
24 #include "platform.h"
25 #include "regex_block_lib.h"
26
27 #define LOG(kind,...) GNUNET_log_from (kind,"regex-bck",__VA_ARGS__)
28
29 /**
30  * Struct to keep track of the xquery while iterating all the edges in a block.
31  */
32 struct regex_block_xquery_ctx
33 {
34   /**
35    * Xquery: string we are looking for.
36    */
37   const char *xquery;
38
39   /**
40    * Has any edge matched the xquery so far? (GNUNET_OK / GNUNET_NO)
41    */
42   int found;
43
44   /**
45    * Key of the block we are iterating (for debug purposes).
46    */
47   char *key;
48 };
49
50
51 /**
52  * Iterator over all edges in a block, checking for a presence of a given query.
53  *
54  * @param cls Closure, (xquery context).
55  * @param token Token that follows to next state.
56  * @param len Lenght of token.
57  * @param key Hash of next state.
58  * 
59  * @return GNUNET_YES, to keep iterating
60  */
61 static int
62 check_edge (void *cls,
63             const char *token,
64             size_t len,
65             const struct GNUNET_HashCode *key)
66 {
67   struct regex_block_xquery_ctx *ctx = cls;
68
69
70   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  edge %.*s [%u]: %s->%s\n",
71               (int) len, token, len, ctx->key, GNUNET_h2s(key));
72
73   if (NULL == ctx->xquery)
74     return GNUNET_YES;
75   if (strlen (ctx->xquery) < len)
76   {
77     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  too long!\n");
78     return GNUNET_YES;
79   }
80   if (0 == strncmp (ctx->xquery, token, len))
81   {
82     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  OK!\n");
83     ctx->found = GNUNET_OK;
84   }
85   else
86   {
87     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  KO!\n");
88   }
89
90   return GNUNET_YES; /* keep checking for malformed data! */
91 }
92
93
94 int
95 GNUNET_REGEX_block_check (const struct RegexBlock *block,
96                           size_t size,
97                           const char *xquery)
98 {
99   int res;
100   struct regex_block_xquery_ctx ctx;
101
102   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
103               "* Checking block with xquery \"%s\"\n",
104               NULL != xquery ? xquery : "NULL");
105   if ( (GNUNET_YES == ntohl (block->accepting)) &&
106        ( (NULL == xquery) || ('\0' == xquery[0]) )
107      )
108     return GNUNET_OK;
109   ctx.xquery = xquery;
110   ctx.found = GNUNET_NO;
111   ctx.key = GNUNET_strdup (GNUNET_h2s (&block->key));
112   res = GNUNET_REGEX_block_iterate (block, size, &check_edge, &ctx);
113   GNUNET_free (ctx.key);
114   if (GNUNET_SYSERR == res)
115     return GNUNET_SYSERR;
116   if (NULL == xquery)
117     return GNUNET_YES;
118   return ctx.found;
119 }
120
121
122 int
123 GNUNET_REGEX_block_iterate (const struct RegexBlock *block,
124                             size_t size,
125                             GNUNET_REGEX_EgdeIterator iterator,
126                             void *iter_cls)
127 {
128   struct RegexEdge *edge;
129   unsigned int n;
130   unsigned int n_token;
131   unsigned int i;
132   size_t offset;
133   char *aux;
134
135   offset = sizeof (struct RegexBlock);
136   LOG (GNUNET_ERROR_TYPE_DEBUG,
137        "* Start iterating block of size %u, off %u\n",
138        size, offset);
139   if (offset >= size) /* Is it safe to access the regex block? */
140   {
141     LOG (GNUNET_ERROR_TYPE_WARNING,
142          "*   Block is smaller than struct RegexBlock, END\n");
143     GNUNET_break_op (0);
144     return GNUNET_SYSERR;
145   }
146   n = ntohl (block->n_proof);
147   offset += n;
148   LOG (GNUNET_ERROR_TYPE_DEBUG,
149        "*  Proof length: %u, off %u\n", n, offset);
150   if (offset >= size) /* Is it safe to access the regex proof? */
151   {
152     LOG (GNUNET_ERROR_TYPE_WARNING,
153          "*   Block is smaller than Block + proof, END\n");
154     GNUNET_break_op (0);
155     return GNUNET_SYSERR;
156   }
157   aux = (char *) &block[1];  /* Skip regex block */
158   aux = &aux[n];             /* Skip regex proof */
159   n = ntohl (block->n_edges);
160   LOG (GNUNET_ERROR_TYPE_DEBUG, "*  Edges: %u\n", n);
161   /* aux always points at the end of the previous block */
162   for (i = 0; i < n; i++)
163   {
164     offset += sizeof (struct RegexEdge);
165     LOG (GNUNET_ERROR_TYPE_DEBUG, "*   Edge %u, off %u\n", i, offset);
166     if (offset >= size) /* Is it safe to access the next edge block? */
167     {
168       LOG (GNUNET_ERROR_TYPE_WARNING,
169            "*   Size not enough for RegexEdge, END\n");
170       GNUNET_break_op (0);
171       return GNUNET_SYSERR;
172     }
173     edge = (struct RegexEdge *) aux;
174     n_token = ntohl (edge->n_token);
175     offset += n_token;
176     LOG (GNUNET_ERROR_TYPE_DEBUG, 
177          "*    Token length %u, off %u\n", n_token, offset);
178     if (offset > size) /* Is it safe to access the edge token? */
179     {
180       LOG (GNUNET_ERROR_TYPE_WARNING,
181            "*   Size not enough for edge token, END\n");
182       GNUNET_break_op (0);
183       return GNUNET_SYSERR;
184     }
185     aux = (char *) &edge[1]; /* Skip edge block */
186     if (NULL != iterator)
187         if (GNUNET_NO == iterator (iter_cls, aux, n_token, &edge->key))
188             return GNUNET_OK;
189     aux = &aux[n_token];     /* Skip edge token */
190   }
191   /* The total size should be exactly the size of (regex + all edges) blocks
192    * If size == -1, block is from cache and therefore previously checked and
193    * assumed correct. */
194   if (offset == size || SIZE_MAX == size)
195   {
196     LOG (GNUNET_ERROR_TYPE_DEBUG, "* Block processed, END OK\n");
197     return GNUNET_OK;
198   }
199   LOG (GNUNET_ERROR_TYPE_WARNING,
200        "*   Size %u (%d), read %u END KO\n", size, size, offset);
201   GNUNET_break_op (0);
202   return GNUNET_SYSERR;
203 }
204
205 /* end of regex_block_lib.c */