flat_con.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  *
00004  * Copyright (C) 2004 FhG FOKUS
00005  * Copyright (C) 2008 iptelorg GmbH
00006  * Written by Jan Janak <jan@iptel.org>
00007  *
00008  * This file is part of SER, a free SIP server.
00009  *
00010  * SER is free software; you can redistribute it and/or modify it under the
00011  * terms of the GNU General Public License as published by the Free Software
00012  * Foundation; either version 2 of the License, or (at your option) any later
00013  * version.
00014  *
00015  * SER is distributed in the hope that it will be useful, but WITHOUT ANY
00016  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00017  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
00018  * details.
00019  *
00020  * You should have received a copy of the GNU General Public License along
00021  * with this program; if not, write to the Free Software Foundation, Inc., 
00022  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00023  */
00024 
00033 #include "flat_con.h"
00034 #include "flatstore_mod.h"
00035 #include "flat_uri.h"
00036 
00037 #include "../../mem/mem.h"
00038 #include "../../dprint.h"
00039 #include "../../ut.h"
00040 
00041 #include <stdio.h>
00042 #include <stdlib.h>
00043 #include <string.h>
00044 #include <errno.h>
00045 
00046 
00053 static void flat_con_free(db_con_t* con, struct flat_con* payload)
00054 {
00055         int i;
00056         if (!payload) return;
00057 
00058         /* delete the structure only if there are no more references
00059          * to it in the connection pool
00060          */
00061         if (db_pool_remove((db_pool_entry_t*)payload) == 0) return;
00062         
00063         db_pool_entry_free(&payload->gen);
00064 
00065         if (payload->file) {
00066                 for(i = 0; i < payload->n; i++) {
00067                         if (payload->file[i].filename) pkg_free(payload->file[i].filename);
00068                         if (payload->file[i].table.s) pkg_free(payload->file[i].table.s);
00069                         if (payload->file[i].f) fclose(payload->file[i].f);
00070                 }
00071                 pkg_free(payload->file);
00072         }
00073         pkg_free(payload);
00074 }
00075 
00076 
00077 int flat_con(db_con_t* con)
00078 {
00079         struct flat_con* fcon;
00080 
00081         /* First try to lookup the connection in the connection pool and
00082          * re-use it if a match is found
00083          */
00084         fcon = (struct flat_con*)db_pool_get(con->uri);
00085         if (fcon) {
00086                 DBG("flatstore: A handle to %.*s found in the connection pool\n",
00087                         STR_FMT(&con->uri->body));
00088                 goto found;
00089         }
00090 
00091         fcon = (struct flat_con*)pkg_malloc(sizeof(struct flat_con));
00092         if (fcon == NULL) {
00093                 ERR("flatstore: No memory left\n");
00094                 goto error;
00095         }
00096         memset(fcon, '\0', sizeof(struct flat_con));
00097         if (db_pool_entry_init(&fcon->gen, flat_con_free, con->uri) < 0) goto error;
00098 
00099         DBG("flastore: Preparing new file handles to files in %.*s\n", 
00100                 STR_FMT(&con->uri->body));
00101         
00102         /* Put the newly created flatstore connection into the pool */
00103         db_pool_put((struct db_pool_entry*)fcon);
00104         DBG("flatstore: Handle stored in connection pool\n");
00105 
00106  found:
00107         /* Attach driver payload to the db_con structure and set connect and
00108          * disconnect functions
00109          */
00110         DB_SET_PAYLOAD(con, fcon);
00111         con->connect = flat_con_connect;
00112         con->disconnect = flat_con_disconnect;
00113         return 0;
00114 
00115  error:
00116         if (fcon) {
00117                 db_pool_entry_free(&fcon->gen);
00118                 pkg_free(fcon);
00119         }
00120         return -1;
00121 }
00122 
00123 
00124 int flat_con_connect(db_con_t* con)
00125 {
00126         struct flat_con* fcon;
00127         int i;
00128         
00129         fcon = DB_GET_PAYLOAD(con);
00130         
00131         /* Do not reconnect already connected connections */
00132         if (fcon->flags & FLAT_OPENED) return 0;
00133 
00134         DBG("flatstore: Opening handles to files in '%.*s'\n", 
00135                 STR_FMT(&con->uri->body));
00136 
00137         /* FIXME: Make sure the directory exists, is accessible,
00138          * and we can create files there
00139          */
00140 
00141         DBG("flatstore: Directory '%.*s' opened successfully\n", 
00142                 STR_FMT(&con->uri->body));
00143 
00144         for(i = 0; i < fcon->n; i++) {
00145                 if (fcon->file[i].f) {
00146                         fclose(fcon->file[i].f);
00147                 }
00148                 fcon->file[i].f = fopen(fcon->file[i].filename, "a");
00149                 if (fcon->file[i].f == NULL) {
00150                         ERR("flatstore: Error while opening file handle to '%s': %s\n", 
00151                                 fcon->file[i].filename, strerror(errno));
00152                         return -1;
00153                 }
00154         }
00155 
00156         fcon->flags |= FLAT_OPENED;
00157         return 0;
00158 
00159 }
00160 
00161 
00162 void flat_con_disconnect(db_con_t* con)
00163 {
00164         struct flat_con* fcon;
00165         int i;
00166 
00167         fcon = DB_GET_PAYLOAD(con);
00168 
00169         if ((fcon->flags & FLAT_OPENED) == 0) return;
00170 
00171         DBG("flatstore: Closing handles to files in '%.*s'\n", 
00172                 STR_FMT(&con->uri->body));
00173 
00174         for(i = 0; i < fcon->n; i++) {
00175                 if (fcon->file[i].f == NULL) continue;
00176                 fclose(fcon->file[i].f);
00177                 fcon->file[i].f = NULL;
00178         }
00179 
00180         fcon->flags &= ~FLAT_OPENED;
00181 }
00182 
00183 
00184 /* returns a pkg_malloc'ed file name */
00185 static char* get_filename(str* dir, str* name)
00186 {
00187     char* buf, *p;
00188     int buf_len, total_len;
00189 
00190     buf_len = pathmax();
00191 
00192     total_len = dir->len + 1 /* / */ + 
00193                 name->len + 1 /* _ */+
00194                 flat_pid.len +
00195                 flat_suffix.len + 1 /* \0 */;
00196 
00197     if (buf_len < total_len) {
00198         ERR("flatstore: The path is too long (%d and PATHMAX is %d)\n",
00199             total_len, buf_len);
00200         return 0;
00201     }
00202 
00203     if ((buf = pkg_malloc(buf_len)) == NULL) {
00204         ERR("flatstore: No memory left\n");
00205         return 0;
00206     }
00207     p = buf;
00208 
00209     memcpy(p, dir->s, dir->len);
00210     p += dir->len;
00211 
00212     *p++ = '/';
00213 
00214     memcpy(p, name->s, name->len);
00215     p += name->len;
00216 
00217     *p++ = '_';
00218 
00219     memcpy(p, flat_pid.s, flat_pid.len);
00220     p += flat_pid.len;
00221 
00222     memcpy(p, flat_suffix.s, flat_suffix.len);
00223     p += flat_suffix.len;
00224 
00225     *p = '\0';
00226     return buf;
00227 }
00228 
00229 
00230 
00231 int flat_open_table(int* idx, db_con_t* con, str* name)
00232 {
00233         struct flat_uri* furi;
00234         struct flat_con* fcon;
00235         struct flat_file* new;
00236         int i;
00237         char* filename, *table;
00238 
00239         new = NULL;
00240         filename = NULL;
00241         table = NULL;
00242         fcon = DB_GET_PAYLOAD(con);
00243         furi = DB_GET_PAYLOAD(con->uri);
00244         
00245         for(i = 0; i < fcon->n; i++) {
00246                 if (name->len == fcon->file[i].table.len &&
00247                         !strncmp(name->s, fcon->file[i].table.s, name->len))
00248                         break;
00249         }
00250         if (fcon->n == i) {
00251                 /* Perform operations that can fail first (before resizing
00252                  * fcon->file, so that we can fail gracefully if one of the
00253                  * operations fail. 
00254                  */
00255                 if ((filename = get_filename(&furi->path, name)) == NULL)
00256                         goto no_mem;
00257 
00258                 if ((table = pkg_malloc(name->len)) == NULL) goto no_mem;
00259                 memcpy(table, name->s, name->len);
00260 
00261                 new = pkg_realloc(fcon->file, sizeof(struct flat_file) * (fcon->n + 1));
00262                 if (new == NULL) goto no_mem;
00263 
00264                 fcon->file = new;
00265                 new = new + fcon->n; /* Advance to the new (last) element */
00266                 fcon->n++;
00267 
00268                 new->table.s = table;
00269                 new->table.len = name->len;
00270                 new->filename = filename;
00271 
00272                 /* Also open the file if we are connected already */
00273                 if (fcon->flags & FLAT_OPENED) {
00274                         if ((new->f = fopen(new->filename, "a")) == NULL) {
00275                                 ERR("flatstore: Error while opening file handle to '%s': %s\n", 
00276                                         new->filename, strerror(errno));
00277                                 return -1;
00278                         }                       
00279                 } else {
00280                         new->f = NULL;
00281                 }
00282                 
00283                 *idx = fcon->n - 1;
00284         } else {
00285                 *idx = i;
00286         }
00287         DBG("flatstore: Handle to file '%s' opened successfully\n", 
00288                 fcon->file[*idx].filename);
00289         return 0;
00290 
00291  no_mem:
00292         ERR("flatstore: No memory left\n");
00293         if (filename) pkg_free(filename);
00294         if (table) pkg_free(table);
00295         return -1;
00296 }
00297 
00298