|
@@ -1,184 +1,295 @@
|
|
|
/*
|
|
|
* $Id$
|
|
|
*
|
|
|
- * Flastore module connection structure
|
|
|
+ * Copyright (C) 2004 FhG FOKUS
|
|
|
+ * Copyright (C) 2008 iptelorg GmbH
|
|
|
+ * Written by Jan Janak <[email protected]>
|
|
|
*
|
|
|
- * Copyright (C) 2004 FhG Fokus
|
|
|
+ * This file is part of SER, a free SIP server.
|
|
|
*
|
|
|
- * This file is part of ser, a free SIP server.
|
|
|
+ * SER is free software; you can redistribute it and/or modify it under the
|
|
|
+ * terms of the GNU General Public License as published by the Free Software
|
|
|
+ * Foundation; either version 2 of the License, or (at your option) any later
|
|
|
+ * version.
|
|
|
*
|
|
|
- * ser is free software; you can redistribute it and/or modify
|
|
|
- * it under the terms of the GNU General Public License as published by
|
|
|
- * the Free Software Foundation; either version 2 of the License, or
|
|
|
- * (at your option) any later version
|
|
|
+ * SER is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
|
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
|
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
|
+ * details.
|
|
|
*
|
|
|
- * For a license to use the ser software under conditions
|
|
|
- * other than those described here, or to purchase support for this
|
|
|
- * software, please contact iptel.org by e-mail at the following addresses:
|
|
|
- * [email protected]
|
|
|
- *
|
|
|
- * ser is distributed in the hope that it will be useful,
|
|
|
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
- * GNU General Public License for more details.
|
|
|
- *
|
|
|
- * You should have received a copy of the GNU General Public License
|
|
|
- * along with this program; if not, write to the Free Software
|
|
|
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
+ * You should have received a copy of the GNU General Public License along
|
|
|
+ * with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
*/
|
|
|
|
|
|
-#include <string.h>
|
|
|
-#include <errno.h>
|
|
|
+/** \addtogroup flatstore
|
|
|
+ * @{
|
|
|
+ */
|
|
|
+
|
|
|
+/** \file
|
|
|
+ * Inmplementation of flatstore "connections".
|
|
|
+ */
|
|
|
+
|
|
|
+#include "flat_con.h"
|
|
|
+#include "flatstore_mod.h"
|
|
|
+
|
|
|
#include "../../mem/mem.h"
|
|
|
#include "../../dprint.h"
|
|
|
#include "../../ut.h"
|
|
|
-#include "flatstore_mod.h"
|
|
|
-#include "flat_con.h"
|
|
|
|
|
|
-#define FILE_SUFFIX ".log"
|
|
|
-#define FILE_SUFFIX_LEN (sizeof(FILE_SUFFIX) - 1)
|
|
|
+#include <stdio.h>
|
|
|
+#include <stdlib.h>
|
|
|
+#include <string.h>
|
|
|
+#include <errno.h>
|
|
|
|
|
|
-/* returns a pkg_malloc'ed file name */
|
|
|
-static char* get_name(struct flat_id* id)
|
|
|
+
|
|
|
+/** Free all memory allocated for a flat_con structure.
|
|
|
+ * This function function frees all memory that is in use by
|
|
|
+ * a flat_con structure.
|
|
|
+ * @param con A generic db_con connection structure.
|
|
|
+ * @param payload Flatstore specific payload to be freed.
|
|
|
+ */
|
|
|
+static void flat_con_free(db_con_t* con, struct flat_con* payload)
|
|
|
{
|
|
|
- char* buf;
|
|
|
- int buf_len;
|
|
|
- char* num, *ptr;
|
|
|
- int num_len;
|
|
|
- int total_len;
|
|
|
-
|
|
|
- buf_len=pathmax();
|
|
|
- if (!id) {
|
|
|
- LOG(L_ERR, "get_name: Invalid parameter value\n");
|
|
|
- return 0;
|
|
|
- }
|
|
|
- total_len=id->dir.len+1 /* / */+id->table.len+1 /* _ */+
|
|
|
- FILE_SUFFIX_LEN+1 /* \0 */; /* without pid*/
|
|
|
- if (buf_len<total_len){
|
|
|
- LOG(L_ERR, "get_name: the path is too long (%d and PATHMAX is %d)\n",
|
|
|
- total_len, buf_len);
|
|
|
- return 0;
|
|
|
+ int i;
|
|
|
+ if (!payload) return;
|
|
|
+
|
|
|
+ /* delete the structure only if there are no more references
|
|
|
+ * to it in the connection pool
|
|
|
+ */
|
|
|
+ if (db_pool_remove((db_pool_entry_t*)payload) == 0) return;
|
|
|
+
|
|
|
+ db_pool_entry_free(&payload->gen);
|
|
|
+
|
|
|
+ if (payload->file) {
|
|
|
+ for(i = 0; i < payload->n; i++) {
|
|
|
+ if (payload->file[i].filename) pkg_free(payload->file[i].filename);
|
|
|
+ if (payload->file[i].table.s) pkg_free(payload->file[i].table.s);
|
|
|
+ if (payload->file[i].f) fclose(payload->file[i].f);
|
|
|
+ }
|
|
|
+ pkg_free(payload->file);
|
|
|
}
|
|
|
+ pkg_free(payload);
|
|
|
+}
|
|
|
|
|
|
- buf=pkg_malloc(buf_len);
|
|
|
- if (buf==0){
|
|
|
- LOG(L_ERR, "ERROR: get_name: memory allocation failure\n");
|
|
|
- return 0;
|
|
|
- }
|
|
|
|
|
|
- ptr = buf;
|
|
|
+int flat_con(db_con_t* con)
|
|
|
+{
|
|
|
+ struct flat_con* fcon;
|
|
|
+
|
|
|
+ /* First try to lookup the connection in the connection pool and
|
|
|
+ * re-use it if a match is found
|
|
|
+ */
|
|
|
+ fcon = (struct flat_con*)db_pool_get(con->uri);
|
|
|
+ if (fcon) {
|
|
|
+ DBG("flatstore: A handle to %.*s found in the connection pool\n",
|
|
|
+ STR_FMT(&con->uri->body));
|
|
|
+ goto found;
|
|
|
+ }
|
|
|
|
|
|
- memcpy(ptr, id->dir.s, id->dir.len);
|
|
|
- ptr += id->dir.len;
|
|
|
- *ptr++ = '/';
|
|
|
+ fcon = (struct flat_con*)pkg_malloc(sizeof(struct flat_con));
|
|
|
+ if (fcon == NULL) {
|
|
|
+ ERR("flatstore: No memory left\n");
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ memset(fcon, '\0', sizeof(struct flat_con));
|
|
|
+ if (db_pool_entry_init(&fcon->gen, flat_con_free, con->uri) < 0) goto error;
|
|
|
+
|
|
|
+ DBG("flastore: Preparing new file handles to files in %.*s\n",
|
|
|
+ STR_FMT(&con->uri->body));
|
|
|
+
|
|
|
+ /* Put the newly created flatstore connection into the pool */
|
|
|
+ db_pool_put((struct db_pool_entry*)fcon);
|
|
|
+ DBG("flatstore: Handle stored in connection pool\n");
|
|
|
+
|
|
|
+ found:
|
|
|
+ /* Attach driver payload to the db_con structure and set connect and
|
|
|
+ * disconnect functions
|
|
|
+ */
|
|
|
+ DB_SET_PAYLOAD(con, fcon);
|
|
|
+ con->connect = flat_con_connect;
|
|
|
+ con->disconnect = flat_con_disconnect;
|
|
|
+ return 0;
|
|
|
|
|
|
- memcpy(ptr, id->table.s, id->table.len);
|
|
|
- ptr += id->table.len;
|
|
|
+ error:
|
|
|
+ if (fcon) {
|
|
|
+ db_pool_entry_free(&fcon->gen);
|
|
|
+ pkg_free(fcon);
|
|
|
+ }
|
|
|
+ return -1;
|
|
|
+}
|
|
|
|
|
|
- *ptr++ = '_';
|
|
|
|
|
|
- num = int2str(flat_pid, &num_len);
|
|
|
- if (buf_len<(total_len+num_len)){
|
|
|
- LOG(L_ERR, "ERROR: get_name: the path is too long (%d and PATHMAX is"
|
|
|
- " %d)\n", total_len+num_len, buf_len);
|
|
|
- pkg_free(buf);
|
|
|
- return 0;
|
|
|
+int flat_con_connect(db_con_t* con)
|
|
|
+{
|
|
|
+ struct flat_con* fcon;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ fcon = DB_GET_PAYLOAD(con);
|
|
|
+
|
|
|
+ /* Do not reconnect already connected connections */
|
|
|
+ if (fcon->flags & FLAT_OPENED) return 0;
|
|
|
+
|
|
|
+ DBG("flatstore: Opening handles to files in '%.*s'\n",
|
|
|
+ STR_FMT(&con->uri->body));
|
|
|
+
|
|
|
+ /* FIXME: Make sure the directory exists, is accessible,
|
|
|
+ * and we can create files there
|
|
|
+ */
|
|
|
+
|
|
|
+ DBG("flatstore: Directory '%.*s' opened successfully\n",
|
|
|
+ STR_FMT(&con->uri->body));
|
|
|
+
|
|
|
+ for(i = 0; i < fcon->n; i++) {
|
|
|
+ if (fcon->file[i].f) {
|
|
|
+ fclose(fcon->file[i].f);
|
|
|
+ }
|
|
|
+ fcon->file[i].f = fopen(fcon->file[i].filename, "a");
|
|
|
+ if (fcon->file[i].f == NULL) {
|
|
|
+ ERR("flatstore: Error while opening file handle to '%s': %s\n",
|
|
|
+ fcon->file[i].filename, strerror(errno));
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
}
|
|
|
- memcpy(ptr, num, num_len);
|
|
|
- ptr += num_len;
|
|
|
|
|
|
- memcpy(ptr, FILE_SUFFIX, FILE_SUFFIX_LEN);
|
|
|
- ptr += FILE_SUFFIX_LEN;
|
|
|
+ fcon->flags |= FLAT_OPENED;
|
|
|
+ return 0;
|
|
|
|
|
|
- *ptr = '\0';
|
|
|
- return buf;
|
|
|
}
|
|
|
|
|
|
|
|
|
-struct flat_con* flat_new_connection(struct flat_id* id)
|
|
|
+void flat_con_disconnect(db_con_t* con)
|
|
|
{
|
|
|
- char* fn;
|
|
|
+ struct flat_con* fcon;
|
|
|
+ int i;
|
|
|
|
|
|
- struct flat_con* res;
|
|
|
+ fcon = DB_GET_PAYLOAD(con);
|
|
|
|
|
|
- if (!id) {
|
|
|
- LOG(L_ERR, "flat_new_connection: Invalid parameter value\n");
|
|
|
- return 0;
|
|
|
- }
|
|
|
+ if ((fcon->flags & FLAT_OPENED) == 0) return;
|
|
|
+
|
|
|
+ DBG("flatstore: Closing handles to files in '%.*s'\n",
|
|
|
+ STR_FMT(&con->uri->body));
|
|
|
|
|
|
- res = (struct flat_con*)pkg_malloc(sizeof(struct flat_con));
|
|
|
- if (!res) {
|
|
|
- LOG(L_ERR, "flat_new_connection: No memory left\n");
|
|
|
- return 0;
|
|
|
+ for(i = 0; i < fcon->n; i++) {
|
|
|
+ if (fcon->file[i].f == NULL) continue;
|
|
|
+ fclose(fcon->file[i].f);
|
|
|
+ fcon->file[i].f = NULL;
|
|
|
}
|
|
|
|
|
|
- memset(res, 0, sizeof(struct flat_con));
|
|
|
- res->ref = 1;
|
|
|
+ fcon->flags &= ~FLAT_OPENED;
|
|
|
+}
|
|
|
|
|
|
- res->id = id;
|
|
|
|
|
|
- fn = get_name(id);
|
|
|
- if (fn==0){
|
|
|
- LOG(L_ERR, "flat_new_connection: get_name() failed\n");
|
|
|
- return 0;
|
|
|
- }
|
|
|
+/* returns a pkg_malloc'ed file name */
|
|
|
+static char* get_filename(str* dir, str* name)
|
|
|
+{
|
|
|
+ char* buf, *p;
|
|
|
+ int buf_len, total_len;
|
|
|
|
|
|
- res->file = fopen(fn, "a");
|
|
|
- pkg_free(fn); /* we don't need fn anymore */
|
|
|
- if (!res->file) {
|
|
|
- LOG(L_ERR, "flat_new_connection: %s\n", strerror(errno));
|
|
|
- pkg_free(res);
|
|
|
- return 0;
|
|
|
- }
|
|
|
+ buf_len = pathmax();
|
|
|
|
|
|
- return res;
|
|
|
-}
|
|
|
+ total_len = dir->len + 1 /* / */ +
|
|
|
+ name->len + 1 /* _ */+
|
|
|
+ flat_pid.len +
|
|
|
+ flat_suffix.len + 1 /* \0 */;
|
|
|
|
|
|
+ if (buf_len < total_len) {
|
|
|
+ ERR("flatstore: The path is too long (%d and PATHMAX is %d)\n",
|
|
|
+ total_len, buf_len);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
|
|
|
-/*
|
|
|
- * Close the connection and release memory
|
|
|
- */
|
|
|
-void flat_free_connection(struct flat_con* con)
|
|
|
-{
|
|
|
- if (!con) return;
|
|
|
- if (con->id) free_flat_id(con->id);
|
|
|
- if (con->file) {
|
|
|
- fclose(con->file);
|
|
|
- }
|
|
|
- pkg_free(con);
|
|
|
-}
|
|
|
+ if ((buf = pkg_malloc(buf_len)) == NULL) {
|
|
|
+ ERR("flatstore: No memory left\n");
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ p = buf;
|
|
|
|
|
|
+ memcpy(p, dir->s, dir->len);
|
|
|
+ p += dir->len;
|
|
|
|
|
|
-/*
|
|
|
- * Reopen a connection
|
|
|
- */
|
|
|
-int flat_reopen_connection(struct flat_con* con)
|
|
|
-{
|
|
|
- char* fn;
|
|
|
+ *p++ = '/';
|
|
|
|
|
|
- if (!con) {
|
|
|
- LOG(L_ERR, "flat_reopen_connection: Invalid parameter value\n");
|
|
|
- return -1;
|
|
|
- }
|
|
|
+ memcpy(p, name->s, name->len);
|
|
|
+ *p += name->len;
|
|
|
|
|
|
- if (con->file) {
|
|
|
- fclose(con->file);
|
|
|
- con->file = 0;
|
|
|
+ *p++ = '_';
|
|
|
|
|
|
- fn = get_name(con->id);
|
|
|
- if (fn == 0) {
|
|
|
- LOG(L_ERR, "flat_reopen_connection: get_name() failed\n");
|
|
|
- return -1;
|
|
|
- }
|
|
|
+ memcpy(p, flat_pid.s, flat_pid.len);
|
|
|
+ p += flat_pid.len;
|
|
|
|
|
|
- con->file = fopen(fn, "a");
|
|
|
- pkg_free(fn);
|
|
|
+ memcpy(p, flat_suffix.s, flat_suffix.len);
|
|
|
+ p += flat_suffix.len;
|
|
|
|
|
|
- if (!con->file) {
|
|
|
- LOG(L_ERR, "flat_reopen_connection: Invalid parameter value\n");
|
|
|
- return -1;
|
|
|
+ *p = '\0';
|
|
|
+ return buf;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+int flat_open_table(int* idx, db_con_t* con, str* name)
|
|
|
+{
|
|
|
+ struct flat_con* fcon;
|
|
|
+ struct flat_file* new;
|
|
|
+ int i;
|
|
|
+ char* filename, *table;
|
|
|
+
|
|
|
+ new = NULL;
|
|
|
+ filename = NULL;
|
|
|
+ table = NULL;
|
|
|
+ fcon = DB_GET_PAYLOAD(con);
|
|
|
+
|
|
|
+ for(i = 0; i < fcon->n; i++) {
|
|
|
+ if (name->len == fcon->file[i].table.len &&
|
|
|
+ !strncmp(name->s, fcon->file[i].table.s, name->len))
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (fcon->n == i) {
|
|
|
+ /* Perform operations that can fail first (before resizing
|
|
|
+ * fcon->file, so that we can fail gracefully if one of the
|
|
|
+ * operations fail.
|
|
|
+ */
|
|
|
+ if ((filename = get_filename(&con->uri->body, name)) == NULL)
|
|
|
+ goto no_mem;
|
|
|
+
|
|
|
+ if ((table = pkg_malloc(name->len)) == NULL) goto no_mem;
|
|
|
+ memcpy(table, name->s, name->len);
|
|
|
+
|
|
|
+ new = pkg_realloc(fcon->file, sizeof(struct flat_file) * (fcon->n + 1));
|
|
|
+ if (new == NULL) goto no_mem;
|
|
|
+
|
|
|
+ fcon->file = new;
|
|
|
+ new = new + fcon->n; /* Advance to the new (last) element */
|
|
|
+ fcon->n++;
|
|
|
+
|
|
|
+ new->table.s = table;
|
|
|
+ new->table.len = name->len;
|
|
|
+ new->filename = filename;
|
|
|
+
|
|
|
+ /* Also open the file if we are connected already */
|
|
|
+ if (fcon->flags & FLAT_OPENED) {
|
|
|
+ if ((new->f = fopen(new->filename, "a")) == NULL) {
|
|
|
+ ERR("flatstore: Error while opening file handle to '%s': %s\n",
|
|
|
+ new->filename, strerror(errno));
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ new[fcon->n].f = NULL;
|
|
|
}
|
|
|
+
|
|
|
+ *idx = fcon->n - 1;
|
|
|
+ } else {
|
|
|
+ *idx = i;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
return 0;
|
|
|
+
|
|
|
+ no_mem:
|
|
|
+ ERR("flatstore: No memory left\n");
|
|
|
+ if (filename) pkg_free(filename);
|
|
|
+ if (table) pkg_free(table);
|
|
|
+ return -1;
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+/** @} */
|