GNUnet  0.10.x
mysql.c
Go to the documentation of this file.
1 
2 /*
3  This file is part of GNUnet
4  Copyright (C) 2012 GNUnet e.V.
5 
6  GNUnet is free software: you can redistribute it and/or modify it
7  under the terms of the GNU Affero General Public License as published
8  by the Free Software Foundation, either version 3 of the License,
9  or (at your option) any later version.
10 
11  GNUnet is distributed in the hope that it will be useful, but
12  WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  Affero General Public License for more details.
15 
16  You should have received a copy of the GNU Affero General Public License
17  along with this program. If not, see <http://www.gnu.org/licenses/>.
18 
19  SPDX-License-Identifier: AGPL3.0-or-later
20  */
26 #include "platform.h"
27 #include <mysql/mysql.h>
28 #include "gnunet_mysql_lib.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 
81 
85  const char *section;
86 
90  MYSQL *dbf;
91 
96 
101 
105  char *cnffile;
106 };
107 
108 
117 
122 
127 
131  char *query;
132 
136  MYSQL_STMT *statement;
137 
141  int valid;
142 };
143 
144 
152 static char *
154  const char *section)
155 {
156  char *cnffile;
157  char *home_dir;
158  struct stat st;
159 
160  struct passwd *pw;
161 
162  int configured;
163 
164  pw = getpwuid(getuid());
165  if (!pw)
166  {
168  return NULL;
169  }
170  if (GNUNET_YES == GNUNET_CONFIGURATION_have_value(cfg, section, "CONFIG"))
171  {
174  section,
175  "CONFIG",
176  &cnffile));
177  configured = GNUNET_YES;
178  }
179  else
180  {
181  home_dir = GNUNET_strdup(pw->pw_dir);
182  GNUNET_asprintf(&cnffile, "%s/.my.cnf", home_dir);
183  GNUNET_free(home_dir);
184  configured = GNUNET_NO;
185  }
186 
188  "mysql",
189  _("Trying to use file `%s' for MySQL configuration.\n"),
190  cnffile);
191  if ((0 != stat(cnffile, &st)) || (0 != access(cnffile, R_OK)) ||
192  (!S_ISREG(st.st_mode)))
193  {
194  if (configured == GNUNET_YES)
196  "mysql",
197  _("Could not access file `%s': %s\n"),
198  cnffile,
199  strerror(errno));
200  GNUNET_free(cnffile);
201  return NULL;
202  }
203  return cnffile;
204 }
205 
206 
214 static int
216 {
217  char *mysql_dbname;
218  char *mysql_server;
219  char *mysql_user;
220  char *mysql_password;
221  unsigned long long mysql_port;
222  my_bool reconnect;
223  unsigned int timeout;
224 
225  mc->dbf = mysql_init(NULL);
226  if (mc->dbf == NULL)
227  return GNUNET_SYSERR;
228  if (mc->cnffile != NULL)
229  mysql_options(mc->dbf, MYSQL_READ_DEFAULT_FILE, mc->cnffile);
230  mysql_options(mc->dbf, MYSQL_READ_DEFAULT_GROUP, "client");
231  reconnect = 0;
232  mysql_options(mc->dbf, MYSQL_OPT_RECONNECT, &reconnect);
233  mysql_options(mc->dbf, MYSQL_OPT_CONNECT_TIMEOUT, (const void *)&timeout);
234  mysql_options(mc->dbf, MYSQL_SET_CHARSET_NAME, "UTF8");
235  timeout = 60; /* in seconds */
236  mysql_options(mc->dbf, MYSQL_OPT_READ_TIMEOUT, (const void *)&timeout);
237  mysql_options(mc->dbf, MYSQL_OPT_WRITE_TIMEOUT, (const void *)&timeout);
238  mysql_dbname = NULL;
239  if (GNUNET_YES ==
240  GNUNET_CONFIGURATION_have_value(mc->cfg, mc->section, "DATABASE"))
243  mc->section,
244  "DATABASE",
245  &mysql_dbname));
246  else
247  mysql_dbname = GNUNET_strdup("gnunet");
248  mysql_user = NULL;
249  if (GNUNET_YES ==
250  GNUNET_CONFIGURATION_have_value(mc->cfg, mc->section, "USER"))
251  {
254  mc->section,
255  "USER",
256  &mysql_user));
257  }
258  mysql_password = NULL;
259  if (GNUNET_YES ==
260  GNUNET_CONFIGURATION_have_value(mc->cfg, mc->section, "PASSWORD"))
261  {
264  mc->section,
265  "PASSWORD",
266  &mysql_password));
267  }
268  mysql_server = NULL;
269  if (GNUNET_YES ==
270  GNUNET_CONFIGURATION_have_value(mc->cfg, mc->section, "HOST"))
271  {
274  mc->section,
275  "HOST",
276  &mysql_server));
277  }
278  mysql_port = 0;
279  if (GNUNET_YES ==
280  GNUNET_CONFIGURATION_have_value(mc->cfg, mc->section, "PORT"))
281  {
284  mc->section,
285  "PORT",
286  &mysql_port));
287  }
288 
289  GNUNET_assert(mysql_dbname != NULL);
290  mysql_real_connect(mc->dbf,
291  mysql_server,
292  mysql_user,
293  mysql_password,
294  mysql_dbname,
295  (unsigned int)mysql_port,
296  NULL,
297  CLIENT_IGNORE_SIGPIPE);
298  GNUNET_free_non_null(mysql_server);
299  GNUNET_free_non_null(mysql_user);
300  GNUNET_free_non_null(mysql_password);
301  GNUNET_free(mysql_dbname);
302  if (mysql_error(mc->dbf)[0])
303  {
304  LOG_MYSQL(GNUNET_ERROR_TYPE_ERROR, "mysql_real_connect", mc);
305  return GNUNET_SYSERR;
306  }
307  return GNUNET_OK;
308 }
309 
310 
318 struct GNUNET_MYSQL_Context *
320  const char *section)
321 {
322  struct GNUNET_MYSQL_Context *mc;
323 
324  mc = GNUNET_new(struct GNUNET_MYSQL_Context);
325  mc->cfg = cfg;
326  mc->section = section;
327  mc->cnffile = get_my_cnf_path(cfg, section);
328 
329  return mc;
330 }
331 
332 
339 void
341 {
343 
344  for (sh = mc->shead; NULL != sh; sh = sh->next)
345  {
346  if (GNUNET_YES == sh->valid)
347  {
348  mysql_stmt_close(sh->statement);
349  sh->valid = GNUNET_NO;
350  }
351  sh->statement = NULL;
352  }
353  if (NULL != mc->dbf)
354  {
355  mysql_close(mc->dbf);
356  mc->dbf = NULL;
357  }
358 }
359 
360 
366 void
368 {
370 
372  while (NULL != (sh = mc->shead))
373  {
375  GNUNET_free(sh->query);
376  GNUNET_free(sh);
377  }
378  GNUNET_free(mc);
379  mysql_library_end();
380 }
381 
382 
393  const char *query)
394 {
396 
398  sh->mc = mc;
399  sh->query = GNUNET_strdup(query);
401  return sh;
402 }
403 
404 
413 int
415 {
416  if ((NULL == mc->dbf) && (GNUNET_OK != iopen(mc)))
417  return GNUNET_SYSERR;
418  mysql_query(mc->dbf, sql);
419  if (mysql_error(mc->dbf)[0])
420  {
421  LOG_MYSQL(GNUNET_ERROR_TYPE_ERROR, "mysql_query", mc);
423  return GNUNET_SYSERR;
424  }
425  return GNUNET_OK;
426 }
427 
428 
436 static int
438 {
439  struct GNUNET_MYSQL_Context *mc = sh->mc;
440 
441  if (GNUNET_YES == sh->valid)
442  return GNUNET_OK;
443  if ((NULL == mc->dbf) && (GNUNET_OK != iopen(mc)))
444  return GNUNET_SYSERR;
445  sh->statement = mysql_stmt_init(mc->dbf);
446  if (NULL == sh->statement)
447  {
449  return GNUNET_SYSERR;
450  }
451  if (0 != mysql_stmt_prepare(sh->statement, sh->query, strlen(sh->query)))
452  {
454  "mysql",
455  "prepare_statement: %s\n",
456  sh->query);
457  LOG_MYSQL(GNUNET_ERROR_TYPE_ERROR, "mysql_stmt_prepare", mc);
458  mysql_stmt_close(sh->statement);
459  sh->statement = NULL;
461  return GNUNET_SYSERR;
462  }
463  sh->valid = GNUNET_YES;
464  return GNUNET_OK;
465 }
466 
467 
476 MYSQL_STMT *
478 {
479  (void)prepare_statement(sh);
480  return sh->statement;
481 }
482 
483 
484 /* end of mysql.c */
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
static void reconnect(struct GNUNET_ATS_ApplicationHandle *ch)
Re-establish the connection to the ATS service.
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:319
#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:136
#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:121
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
char * query
Original query string.
Definition: mysql.c:131
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:437
int GNUNET_asprintf(char **buf, const char *format,...)
Like asprintf, just portable.
static struct GNUNET_TIME_Relative timeout
User defined timestamp for completing operations.
Definition: gnunet-arm.c:114
void GNUNET_MYSQL_context_destroy(struct GNUNET_MYSQL_Context *mc)
Destroy a mysql context.
Definition: mysql.c:367
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:477
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:340
int valid
Is the MySQL prepared statement valid, or do we need to re-initialize it?
Definition: mysql.c:141
static struct GNUNET_TESTBED_Controller * mc
Handle to the master controller.
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:76
struct GNUNET_MYSQL_StatementHandle * GNUNET_MYSQL_statement_prepare(struct GNUNET_MYSQL_Context *mc, const char *query)
Prepare a statement.
Definition: mysql.c:392
static char * get_my_cnf_path(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section)
Obtain the location of ".my.cnf".
Definition: mysql.c:153
struct GNUNET_MYSQL_Context * mc
Mysql Context the statement handle belongs to.
Definition: mysql.c:126
configuration data
Definition: configuration.c:83
int GNUNET_MYSQL_statement_run(struct GNUNET_MYSQL_Context *mc, const char *sql)
Run a SQL statement.
Definition: mysql.c:414
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:60
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:116
static int iopen(struct GNUNET_MYSQL_Context *mc)
Open the connection with the database (and initialize our default options).
Definition: mysql.c:215
#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