db_sqlite: rename database scheme files, to allow automatic updates
[sip-router] / select_buf.c
1 /*
2  * $Id$
3  *
4  * Copyright (C) 2005-2006 iptelorg GmbH
5  *
6  * This file is part of ser, a free SIP server.
7  *
8  * ser is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version
12  *
13  * For a license to use the ser software under conditions
14  * other than those described here, or to purchase support for this
15  * software, please contact iptel.org by e-mail at the following addresses:
16  *    info@iptel.org
17  *
18  * ser is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26  *
27  * History:
28  * --------
29  *      2006-06-16  static buffer for select results (mma)
30  *                  each process owns a separate space
31  *                  each request starts using the buffer from the start
32  *
33  */
34
35 /*!
36  * \file
37  * \brief SIP-router core :: 
38  * \ingroup core
39  * Module: \ref core
40  */
41
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <unistd.h>
46 #include <ctype.h>
47
48 #include "dprint.h"
49 #include "mem/mem.h"
50 #include "str.h"
51 #include "ut.h"
52
53 /*
54  * Placeholder for the buffer
55  *
56  * two buffers are actually used to cover the different size requests
57  * assuming that resize can move the result to newly allocated space
58  * and comparing two selects from the script could require two static buffers
59  *
60  * if more static buffers need to be valid at the same time change
61  * the following constant
62  */
63
64 #define MAX_BUFFERS 2
65 #define BUFFER_GRANULARITY 256
66
67 typedef struct stat_buffer_ {
68         char *b;
69         int size;
70         int offset;
71 } stat_buffer_t;
72
73 static stat_buffer_t buffer[MAX_BUFFERS];
74 static int active_buffer=-1;
75
76 #define ALLOC_SIZE(req_size) (((req_size/BUFFER_GRANULARITY)+1)*BUFFER_GRANULARITY)
77
78 static int allocate_buffer(int req_size) {
79         void *b;
80         int size=ALLOC_SIZE(req_size);
81         
82         if (buffer[active_buffer].b == NULL) {
83                 if ((buffer[active_buffer].b=pkg_malloc(size))==NULL)
84                         return 0;
85                 buffer[active_buffer].size=size;
86                 buffer[active_buffer].offset=0;
87                 return 1;
88         }
89         
90         active_buffer = (active_buffer?active_buffer:MAX_BUFFERS)-1;
91         if (buffer[active_buffer].size >= req_size) {
92                 buffer[active_buffer].offset = 0;
93                 return 1;
94         }
95         
96         if ((b=pkg_realloc(buffer[active_buffer].b,size))) {
97                 buffer[active_buffer].b=b;
98                 buffer[active_buffer].size=size;
99                 buffer[active_buffer].offset=0;
100                 return 1;
101         }
102         
103         return 0;
104 }
105
106 /*
107  * Request for space from buffer
108  *
109  * Returns:  NULL  memory allocation failure (no more space)
110  *           pointer to the space on success
111  */
112
113 char* get_static_buffer(int req_size) {
114         char *p = NULL;
115
116 #ifdef EXTRA_DEBUG
117         if ((active_buffer < 0) || (active_buffer > MAX_BUFFERS-1)) {
118                 LOG(L_CRIT, "BUG: buffers have not been initialized yet. "
119                         "Call reset_static_buffer() before executing "
120                         "a route block.\n");
121                 abort();
122         }
123 #endif
124         if ((buffer[active_buffer].size >= buffer[active_buffer].offset + req_size)
125                         || (allocate_buffer(req_size))) {
126                 /* enough space in current buffer or allocation successful */
127                 p = buffer[active_buffer].b+buffer[active_buffer].offset;
128                 buffer[active_buffer].offset += req_size;       
129                 return p;
130         }
131         return NULL;
132 }
133
134 /* Internal function - called before request is going to be processed
135  *
136  * Reset offset to unused space
137  */
138
139 int reset_static_buffer() {
140         int i;
141
142         if (active_buffer == -1) {
143                 memset(buffer, 0, sizeof(buffer));
144         } else {
145                 for (i=0; i<MAX_BUFFERS; i++)
146                         buffer[i].offset=0;
147         }
148         active_buffer=0;
149         return 0;
150 }
151
152 int str_to_static_buffer(str* res, str* s)
153 {
154         res->s = get_static_buffer(s->len);
155         if (!res->s) return -1;
156         memcpy(res->s, s->s, s->len);
157         res->len = s->len;
158         return 0;
159 }
160
161 int int_to_static_buffer(str* res, int val)
162 {
163         char *c;
164         c = int2str(abs(val), &res->len);
165         res->s = get_static_buffer(res->len+(val<0)?1:0);
166         if (!res->s) return -1;
167         if (val < 0) {
168                 res->s[0] = '-';        
169                 memcpy(res->s+1, c, res->len);
170                 res->len++;
171         }
172         else {
173                 memcpy(res->s, c, res->len);
174         }
175         return 0;
176 }
177
178 int uint_to_static_buffer(str* res, unsigned int val)
179 {
180         char *c;
181         c = int2str(val, &res->len);
182         res->s = get_static_buffer(res->len);
183         if (!res->s) return -1;
184         memcpy(res->s, c, res->len);
185         return 0;
186 }
187
188 int uint_to_static_buffer_ex(str* res, unsigned int val, int base, int pad)
189 {
190         char *c;
191         c = int2str_base_0pad(val, &res->len, base, pad); 
192         res->s = get_static_buffer(res->len);
193         if (!res->s) return -1;
194         memcpy(res->s, c, res->len);
195         return 0;
196 }
197