GNUnet  0.19.2
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 #include "gnunet_mysql_compat.h"
29 
34 #define MAX_PARAM 16
35 
36 
42 #define DIE_MYSQL(cmd, dbh) \
43  do \
44  { \
45  GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, \
46  "mysql", \
47  _ ("`%s' failed at %s:%d with error: %s\n"), \
48  cmd, \
49  __FILE__, \
50  __LINE__, \
51  mysql_error ((dbh)->dbf)); \
52  GNUNET_assert (0); \
53  } while (0);
54 
60 #define LOG_MYSQL(level, cmd, dbh) \
61  do \
62  { \
63  GNUNET_log_from (level, \
64  "mysql", \
65  _ ("`%s' failed at %s:%d with error: %s\n"), \
66  cmd, \
67  __FILE__, \
68  __LINE__, \
69  mysql_error ((dbh)->dbf)); \
70  } while (0);
71 
72 
77 {
82 
86  const char *section;
87 
91  MYSQL *dbf;
92 
97 
102 
106  char *cnffile;
107 };
108 
109 
114 {
119 
124 
129 
133  char *query;
134 
138  MYSQL_STMT *statement;
139 
143  int valid;
144 };
145 
146 
154 static char *
156  const char *section)
157 {
158  char *cnffile;
159  char *home_dir;
160  struct stat st;
161 
162  struct passwd *pw;
163 
164  int configured;
165 
166  pw = getpwuid (getuid ());
167  if (! pw)
168  {
169  GNUNET_log_from_strerror (GNUNET_ERROR_TYPE_ERROR, "mysql", "getpwuid");
170  return NULL;
171  }
172  if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (cfg, section, "CONFIG"))
173  {
176  section,
177  "CONFIG",
178  &cnffile));
179  configured = GNUNET_YES;
180  }
181  else
182  {
183  home_dir = GNUNET_strdup (pw->pw_dir);
184  GNUNET_asprintf (&cnffile, "%s/.my.cnf", home_dir);
185  GNUNET_free (home_dir);
186  configured = GNUNET_NO;
187  }
188 
190  "mysql",
191  _ ("Trying to use file `%s' for MySQL configuration.\n"),
192  cnffile);
193  if ((0 != stat (cnffile, &st)) || (0 != access (cnffile, R_OK)) ||
194  (! S_ISREG (st.st_mode)))
195  {
196  if (configured == GNUNET_YES)
198  "mysql",
199  _ ("Could not access file `%s': %s\n"),
200  cnffile,
201  strerror (errno));
202  GNUNET_free (cnffile);
203  return NULL;
204  }
205  return cnffile;
206 }
207 
208 
216 static int
218 {
219  char *mysql_dbname;
220  char *mysql_server;
221  char *mysql_user;
222  char *mysql_password;
223  unsigned long long mysql_port;
225  unsigned int timeout;
226 
227  mc->dbf = mysql_init (NULL);
228  if (mc->dbf == NULL)
229  return GNUNET_SYSERR;
230  if (mc->cnffile != NULL)
231  mysql_options (mc->dbf, MYSQL_READ_DEFAULT_FILE, mc->cnffile);
232  mysql_options (mc->dbf, MYSQL_READ_DEFAULT_GROUP, "client");
233  reconnect = 0;
234  mysql_options (mc->dbf, MYSQL_OPT_RECONNECT, &reconnect);
235  mysql_options (mc->dbf, MYSQL_OPT_CONNECT_TIMEOUT, (const void *) &timeout);
236  mysql_options (mc->dbf, MYSQL_SET_CHARSET_NAME, "UTF8");
237  timeout = 60; /* in seconds */
238  mysql_options (mc->dbf, MYSQL_OPT_READ_TIMEOUT, (const void *) &timeout);
239  mysql_options (mc->dbf, MYSQL_OPT_WRITE_TIMEOUT, (const void *) &timeout);
240  mysql_dbname = NULL;
241  if (GNUNET_YES ==
242  GNUNET_CONFIGURATION_have_value (mc->cfg, mc->section, "DATABASE"))
245  mc->section,
246  "DATABASE",
247  &mysql_dbname));
248  else
249  mysql_dbname = GNUNET_strdup ("gnunet");
250  mysql_user = NULL;
251  if (GNUNET_YES ==
252  GNUNET_CONFIGURATION_have_value (mc->cfg, mc->section, "USER"))
253  {
256  mc->section,
257  "USER",
258  &mysql_user));
259  }
260  mysql_password = NULL;
261  if (GNUNET_YES ==
262  GNUNET_CONFIGURATION_have_value (mc->cfg, mc->section, "PASSWORD"))
263  {
266  mc->section,
267  "PASSWORD",
268  &mysql_password));
269  }
270  mysql_server = NULL;
271  if (GNUNET_YES ==
272  GNUNET_CONFIGURATION_have_value (mc->cfg, mc->section, "HOST"))
273  {
276  mc->section,
277  "HOST",
278  &mysql_server));
279  }
280  mysql_port = 0;
281  if (GNUNET_YES ==
282  GNUNET_CONFIGURATION_have_value (mc->cfg, mc->section, "PORT"))
283  {
286  mc->section,
287  "PORT",
288  &mysql_port));
289  }
290 
291  GNUNET_assert (mysql_dbname != NULL);
292  mysql_real_connect (mc->dbf,
293  mysql_server,
294  mysql_user,
295  mysql_password,
296  mysql_dbname,
297  (unsigned int) mysql_port,
298  NULL,
299  CLIENT_IGNORE_SIGPIPE);
300  GNUNET_free (mysql_server);
301  GNUNET_free (mysql_user);
302  GNUNET_free (mysql_password);
303  GNUNET_free (mysql_dbname);
304  if (mysql_error (mc->dbf)[0])
305  {
306  LOG_MYSQL (GNUNET_ERROR_TYPE_ERROR, "mysql_real_connect", mc);
307  return GNUNET_SYSERR;
308  }
309  return GNUNET_OK;
310 }
311 
312 
320 struct GNUNET_MYSQL_Context *
322  const char *section)
323 {
324  struct GNUNET_MYSQL_Context *mc;
325 
327  mc->cfg = cfg;
328  mc->section = section;
329  mc->cnffile = get_my_cnf_path (cfg, section);
330 
331  return mc;
332 }
333 
334 
341 void
343 {
345 
346  for (sh = mc->shead; NULL != sh; sh = sh->next)
347  {
348  if (GNUNET_YES == sh->valid)
349  {
350  mysql_stmt_close (sh->statement);
351  sh->valid = GNUNET_NO;
352  }
353  sh->statement = NULL;
354  }
355  if (NULL != mc->dbf)
356  {
357  mysql_close (mc->dbf);
358  mc->dbf = NULL;
359  }
360 }
361 
362 
368 void
370 {
372 
374  while (NULL != (sh = mc->shead))
375  {
376  GNUNET_CONTAINER_DLL_remove (mc->shead, mc->stail, sh);
377  GNUNET_free (sh->query);
378  GNUNET_free (sh);
379  }
380  GNUNET_free (mc);
381  mysql_library_end ();
382 }
383 
384 
395  const char *query)
396 {
398 
400  sh->mc = mc;
401  sh->query = GNUNET_strdup (query);
402  GNUNET_CONTAINER_DLL_insert (mc->shead, mc->stail, sh);
403  return sh;
404 }
405 
406 
415 int
417 {
418  if ((NULL == mc->dbf) && (GNUNET_OK != iopen (mc)))
419  return GNUNET_SYSERR;
420  mysql_query (mc->dbf, sql);
421  if (mysql_error (mc->dbf)[0])
422  {
423  LOG_MYSQL (GNUNET_ERROR_TYPE_ERROR, "mysql_query", mc);
425  return GNUNET_SYSERR;
426  }
427  return GNUNET_OK;
428 }
429 
430 
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 */
static void reconnect(struct GNUNET_ABD_Handle *handle)
Reconnect to ABD service.
Definition: abd_api.c:316
static const struct GNUNET_CONFIGURATION_Handle * cfg
Configuration we are using.
Definition: gnunet-abd.c:36
static struct GNUNET_TIME_Relative timeout
Desired timeout for the lookup (default is no timeout).
Definition: gnunet-abd.c:61
static struct SolverHandle * sh
static struct GNUNET_SCHEDULER_Task * st
The shutdown task.
static struct GNUNET_TESTBED_Controller * mc
Handle to the master controller.
enum GNUNET_GenericReturnValue 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.
enum GNUNET_GenericReturnValue 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.
enum GNUNET_GenericReturnValue 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.
enum GNUNET_GenericReturnValue 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.
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
#define GNUNET_log_from(kind, comp,...)
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
@ GNUNET_SYSERR
#define GNUNET_log_from_strerror(level, component, cmd)
Log an error message at log-level 'level' that indicates a failure of the command 'cmd' with the mess...
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_INFO
int int GNUNET_asprintf(char **buf, const char *format,...) __attribute__((format(printf
Like asprintf, just portable.
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_free(ptr)
Wrapper around free.
#define MYSQL_BOOL
struct GNUNET_MYSQL_StatementHandle * GNUNET_MYSQL_statement_prepare(struct GNUNET_MYSQL_Context *mc, const char *query)
Prepare a statement.
Definition: mysql.c:394
MYSQL_STMT * GNUNET_MYSQL_statement_get_stmt(struct GNUNET_MYSQL_StatementHandle *sh)
Get internal handle for a prepared statement.
Definition: mysql.c:478
struct GNUNET_MYSQL_Context * GNUNET_MYSQL_context_create(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section)
Create a mysql context.
Definition: mysql.c:321
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:342
void GNUNET_MYSQL_context_destroy(struct GNUNET_MYSQL_Context *mc)
Destroy a mysql context.
Definition: mysql.c:369
int GNUNET_MYSQL_statement_run(struct GNUNET_MYSQL_Context *mc, const char *sql)
Run a SQL statement.
Definition: mysql.c:416
static int iopen(struct GNUNET_MYSQL_Context *mc)
Open the connection with the database (and initialize our default options).
Definition: mysql.c:217
#define LOG_MYSQL(level, cmd, dbh)
Log an error message at log-level 'level' that indicates a failure of the command 'cmd' on file 'file...
Definition: mysql.c:60
static char * get_my_cnf_path(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section)
Obtain the location of ".my.cnf".
Definition: mysql.c:155
static int prepare_statement(struct GNUNET_MYSQL_StatementHandle *sh)
Prepare a statement for running.
Definition: mysql.c:438
#define _(String)
GNU gettext support macro.
Definition: platform.h:177
Mysql context.
Definition: mysql.c:77
MYSQL * dbf
Handle to the mysql database.
Definition: mysql.c:91
const struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
Definition: mysql.c:81
const char * section
Our section.
Definition: mysql.c:86
struct GNUNET_MYSQL_StatementHandle * stail
Tail of list of our prepared statements.
Definition: mysql.c:101
struct GNUNET_MYSQL_StatementHandle * shead
Head of list of our prepared statements.
Definition: mysql.c:96
char * cnffile
Filename of "my.cnf" (msyql configuration).
Definition: mysql.c:106
Handle for a prepared statement.
Definition: mysql.c:114
struct GNUNET_MYSQL_StatementHandle * prev
Kept in a DLL.
Definition: mysql.c:123
struct GNUNET_MYSQL_StatementHandle * next
Kept in a DLL.
Definition: mysql.c:118
char * query
Original query string.
Definition: mysql.c:133
MYSQL_STMT * statement
Handle to MySQL prepared statement.
Definition: mysql.c:138
struct GNUNET_MYSQL_Context * mc
Mysql Context the statement handle belongs to.
Definition: mysql.c:128
int valid
Is the MySQL prepared statement valid, or do we need to re-initialize it?
Definition: mysql.c:143
struct GNUNET_CONFIGURATION_Handle * cfg
The configuration to use while connecting to controller.
Definition: testbed_api.h:213