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 738659864..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
29/**
30 * Maximum number of supported parameters for a prepared
31 * statement. Increase if needed.
32 */
33#define MAX_PARAM 16
34
35
36/**
37 * Die with an error message that indicates
38 * a failure of the command 'cmd' with the message given
39 * by strerror(errno).
40 */
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
54/**
55 * Log an error message at log-level 'level' that indicates
56 * a failure of the command 'cmd' on file 'filename'
57 * with the message given by strerror(errno).
58 */
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
72/**
73 * Mysql context.
74 */
75struct GNUNET_MYSQL_Context
76{
77 /**
78 * Our configuration.
79 */
80 const struct GNUNET_CONFIGURATION_Handle *cfg;
81
82 /**
83 * Our section.
84 */
85 const char *section;
86
87 /**
88 * Handle to the mysql database.
89 */
90 MYSQL *dbf;
91
92 /**
93 * Head of list of our prepared statements.
94 */
95 struct GNUNET_MYSQL_StatementHandle *shead;
96
97 /**
98 * Tail of list of our prepared statements.
99 */
100 struct GNUNET_MYSQL_StatementHandle *stail;
101
102 /**
103 * Filename of "my.cnf" (msyql configuration).
104 */
105 char *cnffile;
106};
107
108
109/**
110 * Handle for a prepared statement.
111 */
112struct GNUNET_MYSQL_StatementHandle
113{
114 /**
115 * Kept in a DLL.
116 */
117 struct GNUNET_MYSQL_StatementHandle *next;
118
119 /**
120 * Kept in a DLL.
121 */
122 struct GNUNET_MYSQL_StatementHandle *prev;
123
124 /**
125 * Mysql Context the statement handle belongs to.
126 */
127 struct GNUNET_MYSQL_Context *mc;
128
129 /**
130 * Original query string.
131 */
132 char *query;
133
134 /**
135 * Handle to MySQL prepared statement.
136 */
137 MYSQL_STMT *statement;
138
139 /**
140 * Is the MySQL prepared statement valid, or do we need to re-initialize it?
141 */
142 int valid;
143};
144
145
146/**
147 * Obtain the location of ".my.cnf".
148 *
149 * @param cfg our configuration
150 * @param section the section
151 * @return NULL on error
152 */
153static char *
154get_my_cnf_path (const struct GNUNET_CONFIGURATION_Handle *cfg,
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 {
173 GNUNET_assert (GNUNET_OK ==
174 GNUNET_CONFIGURATION_get_value_filename (cfg,
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
188 GNUNET_log_from (GNUNET_ERROR_TYPE_INFO,
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)
196 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
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
208/**
209 * Open the connection with the database (and initialize
210 * our default options).
211 *
212 * @param mc database context to initialize
213 * @return #GNUNET_OK on success
214 */
215static int
216iopen (struct GNUNET_MYSQL_Context *mc)
217{
218 char *mysql_dbname;
219 char *mysql_server;
220 char *mysql_user;
221 char *mysql_password;
222 unsigned long long mysql_port;
223 MYSQL_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"))
242 GNUNET_assert (GNUNET_OK ==
243 GNUNET_CONFIGURATION_get_value_string (mc->cfg,
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 {
253 GNUNET_assert (GNUNET_OK ==
254 GNUNET_CONFIGURATION_get_value_string (mc->cfg,
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 {
263 GNUNET_assert (GNUNET_OK ==
264 GNUNET_CONFIGURATION_get_value_string (mc->cfg,
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 {
273 GNUNET_assert (GNUNET_OK ==
274 GNUNET_CONFIGURATION_get_value_string (mc->cfg,
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 {
283 GNUNET_assert (GNUNET_OK ==
284 GNUNET_CONFIGURATION_get_value_number (mc->cfg,
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 (mysql_server);
300 GNUNET_free (mysql_user);
301 GNUNET_free (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
312/**
313 * Create a mysql context.
314 *
315 * @param cfg configuration
316 * @param section configuration section to use to get MySQL configuration options
317 * @return the mysql context
318 */
319struct GNUNET_MYSQL_Context *
320GNUNET_MYSQL_context_create (const struct GNUNET_CONFIGURATION_Handle *cfg,
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
334/**
335 * Close database connection and all prepared statements (we got a DB
336 * error).
337 *
338 * @param mc mysql context
339 */
340void
341GNUNET_MYSQL_statements_invalidate (struct GNUNET_MYSQL_Context *mc)
342{
343 struct GNUNET_MYSQL_StatementHandle *sh;
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
362/**
363 * Destroy a mysql context. Also frees all associated prepared statements.
364 *
365 * @param mc context to destroy
366 */
367void
368GNUNET_MYSQL_context_destroy (struct GNUNET_MYSQL_Context *mc)
369{
370 struct GNUNET_MYSQL_StatementHandle *sh;
371
372 GNUNET_MYSQL_statements_invalidate (mc);
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
384/**
385 * Prepare a statement. Prepared statements are automatically discarded
386 * when the MySQL context is destroyed.
387 *
388 * @param mc mysql context
389 * @param query query text
390 * @return prepared statement, NULL on error
391 */
392struct GNUNET_MYSQL_StatementHandle *
393GNUNET_MYSQL_statement_prepare (struct GNUNET_MYSQL_Context *mc,
394 const char *query)
395{
396 struct GNUNET_MYSQL_StatementHandle *sh;
397
398 sh = GNUNET_new (struct GNUNET_MYSQL_StatementHandle);
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
406/**
407 * Run a SQL statement.
408 *
409 * @param mc mysql context
410 * @param sql SQL statement to run
411 * @return #GNUNET_OK on success
412 * #GNUNET_SYSERR if there was a problem
413 */
414int
415GNUNET_MYSQL_statement_run (struct GNUNET_MYSQL_Context *mc, const char *sql)
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);
423 GNUNET_MYSQL_statements_invalidate (mc);
424 return GNUNET_SYSERR;
425 }
426 return GNUNET_OK;
427}
428
429
430/**
431 * Prepare a statement for running.
432 *
433 * @param mc mysql context
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 */