aboutsummaryrefslogtreecommitdiff
path: root/src/mysql/mysql.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mysql/mysql.c')
-rw-r--r--src/mysql/mysql.c485
1 files changed, 0 insertions, 485 deletions
diff --git a/src/mysql/mysql.c b/src/mysql/mysql.c
deleted file mode 100644
index 056c2f07f..000000000
--- a/src/mysql/mysql.c
+++ /dev/null
@@ -1,485 +0,0 @@
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 */
20/**
21 * @file mysql/mysql.c
22 * @brief library to help with access to a MySQL database
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include <mysql/mysql.h>
27#include "gnunet_mysql_lib.h"
28#include "gnunet_mysql_compat.h"
29
30/**
31 * Maximum number of supported parameters for a prepared
32 * statement. Increase if needed.
33 */
34#define MAX_PARAM 16
35
36
37/**
38 * Die with an error message that indicates
39 * a failure of the command 'cmd' with the message given
40 * by strerror(errno).
41 */
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
55/**
56 * Log an error message at log-level 'level' that indicates
57 * a failure of the command 'cmd' on file 'filename'
58 * with the message given by strerror(errno).
59 */
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
73/**
74 * Mysql context.
75 */
76struct GNUNET_MYSQL_Context
77{
78 /**
79 * Our configuration.
80 */
81 const struct GNUNET_CONFIGURATION_Handle *cfg;
82
83 /**
84 * Our section.
85 */
86 const char *section;
87
88 /**
89 * Handle to the mysql database.
90 */
91 MYSQL *dbf;
92
93 /**
94 * Head of list of our prepared statements.
95 */
96 struct GNUNET_MYSQL_StatementHandle *shead;
97
98 /**
99 * Tail of list of our prepared statements.
100 */
101 struct GNUNET_MYSQL_StatementHandle *stail;
102
103 /**
104 * Filename of "my.cnf" (msyql configuration).
105 */
106 char *cnffile;
107};
108
109
110/**
111 * Handle for a prepared statement.
112 */
113struct GNUNET_MYSQL_StatementHandle
114{
115 /**
116 * Kept in a DLL.
117 */
118 struct GNUNET_MYSQL_StatementHandle *next;
119
120 /**
121 * Kept in a DLL.
122 */
123 struct GNUNET_MYSQL_StatementHandle *prev;
124
125 /**
126 * Mysql Context the statement handle belongs to.
127 */
128 struct GNUNET_MYSQL_Context *mc;
129
130 /**
131 * Original query string.
132 */
133 char *query;
134
135 /**
136 * Handle to MySQL prepared statement.
137 */
138 MYSQL_STMT *statement;
139
140 /**
141 * Is the MySQL prepared statement valid, or do we need to re-initialize it?
142 */
143 int valid;
144};
145
146
147/**
148 * Obtain the location of ".my.cnf".
149 *
150 * @param cfg our configuration
151 * @param section the section
152 * @return NULL on error
153 */
154static char *
155get_my_cnf_path (const struct GNUNET_CONFIGURATION_Handle *cfg,
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 {
174 GNUNET_assert (GNUNET_OK ==
175 GNUNET_CONFIGURATION_get_value_filename (cfg,
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
189 GNUNET_log_from (GNUNET_ERROR_TYPE_INFO,
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)
197 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
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
209/**
210 * Open the connection with the database (and initialize
211 * our default options).
212 *
213 * @param mc database context to initialize
214 * @return #GNUNET_OK on success
215 */
216static int
217iopen (struct GNUNET_MYSQL_Context *mc)
218{
219 char *mysql_dbname;
220 char *mysql_server;
221 char *mysql_user;
222 char *mysql_password;
223 unsigned long long mysql_port;
224 MYSQL_BOOL reconnect;
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"))
243 GNUNET_assert (GNUNET_OK ==
244 GNUNET_CONFIGURATION_get_value_string (mc->cfg,
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 {
254 GNUNET_assert (GNUNET_OK ==
255 GNUNET_CONFIGURATION_get_value_string (mc->cfg,
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 {
264 GNUNET_assert (GNUNET_OK ==
265 GNUNET_CONFIGURATION_get_value_string (mc->cfg,
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 {
274 GNUNET_assert (GNUNET_OK ==
275 GNUNET_CONFIGURATION_get_value_string (mc->cfg,
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 {
284 GNUNET_assert (GNUNET_OK ==
285 GNUNET_CONFIGURATION_get_value_number (mc->cfg,
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
313/**
314 * Create a mysql context.
315 *
316 * @param cfg configuration
317 * @param section configuration section to use to get MySQL configuration options
318 * @return the mysql context
319 */
320struct GNUNET_MYSQL_Context *
321GNUNET_MYSQL_context_create (const struct GNUNET_CONFIGURATION_Handle *cfg,
322 const char *section)
323{
324 struct GNUNET_MYSQL_Context *mc;
325
326 mc = GNUNET_new (struct GNUNET_MYSQL_Context);
327 mc->cfg = cfg;
328 mc->section = section;
329 mc->cnffile = get_my_cnf_path (cfg, section);
330
331 return mc;
332}
333
334
335/**
336 * Close database connection and all prepared statements (we got a DB
337 * error).
338 *
339 * @param mc mysql context
340 */
341void
342GNUNET_MYSQL_statements_invalidate (struct GNUNET_MYSQL_Context *mc)
343{
344 struct GNUNET_MYSQL_StatementHandle *sh;
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
363/**
364 * Destroy a mysql context. Also frees all associated prepared statements.
365 *
366 * @param mc context to destroy
367 */
368void
369GNUNET_MYSQL_context_destroy (struct GNUNET_MYSQL_Context *mc)
370{
371 struct GNUNET_MYSQL_StatementHandle *sh;
372
373 GNUNET_MYSQL_statements_invalidate (mc);
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
385/**
386 * Prepare a statement. Prepared statements are automatically discarded
387 * when the MySQL context is destroyed.
388 *
389 * @param mc mysql context
390 * @param query query text
391 * @return prepared statement, NULL on error
392 */
393struct GNUNET_MYSQL_StatementHandle *
394GNUNET_MYSQL_statement_prepare (struct GNUNET_MYSQL_Context *mc,
395 const char *query)
396{
397 struct GNUNET_MYSQL_StatementHandle *sh;
398
399 sh = GNUNET_new (struct GNUNET_MYSQL_StatementHandle);
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
407/**
408 * Run a SQL statement.
409 *
410 * @param mc mysql context
411 * @param sql SQL statement to run
412 * @return #GNUNET_OK on success
413 * #GNUNET_SYSERR if there was a problem
414 */
415int
416GNUNET_MYSQL_statement_run (struct GNUNET_MYSQL_Context *mc, const char *sql)
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);
424 GNUNET_MYSQL_statements_invalidate (mc);
425 return GNUNET_SYSERR;
426 }
427 return GNUNET_OK;
428}
429
430
431/**
432 * Prepare a statement for running.
433 *
434 * @param sh statement handle to prepare
435 * @return #GNUNET_OK on success
436 */
437static int
438prepare_statement (struct GNUNET_MYSQL_StatementHandle *sh)
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 {
449 GNUNET_MYSQL_statements_invalidate (mc);
450 return GNUNET_SYSERR;
451 }
452 if (0 != mysql_stmt_prepare (sh->statement, sh->query, strlen (sh->query)))
453 {
454 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
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;
461 GNUNET_MYSQL_statements_invalidate (mc);
462 return GNUNET_SYSERR;
463 }
464 sh->valid = GNUNET_YES;
465 return GNUNET_OK;
466}
467
468
469/**
470 * Get internal handle for a prepared statement. This function should rarely
471 * be used, and if, with caution! On failures during the interaction with
472 * the handle, you must call 'GNUNET_MYSQL_statements_invalidate'!
473 *
474 * @param sh prepared statement to introspect
475 * @return MySQL statement handle, NULL on error
476 */
477MYSQL_STMT *
478GNUNET_MYSQL_statement_get_stmt (struct GNUNET_MYSQL_StatementHandle *sh)
479{
480 (void) prepare_statement (sh);
481 return sh->statement;
482}
483
484
485/* end of mysql.c */