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 
77 {
78 
83 
87  const char *section;
88 
92  MYSQL *dbf;
93 
98 
103 
107  char *cnffile;
108 };
109 
110 
115 {
116 
121 
126 
131 
135  char *query;
136 
140  MYSQL_STMT *statement;
141 
145  int valid;
146 };
147 
148 
156 static char *
158  const char *section)
159 {
160  char *cnffile;
161  char *home_dir;
162  struct stat st;
163 
164 #ifndef WINDOWS
165  struct passwd *pw;
166 #endif
167  int configured;
168 
169 #ifndef WINDOWS
170  pw = getpwuid (getuid ());
171  if (! pw)
172  {
173  GNUNET_log_from_strerror (GNUNET_ERROR_TYPE_ERROR, "mysql", "getpwuid");
174  return NULL;
175  }
176  if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (cfg, section, "CONFIG"))
177  {
180  section,
181  "CONFIG",
182  &cnffile));
183  configured = GNUNET_YES;
184  }
185  else
186  {
187  home_dir = GNUNET_strdup (pw->pw_dir);
188  GNUNET_asprintf (&cnffile, "%s/.my.cnf", home_dir);
189  GNUNET_free (home_dir);
190  configured = GNUNET_NO;
191  }
192 #else
193  home_dir = (char *) GNUNET_malloc (_MAX_PATH + 1);
194  plibc_conv_to_win_path ("~/", home_dir);
195  GNUNET_asprintf (&cnffile, "%s/.my.cnf", home_dir);
196  GNUNET_free (home_dir);
197  configured = GNUNET_NO;
198 #endif
200  "mysql",
201  _ ("Trying to use file `%s' for MySQL configuration.\n"),
202  cnffile);
203  if ((0 != STAT (cnffile, &st)) || (0 != ACCESS (cnffile, R_OK)) ||
204  (! S_ISREG (st.st_mode)))
205  {
206  if (configured == GNUNET_YES)
208  "mysql",
209  _ ("Could not access file `%s': %s\n"),
210  cnffile,
211  STRERROR (errno));
212  GNUNET_free (cnffile);
213  return NULL;
214  }
215  return cnffile;
216 }
217 
218 
226 static int
228 {
229  char *mysql_dbname;
230  char *mysql_server;
231  char *mysql_user;
232  char *mysql_password;
233  unsigned long long mysql_port;
234  my_bool reconnect;
235  unsigned int timeout;
236 
237  mc->dbf = mysql_init (NULL);
238  if (mc->dbf == NULL)
239  return GNUNET_SYSERR;
240  if (mc->cnffile != NULL)
241  mysql_options (mc->dbf, MYSQL_READ_DEFAULT_FILE, mc->cnffile);
242  mysql_options (mc->dbf, MYSQL_READ_DEFAULT_GROUP, "client");
243  reconnect = 0;
244  mysql_options (mc->dbf, MYSQL_OPT_RECONNECT, &reconnect);
245  mysql_options (mc->dbf, MYSQL_OPT_CONNECT_TIMEOUT, (const void *) &timeout);
246  mysql_options (mc->dbf, MYSQL_SET_CHARSET_NAME, "UTF8");
247  timeout = 60; /* in seconds */
248  mysql_options (mc->dbf, MYSQL_OPT_READ_TIMEOUT, (const void *) &timeout);
249  mysql_options (mc->dbf, MYSQL_OPT_WRITE_TIMEOUT, (const void *) &timeout);
250  mysql_dbname = NULL;
251  if (GNUNET_YES ==
252  GNUNET_CONFIGURATION_have_value (mc->cfg, mc->section, "DATABASE"))
255  mc->section,
256  "DATABASE",
257  &mysql_dbname));
258  else
259  mysql_dbname = GNUNET_strdup ("gnunet");
260  mysql_user = NULL;
261  if (GNUNET_YES ==
262  GNUNET_CONFIGURATION_have_value (mc->cfg, mc->section, "USER"))
263  {
266  mc->section,
267  "USER",
268  &mysql_user));
269  }
270  mysql_password = NULL;
271  if (GNUNET_YES ==
272  GNUNET_CONFIGURATION_have_value (mc->cfg, mc->section, "PASSWORD"))
273  {
276  mc->section,
277  "PASSWORD",
278  &mysql_password));
279  }
280  mysql_server = NULL;
281  if (GNUNET_YES ==
282  GNUNET_CONFIGURATION_have_value (mc->cfg, mc->section, "HOST"))
283  {
286  mc->section,
287  "HOST",
288  &mysql_server));
289  }
290  mysql_port = 0;
291  if (GNUNET_YES ==
292  GNUNET_CONFIGURATION_have_value (mc->cfg, mc->section, "PORT"))
293  {
296  mc->section,
297  "PORT",
298  &mysql_port));
299  }
300 
301  GNUNET_assert (mysql_dbname != NULL);
302  mysql_real_connect (mc->dbf,
303  mysql_server,
304  mysql_user,
305  mysql_password,
306  mysql_dbname,
307  (unsigned int) mysql_port,
308  NULL,
309  CLIENT_IGNORE_SIGPIPE);
310  GNUNET_free_non_null (mysql_server);
311  GNUNET_free_non_null (mysql_user);
312  GNUNET_free_non_null (mysql_password);
313  GNUNET_free (mysql_dbname);
314  if (mysql_error (mc->dbf)[0])
315  {
316  LOG_MYSQL (GNUNET_ERROR_TYPE_ERROR, "mysql_real_connect", mc);
317  return GNUNET_SYSERR;
318  }
319  return GNUNET_OK;
320 }
321 
322 
330 struct GNUNET_MYSQL_Context *
332  const char *section)
333 {
334  struct GNUNET_MYSQL_Context *mc;
335 
336  mc = GNUNET_new (struct GNUNET_MYSQL_Context);
337  mc->cfg = cfg;
338  mc->section = section;
339  mc->cnffile = get_my_cnf_path (cfg, section);
340 
341  return mc;
342 }
343 
344 
351 void
353 {
355 
356  for (sh = mc->shead; NULL != sh; sh = sh->next)
357  {
358  if (GNUNET_YES == sh->valid)
359  {
360  mysql_stmt_close (sh->statement);
361  sh->valid = GNUNET_NO;
362  }
363  sh->statement = NULL;
364  }
365  if (NULL != mc->dbf)
366  {
367  mysql_close (mc->dbf);
368  mc->dbf = NULL;
369  }
370 }
371 
372 
378 void
380 {
382 
384  while (NULL != (sh = mc->shead))
385  {
386  GNUNET_CONTAINER_DLL_remove (mc->shead, mc->stail, sh);
387  GNUNET_free (sh->query);
388  GNUNET_free (sh);
389  }
390  GNUNET_free (mc);
391  mysql_library_end ();
392 }
393 
394 
405  const char *query)
406 {
408 
410  sh->mc = mc;
411  sh->query = GNUNET_strdup (query);
412  GNUNET_CONTAINER_DLL_insert (mc->shead, mc->stail, sh);
413  return sh;
414 }
415 
416 
425 int
427 {
428  if ((NULL == mc->dbf) && (GNUNET_OK != iopen (mc)))
429  return GNUNET_SYSERR;
430  mysql_query (mc->dbf, sql);
431  if (mysql_error (mc->dbf)[0])
432  {
433  LOG_MYSQL (GNUNET_ERROR_TYPE_ERROR, "mysql_query", mc);
435  return GNUNET_SYSERR;
436  }
437  return GNUNET_OK;
438 }
439 
440 
448 static int
450 {
451  struct GNUNET_MYSQL_Context *mc = sh->mc;
452 
453  if (GNUNET_YES == sh->valid)
454  return GNUNET_OK;
455  if ((NULL == mc->dbf) && (GNUNET_OK != iopen (mc)))
456  return GNUNET_SYSERR;
457  sh->statement = mysql_stmt_init (mc->dbf);
458  if (NULL == sh->statement)
459  {
461  return GNUNET_SYSERR;
462  }
463  if (0 != mysql_stmt_prepare (sh->statement, sh->query, strlen (sh->query)))
464  {
466  "mysql",
467  "prepare_statement: %s\n",
468  sh->query);
469  LOG_MYSQL (GNUNET_ERROR_TYPE_ERROR, "mysql_stmt_prepare", mc);
470  mysql_stmt_close (sh->statement);
471  sh->statement = NULL;
473  return GNUNET_SYSERR;
474  }
475  sh->valid = GNUNET_YES;
476  return GNUNET_OK;
477 }
478 
479 
488 MYSQL_STMT *
490 {
491  (void) prepare_statement (sh);
492  return sh->statement;
493 }
494 
495 
496 /* 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:331
#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:140
#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:125
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define STRERROR(i)
Definition: plibc.h:676
char * query
Original query string.
Definition: mysql.c:135
char * cnffile
Filename of "my.cnf" (msyql configuration).
Definition: mysql.c:107
#define GNUNET_NO
Definition: gnunet_common.h:81
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:78
#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:114
#define STAT(p, b)
Definition: plibc.h:663
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define _(String)
GNU gettext support macro.
Definition: platform.h:208
const struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
Definition: mysql.c:82
static int prepare_statement(struct GNUNET_MYSQL_StatementHandle *sh)
Prepare a statement for running.
Definition: mysql.c:449
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:379
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:489
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:352
int valid
Is the MySQL prepared statement valid, or do we need to re-initialize it?
Definition: mysql.c:145
int plibc_conv_to_win_path(const char *pszUnix, char *pszWindows)
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:92
#define GNUNET_SYSERR
Definition: gnunet_common.h:79
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:404
static char * get_my_cnf_path(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section)
Obtain the location of ".my.cnf".
Definition: mysql.c:157
struct GNUNET_MYSQL_Context * mc
Mysql Context the statement handle belongs to.
Definition: mysql.c:130
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:426
struct GNUNET_MYSQL_StatementHandle * stail
Tail of list of our prepared statements.
Definition: mysql.c:102
const char * section
Our section.
Definition: mysql.c:87
#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:80
struct GNUNET_MYSQL_StatementHandle * next
Kept in a DLL.
Definition: mysql.c:120
static int iopen(struct GNUNET_MYSQL_Context *mc)
Open the connection with the database (and initialize our default options).
Definition: mysql.c:227
#define GNUNET_log_from(kind, comp,...)
#define ACCESS(p, m)
Definition: plibc.h:656
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_free(ptr)
Wrapper around free.
struct GNUNET_MYSQL_StatementHandle * shead
Head of list of our prepared statements.
Definition: mysql.c:97