posops: new module with functions working with the position in message buffer
[kamailio] / src / modules / posops / posops_mod.c
1 /**
2  * Copyright (C) 2021 Daniel-Constantin Mierla (asipto.com)
3  *
4  * This file is part of Kamailio, a free SIP server.
5  *
6  * This file is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version
10  *
11  *
12  * This file is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20  *
21  */
22
23 #include <stdio.h>
24 #include <unistd.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "../../core/sr_module.h"
29 #include "../../core/dprint.h"
30 #include "../../core/mod_fix.h"
31 #include "../../core/data_lump.h"
32 #include "../../core/kemi.h"
33
34
35 MODULE_VERSION
36
37 static int mod_init(void);
38 static int child_init(int);
39 static void mod_destroy(void);
40
41 static int w_posops_pos_append(sip_msg_t* msg, char* p1idx, char* p2val);
42 static int w_posops_pos_insert(sip_msg_t* msg, char* p1idx, char* p2val);
43 static int w_posops_pos_rm(sip_msg_t* msg, char* p1idx, char* p2len);
44
45 typedef struct posops_data {
46         int ret;
47         int idx;
48 } pospos_data_t;
49
50 /* clang-format off */
51 static cmd_export_t cmds[]={
52         {"pos_append", (cmd_function)w_posops_pos_append, 2, fixup_igp_spve,
53                 fixup_free_igp_spve, ANY_ROUTE},
54         {"pos_insert", (cmd_function)w_posops_pos_insert, 2, fixup_igp_spve,
55                 fixup_free_igp_spve, ANY_ROUTE},
56         {"pos_rm", (cmd_function)w_posops_pos_rm, 2, fixup_igp_igp,
57                 fixup_free_igp_igp, ANY_ROUTE},
58
59         {0, 0, 0, 0, 0, 0}
60 };
61
62 static param_export_t params[]={
63
64         {0, 0, 0}
65 };
66
67 struct module_exports exports = {
68         "posops",
69         DEFAULT_DLFLAGS, /* dlopen flags */
70         cmds,
71         params,
72         0,              /* exported RPC methods */
73         0,              /* exported pseudo-variables */
74         0,              /* response function */
75         mod_init,       /* module initialization function */
76         child_init,     /* per child init function */
77         mod_destroy     /* destroy function */
78 };
79 /* clang-format on */
80
81
82 /**
83  * init module function
84  */
85 static int mod_init(void)
86 {
87         return 0;
88 }
89
90 /**
91  * @brief Initialize async module children
92  */
93 static int child_init(int rank)
94 {
95         return 0;
96 }
97
98 /**
99  * destroy module function
100  */
101 static void mod_destroy(void)
102 {
103         return;
104 }
105
106 /**
107  *
108  */
109 static int ki_posops_pos_append(sip_msg_t *msg, int idx, str *val)
110 {
111         int offset;
112         sr_lump_t *anchor = NULL;
113
114         if(val==NULL || val->s==NULL || val->len<=0) {
115                 LM_ERR("invalid val parameter\n");
116                 return -1;
117         }
118
119         if(idx<0) {
120                 offset = msg->len + idx + 1;
121         } else {
122                 offset = idx;
123         }
124         if(offset>msg->len) {
125                 LM_ERR("offset invalid: %d (msg-len: %d)\n", offset, msg->len);
126                 return -1;
127         }
128
129         anchor = anchor_lump(msg, offset, 0, 0);
130         if (insert_new_lump_after(anchor, val->s, val->len, 0) == 0) {
131                 LM_ERR("unable to add lump\n");
132                 return -1;
133         }
134
135         return 1;
136 }
137
138 /**
139  *
140  */
141 static int w_posops_pos_append(sip_msg_t* msg, char* p1idx, char* p2val)
142 {
143         int idx = 0;
144         str val = STR_NULL;
145
146         if(fixup_get_ivalue(msg, (gparam_t*)p1idx, &idx)!=0) {
147                 LM_ERR("unable to get idx parameter\n");
148                 return -1;
149         }
150
151         if(fixup_get_svalue(msg, (gparam_t*)p2val, &val)!=0) {
152                 LM_ERR("unable to get val parameter\n");
153                 return -1;
154         }
155
156         return ki_posops_pos_append(msg, idx, &val);
157 }
158
159 /**
160  *
161  */
162 static int ki_posops_pos_insert(sip_msg_t *msg, int idx, str *val)
163 {
164         int offset;
165         sr_lump_t *anchor = NULL;
166
167         if(val==NULL || val->s==NULL || val->len<=0) {
168                 LM_ERR("invalid val parameter\n");
169                 return -1;
170         }
171
172         if(idx<0) {
173                 offset = msg->len + idx + 1;
174         } else {
175                 offset = idx;
176         }
177         if(offset>msg->len) {
178                 LM_ERR("offset invalid: %d (msg-len: %d)\n", offset, msg->len);
179                 return -1;
180         }
181
182         anchor = anchor_lump(msg, offset, 0, 0);
183         if (insert_new_lump_before(anchor, val->s, val->len, 0) == 0) {
184                 LM_ERR("unable to add lump\n");
185                 return -1;
186         }
187
188         return 1;
189 }
190
191 /**
192  *
193  */
194 static int w_posops_pos_insert(sip_msg_t* msg, char* p1idx, char* p2val)
195 {
196         int idx = 0;
197         str val = STR_NULL;
198
199         if(fixup_get_ivalue(msg, (gparam_t*)p1idx, &idx)!=0) {
200                 LM_ERR("unable to get idx parameter\n");
201                 return -1;
202         }
203
204         if(fixup_get_svalue(msg, (gparam_t*)p2val, &val)!=0) {
205                 LM_ERR("unable to get val parameter\n");
206                 return -1;
207         }
208
209         return ki_posops_pos_insert(msg, idx, &val);
210 }
211
212
213 /**
214  *
215  */
216 static int ki_posops_pos_rm(sip_msg_t *msg, int idx, int len)
217 {
218         int offset;
219         sr_lump_t *anchor = NULL;
220
221         if(len<=0) {
222                 LM_ERR("length invalid: %d (msg-len: %d)\n", len, msg->len);
223                 return -1;
224         }
225         if(idx<0) {
226                 offset = msg->len + idx + 1;
227         } else {
228                 offset = idx;
229         }
230         if(offset>msg->len) {
231                 LM_ERR("offset invalid: %d (msg-len: %d)\n", offset, msg->len);
232                 return -1;
233         }
234         if(offset==msg->len) {
235                 LM_WARN("offset at the end of message: %d (msg-len: %d)\n",
236                                 offset, msg->len);
237                 return 1;
238         }
239         if(offset + len > msg->len) {
240                 LM_WARN("offset + len over the end of message: %d + %d (msg-len: %d)\n",
241                                 offset, len, msg->len);
242                 return -1;
243         }
244         anchor=del_lump(msg, offset, len, 0);
245         if (anchor==0) {
246                 LM_ERR("cannot remove - offset: %d - len: %d - msg-len: %d\n",
247                                 offset, len, msg->len);
248                 return -1;
249         }
250         return 1;
251 }
252
253 /**
254  *
255  */
256 static int w_posops_pos_rm(sip_msg_t* msg, char* p1idx, char* p2len)
257 {
258         int idx = 0;
259         int len = 0;
260
261         if(fixup_get_ivalue(msg, (gparam_t*)p1idx, &idx)!=0) {
262                 LM_ERR("unable to get idx parameter\n");
263                 return -1;
264         }
265         if(fixup_get_ivalue(msg, (gparam_t*)p2len, &len)!=0) {
266                 LM_ERR("unable to get len parameter\n");
267                 return -1;
268         }
269
270         return ki_posops_pos_rm(msg, idx, len);
271 }
272
273 /**
274  *
275  */
276 /* clang-format off */
277 static sr_kemi_t sr_kemi_posops_exports[] = {
278         { str_init("posops"), str_init("pos_append"),
279                 SR_KEMIP_INT, ki_posops_pos_append,
280                 { SR_KEMIP_INT, SR_KEMIP_STR, SR_KEMIP_NONE,
281                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
282         },
283         { str_init("posops"), str_init("pos_insert"),
284                 SR_KEMIP_INT, ki_posops_pos_insert,
285                 { SR_KEMIP_INT, SR_KEMIP_STR, SR_KEMIP_NONE,
286                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
287         },
288         { str_init("posops"), str_init("pos_rm"),
289                 SR_KEMIP_INT, ki_posops_pos_rm,
290                 { SR_KEMIP_INT, SR_KEMIP_INT, SR_KEMIP_NONE,
291                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
292         },
293
294         { {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
295 };
296 /* clang-format on */
297
298 /**
299  *
300  */
301 int mod_register(char *path, int *dlflags, void *p1, void *p2)
302 {
303         sr_kemi_modules_add(sr_kemi_posops_exports);
304         return 0;
305 }