GNUnet  0.11.x
mysql.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet
3  Copyright (C) 2012 GNUnet e.V.
4 
5  GNUnet is free software: you can redistribute it and/or modify it
6  under the terms of the GNU Affero General Public License as published
7  by the Free Software Foundation, either version 3 of the License,
8  or (at your 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  Affero General Public License for more details.
14 
15  You should have received a copy of the GNU Affero General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  SPDX-License-Identifier: AGPL3.0-or-later
19  */
25 #include "platform.h"
26 #include <mysql/mysql.h>
27 #include "gnunet_mysql_lib.h"
28 
33 #define MAX_PARAM 16
34 
35 
41 #define DIE_MYSQL(cmd, dbh) \
42  do \
43  { \
44  GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, \
45  "mysql", \
46  _ ("`%s' failed at %s:%d with error: %s\n"), \
47  cmd, \
48  __FILE__, \
49  __LINE__, \
50  mysql_error ((dbh)->dbf)); \
51  GNUNET_assert (0); \
52  } while (0);
53 
59 #define LOG_MYSQL(level, cmd, dbh) \
60  do \
61  { \
62  GNUNET_log_from (level, \
63  "mysql", \
64  _ ("`%s' failed at %s:%d with error: %s\n"), \
65  cmd, \
66  __FILE__, \
67  __LINE__, \
68  mysql_error ((dbh)->dbf)); \
69  } while (0);
70 
71 
76 {
81 
85  const char *section;
86 
90  MYSQL *dbf;
91 
96 
101 
105  char *cnffile;
106 };
107 
108 
113 {
118 
123 
128 
132  char *query;
133 
137  MYSQL_STMT *statement;
138 
142  int valid;
143 };
144 
145 
153 static char *
155  const char *section)
156 {
157  char *cnffile;
158  char *home_dir;
159  struct stat st;
160 
161  struct passwd *pw;
162 
163  int configured;
164 
165  pw = getpwuid (getuid ());
166  if (! pw)
167  {
168  GNUNET_log_from_strerror (GNUNET_ERROR_TYPE_ERROR, "mysql", "getpwuid");
169  return NULL;
170  }
171  if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (cfg, section, "CONFIG"))
172  {
175  section,
176  "CONFIG",
177  &cnffile));
178  configured = GNUNET_YES;
179  }
180  else
181  {
182  home_dir = GNUNET_strdup (pw->pw_dir);
183  GNUNET_asprintf (&cnffile, "%s/.my.cnf", home_dir);
184  GNUNET_free (home_dir);
185  configured = GNUNET_NO;
186  }
187 
189  "mysql",
190  _ ("Trying to use file `%s' for MySQL configuration.\n"),
191  cnffile);
192  if ((0 != stat (cnffile, &st)) || (0 != access (cnffile, R_OK)) ||
193  (! S_ISREG (st.st_mode)))
194  {
195  if (configured == GNUNET_YES)
197  "mysql",
198  _ ("Could not access file `%s': %s\n"),
199  cnffile,
200  strerror (errno));
201  GNUNET_free (cnffile);
202  return NULL;
203  }
204  return cnffile;
205 }
206 
207 
215 static int
217 {
218  char *mysql_dbname;
219  char *mysql_server;
220  char *mysql_user;
221  char *mysql_password;
222  unsigned long long mysql_port;
223  my_bool reconnect;
224  unsigned int timeout;
225 
226  mc->dbf = mysql_init (NULL);
227  if (mc->dbf == NULL)
228  return GNUNET_SYSERR;
229  if (mc->cnffile != NULL)
230  mysql_options (mc->dbf, MYSQL_READ_DEFAULT_FILE, mc->cnffile);
231  mysql_options (mc->dbf, MYSQL_READ_DEFAULT_GROUP, "client");
232  reconnect = 0;
233  mysql_options (mc->dbf, MYSQL_OPT_RECONNECT, &reconnect);
234  mysql_options (mc->dbf, MYSQL_OPT_CONNECT_TIMEOUT, (const void *) &timeout);
235  mysql_options (mc->dbf, MYSQL_SET_CHARSET_NAME, "UTF8");
236  timeout = 60; /* in seconds */
237  mysql_options (mc->dbf, MYSQL_OPT_READ_TIMEOUT, (const void *) &timeout);
238  mysql_options (mc->dbf, MYSQL_OPT_WRITE_TIMEOUT, (const void *) &timeout);
239  mysql_dbname = NULL;
240  if (GNUNET_YES ==
241  GNUNET_CONFIGURATION_have_value (mc->cfg, mc->section, "DATABASE"))
244  mc->section,
245  "DATABASE",
246  &mysql_dbname));
247  else
248  mysql_dbname = GNUNET_strdup ("gnunet");
249  mysql_user = NULL;
250  if (GNUNET_YES ==
251  GNUNET_CONFIGURATION_have_value (mc->cfg, mc->section, "USER"))
252  {
255  mc->section,
256  "USER",
257  &mysql_user));
258  }
259  mysql_password = NULL;
260  if (GNUNET_YES ==
261  GNUNET_CONFIGURATION_have_value (mc->cfg, mc->section, "PASSWORD"))
262  {
265  mc->section,
266  "PASSWORD",
267  &mysql_password));
268  }
269  mysql_server = NULL;
270  if (GNUNET_YES ==
271  GNUNET_CONFIGURATION_have_value (mc->cfg, mc->section, "HOST"))
272  {
275  mc->section,
276  "HOST",
277  &mysql_server));
278  }
279  mysql_port = 0;
280  if (GNUNET_YES ==
281  GNUNET_CONFIGURATION_have_value (mc->cfg, mc->section, "PORT"))
282  {
285  mc->section,
286  "PORT",
287  &mysql_port));
288  }
289 
290  GNUNET_assert (mysql_dbname != NULL);
291  mysql_real_connect (mc->dbf,
292  mysql_server,
293  mysql_user,
294  mysql_password,
295  mysql_dbname,
296  (unsigned int) mysql_port,
297  NULL,
298  CLIENT_IGNORE_SIGPIPE);
299  GNUNET_free_non_null (mysql_server);
300  GNUNET_free_non_null (mysql_user);
301  GNUNET_free_non_null (mysql_password);
302  GNUNET_free (mysql_dbname);
303  if (mysql_error (mc->dbf)[0])
304  {
305  LOG_MYSQL (GNUNET_ERROR_TYPE_ERROR, "mysql_real_connect", mc);
306  return GNUNET_SYSERR;
307  }
308  return GNUNET_OK;
309 }
310 
311 
319 struct GNUNET_MYSQL_Context *
321  const char *section)
322 {
323  struct GNUNET_MYSQL_Context *mc;
324 
325  mc = GNUNET_new (struct GNUNET_MYSQL_Context);
326  mc->cfg = cfg;
327  mc->section = section;
328  mc->cnffile = get_my_cnf_path (cfg, section);
329 
330  return mc;
331 }
332 
333 
340 void
342 {
344 
345  for (sh = mc->shead; NULL != sh; sh = sh->next)
346  {
347  if (GNUNET_YES == sh->valid)
348  {
349  mysql_stmt_close (sh->statement);
350  sh->valid = GNUNET_NO;
351  }
352  sh->statement = NULL;
353  }
354  if (NULL != mc->dbf)
355  {
356  mysql_close (mc->dbf);
357  mc->dbf = NULL;
358  }
359 }
360 
361 
367 void
369 {
371 
373  while (NULL != (sh = mc->shead))
374  {
375  GNUNET_CONTAINER_DLL_remove (mc->shead, mc->stail, sh);
376  GNUNET_free (sh->query);
377  GNUNET_free (sh);
378  }
379  GNUNET_free (mc);
380  mysql_library_end ();
381 }
382 
383 
394  const char *query)
395 {
397 
399  sh->mc = mc;
400  sh->query = GNUNET_strdup (query);
401  GNUNET_CONTAINER_DLL_insert (mc->shead, mc->stail, sh);
402  return sh;
403 }
404 
405 
414 int
416 {
417  if ((NULL == mc->dbf) && (GNUNET_OK != iopen (mc)))
418  return GNUNET_SYSERR;
419  mysql_query (mc->dbf, sql);
420  if (mysql_error (mc->dbf)[0])
421  {
422  LOG_MYSQL (GNUNET_ERROR_TYPE_ERROR, "mysql_query", mc);
424  return GNUNET_SYSERR;
425  }
426  return GNUNET_OK;
427 }
428 
429 
437 static int
439 {
440  struct GNUNET_MYSQL_Context *mc = sh->mc;
441 
442  if (GNUNET_YES == sh->valid)
443  return GNUNET_OK;
444  if ((NULL == mc->dbf) && (GNUNET_OK != iopen (mc)))
445  return GNUNET_SYSERR;
446  sh->statement = mysql_stmt_init (mc->dbf);
447  if (NULL == sh->statement)
448  {
450  return GNUNET_SYSERR;
451  }
452  if (0 != mysql_stmt_prepare (sh->statement, sh->query, strlen (sh->query)))
453  {
455  "mysql",
456  "prepare_statement: %s\n",
457  sh->query);
458  LOG_MYSQL (GNUNET_ERROR_TYPE_ERROR, "mysql_stmt_prepare", mc);
459  mysql_stmt_close (sh->statement);
460  sh->statement = NULL;
462  return GNUNET_SYSERR;
463  }
464  sh->valid = GNUNET_YES;
465  return GNUNET_OK;
466 }
467 
468 
477 MYSQL_STMT *
479 {
480  (void) prepare_statement (sh);
481  return sh->statement;
482 }
483 
484 
485 /* end of mysql.c */
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
int GNUNET_CONFIGURATION_get_value_number(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, unsigned long long *number)
Get a configuration value that should be a number.
struct GNUNET_MYSQL_Context * GNUNET_MYSQL_context_create(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section)
Create a mysql context.
Definition: mysql.c:320
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
MYSQL_STMT * statement
Handle to MySQL prepared statement.
Definition: mysql.c:137
#define GNUNET_log_from_strerror(level, component, cmd)
Log an error message at log-level &#39;level&#39; that indicates a failure of the command &#39;cmd&#39; with the mess...
struct GNUNET_MYSQL_StatementHandle * prev
Kept in a DLL.
Definition: mysql.c:122
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
char * query
Original query string.
Definition: mysql.c:132
char * cnffile
Filename of "my.cnf" (msyql configuration).
Definition: mysql.c:105
#define GNUNET_NO
Definition: gnunet_common.h:78
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:75
#define GNUNET_free_non_null(ptr)
Free the memory pointed to by ptr if ptr is not NULL.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
Handle for a prepared statement.
Definition: mysql.c:112
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define _(String)
GNU gettext support macro.
Definition: platform.h:181
const struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
Definition: mysql.c:80
static int prepare_statement(struct GNUNET_MYSQL_StatementHandle *sh)
Prepare a statement for running.
Definition: mysql.c:438
int GNUNET_asprintf(char **buf, const char *format,...)
Like asprintf, just portable.
static struct GNUNET_TIME_Relative timeout
Desired timeout for the lookup (default is no timeout).
Definition: gnunet-abd.c:61
void GNUNET_MYSQL_context_destroy(struct GNUNET_MYSQL_Context *mc)
Destroy a mysql context.
Definition: mysql.c:368
int GNUNET_CONFIGURATION_have_value(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option)
Test if we have a value for a particular option.
static struct SolverHandle * sh
MYSQL_STMT * GNUNET_MYSQL_statement_get_stmt(struct GNUNET_MYSQL_StatementHandle *sh)
Get internal handle for a prepared statement.
Definition: mysql.c:478
void GNUNET_MYSQL_statements_invalidate(struct GNUNET_MYSQL_Context *mc)
Close database connection and all prepared statements (we got a DB error).
Definition: mysql.c:341
int valid
Is the MySQL prepared statement valid, or do we need to re-initialize it?
Definition: mysql.c:142
static struct GNUNET_TESTBED_Controller * mc
Handle to the master controller.
static void reconnect(struct GNUNET_ABD_Handle *handle)
Reconnect to ABD service.
Definition: abd_api.c:316
int GNUNET_CONFIGURATION_get_value_string(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be a string.
MYSQL * dbf
Handle to the mysql database.
Definition: mysql.c:90
#define GNUNET_SYSERR
Definition: gnunet_common.h:76
Mysql context.
Definition: mysql.c:75
struct GNUNET_MYSQL_StatementHandle * GNUNET_MYSQL_statement_prepare(struct GNUNET_MYSQL_Context *mc, const char *query)
Prepare a statement.
Definition: mysql.c:393
static char * get_my_cnf_path(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section)
Obtain the location of ".my.cnf".
Definition: mysql.c:154
struct GNUNET_MYSQL_Context * mc
Mysql Context the statement handle belongs to.
Definition: mysql.c:127
configuration data
Definition: configuration.c:85
int GNUNET_MYSQL_statement_run(struct GNUNET_MYSQL_Context *mc, const char *sql)
Run a SQL statement.
Definition: mysql.c:415
struct GNUNET_MYSQL_StatementHandle * stail
Tail of list of our prepared statements.
Definition: mysql.c:100
const char * section
Our section.
Definition: mysql.c:85
#define LOG_MYSQL(level, cmd, dbh)
Log an error message at log-level &#39;level&#39; that indicates a failure of the command &#39;cmd&#39; on file &#39;file...
Definition: mysql.c:59
int GNUNET_CONFIGURATION_get_value_filename(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be the name of a file or directory.
#define GNUNET_YES
Definition: gnunet_common.h:77
struct GNUNET_MYSQL_StatementHandle * next
Kept in a DLL.
Definition: mysql.c:117
static int iopen(struct GNUNET_MYSQL_Context *mc)
Open the connection with the database (and initialize our default options).
Definition: mysql.c:216
#define GNUNET_log_from(kind, comp,...)
#define GNUNET_free(ptr)
Wrapper around free.
struct GNUNET_MYSQL_StatementHandle * shead
Head of list of our prepared statements.
Definition: mysql.c:95