annotate extensions/rt_rewrite/rt_rewrite.c @ 1341:b0401251d8c0

rt_rewrite: new extension This extension allows rewriting messages: putting data from one AVP into another, or removing AVPs altogether. Written for Effortel Technologies SA and published with their consent.
author Thomas Klausner <tk@giga.or.at>
date Tue, 09 Apr 2019 16:01:29 +0200
parents
children 61e693afccc6
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
1341
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
1 /*********************************************************************************************************
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
2 * Software License Agreement (BSD License) *
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
3 * Author: Thomas Klausner <tk@giga.or.at> *
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
4 * *
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
5 * Copyright (c) 2018, Thomas Klausner *
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
6 * All rights reserved. *
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
7 * *
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
8 * Written under contract by Effortel Technologies SA, http://effortel.com/ *
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
9 * *
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
10 * Redistribution and use of this software in source and binary forms, with or without modification, are *
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
11 * permitted provided that the following conditions are met: *
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
12 * *
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
13 * * Redistributions of source code must retain the above *
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
14 * copyright notice, this list of conditions and the *
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
15 * following disclaimer. *
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
16 * *
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
17 * * Redistributions in binary form must reproduce the above *
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
18 * copyright notice, this list of conditions and the *
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
19 * following disclaimer in the documentation and/or other *
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
20 * materials provided with the distribution. *
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
21 * *
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
23 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
24 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
25 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
28 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
30 *********************************************************************************************************/
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
31
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
32 #include <freeDiameter/extension.h>
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
33 #include "rt_rewrite.h"
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
34
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
35 #include <pthread.h>
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
36 #include <signal.h>
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
37
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
38 /*
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
39 * Replace AVPs: put their values into other AVPs
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
40 * Remove AVPs: drop them from a message
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
41 */
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
42
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
43 /* handler */
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
44 static struct fd_rt_fwd_hdl * rt_rewrite_handle = NULL;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
45
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
46 static char *config_file;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
47
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
48 struct avp_match *avp_match_start = NULL;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
49
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
50 static pthread_rwlock_t rt_rewrite_lock;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
51
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
52 #define MODULE_NAME "rt_rewrite"
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
53
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
54 struct store {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
55 struct avp *avp;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
56 struct avp_target *target;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
57 struct store *next;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
58 };
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
59
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
60 static struct store *store_new(void) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
61 struct store *ret;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
62
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
63 if ((ret=malloc(sizeof(*ret))) == NULL) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
64 fd_log_error("%s: malloc failure", MODULE_NAME);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
65 return NULL;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
66 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
67 ret->avp = NULL;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
68 ret->target = NULL;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
69 ret->next = NULL;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
70
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
71 return ret;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
72 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
73
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
74 static void store_free(struct store *store)
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
75 {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
76 while (store) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
77 struct store *next;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
78 if (store->avp) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
79 fd_msg_free((msg_or_avp *)store->avp);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
80 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
81 store->target = NULL;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
82 next = store->next;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
83 free(store);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
84 store = next;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
85 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
86 return;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
87 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
88
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
89 static int fd_avp_search_avp(msg_or_avp *where, struct dict_object *what, struct avp **avp)
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
90 {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
91 struct avp *nextavp;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
92 struct dict_avp_data dictdata;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
93 enum dict_object_type dicttype;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
94
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
95 CHECK_PARAMS((fd_dict_gettype(what, &dicttype) == 0) && (dicttype == DICT_AVP));
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
96 CHECK_FCT(fd_dict_getval(what, &dictdata));
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
97
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
98 /* Loop on all top AVPs */
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
99 CHECK_FCT(fd_msg_browse(where, MSG_BRW_FIRST_CHILD, (void *)&nextavp, NULL));
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
100 while (nextavp) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
101 struct avp_hdr *header = NULL;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
102 struct dict_object *model = NULL;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
103 if (fd_msg_avp_hdr(nextavp, &header) != 0) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
104 fd_log_notice("%s: unable to get header for AVP", MODULE_NAME);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
105 return -1;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
106 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
107 if (fd_msg_model(nextavp, &model) != 0) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
108 fd_log_notice("%s: unable to get model for AVP (%d, vendor %d)", MODULE_NAME, header->avp_code, header->avp_vendor);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
109 return 0;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
110 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
111 if (model == NULL) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
112 fd_log_notice("%s: unknown AVP (%d, vendor %d) (not in dictionary), skipping", MODULE_NAME, header->avp_code, header->avp_vendor);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
113 } else {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
114 if ((header->avp_code == dictdata.avp_code) && (header->avp_vendor == dictdata.avp_vendor)) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
115 break;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
116 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
117 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
118
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
119 /* Otherwise move to next AVP in the message */
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
120 CHECK_FCT(fd_msg_browse(nextavp, MSG_BRW_NEXT, (void *)&nextavp, NULL) );
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
121 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
122
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
123 if (avp)
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
124 *avp = nextavp;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
125
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
126 if (*avp || nextavp) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
127 return 0;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
128 } else {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
129 return ENOENT;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
130 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
131 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
132
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
133
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
134
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
135 static msg_or_avp *find_container(msg_or_avp *msg, struct avp_target *target)
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
136 {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
137 msg_or_avp *location = msg;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
138 while (target->child) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
139 struct dict_object *avp_do;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
140 msg_or_avp *new_location = NULL;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
141 int ret;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
142
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
143 fd_log_debug("%s: looking for '%s'", MODULE_NAME, target->name);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
144 if ((ret=fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME_ALL_VENDORS, target->name, &avp_do, ENOENT)) != 0) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
145 fd_log_error("%s: target AVP '%s' not in dictionary: %s", MODULE_NAME, target->name, strerror(ret));
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
146 return NULL;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
147 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
148 if ((ret=fd_avp_search_avp(location, avp_do, (struct avp **)&new_location)) != 0) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
149 fd_log_debug("%s: did not find '%s', adding it", MODULE_NAME, target->name);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
150 struct avp *avp = NULL;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
151 if ((ret = fd_msg_avp_new(avp_do, 0, &avp)) != 0) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
152 fd_log_notice("%s: unable to create new '%s' AVP", MODULE_NAME, target->name);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
153 return NULL;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
154 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
155 if ((ret=fd_msg_avp_add(location, MSG_BRW_LAST_CHILD, avp)) != 0) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
156 fd_log_error("%s: cannot add AVP '%s' to message: %s", MODULE_NAME, target->name, strerror(ret));
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
157 return NULL;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
158 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
159 fd_log_debug("%s: '%s' added", MODULE_NAME, target->name);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
160 /* now find it in the new place */
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
161 continue;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
162 } else {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
163 location = new_location;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
164 fd_log_debug("%s: found '%s'", MODULE_NAME, target->name);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
165 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
166 target = target->child;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
167 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
168 fd_log_debug("%s: returning AVP for '%s'", MODULE_NAME, target->name);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
169 return location;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
170 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
171
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
172 static int store_apply(msg_or_avp *msg, struct store **store)
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
173 {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
174 while (*store) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
175 msg_or_avp *container;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
176 struct store *next;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
177 if ((*store)->avp) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
178 int ret;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
179 if ((container=find_container(msg, (*store)->target)) == NULL) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
180 fd_log_error("%s: internal error, container not found", MODULE_NAME);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
181 return -1;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
182 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
183
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
184 if ((ret=fd_msg_avp_add(container, MSG_BRW_LAST_CHILD, (*store)->avp)) != 0) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
185 fd_log_error("%s: cannot add AVP '%s' to message: %s", MODULE_NAME, (*store)->target->name, strerror(ret));
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
186 return -1;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
187 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
188 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
189 next = (*store)->next;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
190 free(*store);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
191 *store = next;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
192 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
193 return 0;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
194 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
195
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
196 static int schedule_for_adding(struct avp *avp, struct avp_target *target, struct store *store)
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
197 {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
198 if (store->avp) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
199 struct store *new;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
200 if ((new=store_new()) == NULL) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
201 return -1;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
202 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
203 new->avp = avp;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
204 new->target = target;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
205 new->next = store->next;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
206 store->next = new;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
207 } else {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
208 store->avp = avp;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
209 store->target = target;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
210 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
211 fd_log_debug("%s: noted %s for later adding", MODULE_NAME, target->name);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
212 return 0;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
213 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
214
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
215 static void move_avp_to_target(union avp_value *avp_value, struct avp_target *target, struct store *store)
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
216 {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
217 struct dict_object *avp_do;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
218 struct avp *avp;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
219 int ret;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
220 struct avp_target *final = target;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
221
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
222 while (final->child) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
223 final = final->child;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
224 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
225 if ((ret=fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME_ALL_VENDORS, final->name, &avp_do, ENOENT)) != 0) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
226 fd_log_error("internal error, target AVP '%s' not in dictionary: %s", final->name, strerror(ret));
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
227 return;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
228 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
229 if ((ret=fd_msg_avp_new(avp_do, 0, &avp)) != 0) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
230 fd_log_error("internal error, error creating structure for AVP '%s': %s", final->name, strerror(ret));
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
231 return;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
232 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
233 if ((ret=fd_msg_avp_setvalue(avp, avp_value)) != 0) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
234 fd_log_error("internal error, cannot set value for AVP '%s': %s", final->name, strerror(ret));
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
235 return;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
236 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
237 if (schedule_for_adding(avp, target, store) != 0) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
238 fd_log_error("internal error, cannot add AVP '%s' to message", final->name);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
239 return;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
240 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
241
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
242 return;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
243 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
244
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
245
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
246 static struct avp_match *avp_to_be_replaced(const char *avp_name, struct avp_match *subtree)
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
247 {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
248 struct avp_match *ret;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
249 for (ret=subtree; ret != NULL; ret=ret->next) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
250 if (strcmp(ret->name, avp_name) == 0) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
251 return ret;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
252 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
253 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
254 return NULL;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
255 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
256
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
257 /*
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
258 * msg: whole message
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
259 * avp: current AVP in message
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
260 * subtree: comparison subtree
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
261 */
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
262 static int replace_avps(struct msg *msg, msg_or_avp *avp, struct avp_match *subtree, struct store *store)
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
263 {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
264 int nothing_left = 1;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
265 /* for each AVP in message */
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
266 while (avp) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
267 struct avp_hdr *header = NULL;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
268 struct dict_object *model = NULL;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
269 const char *avp_name = NULL;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
270 msg_or_avp *next;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
271 int delete = 0;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
272
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
273 if (fd_msg_avp_hdr(avp, &header) != 0) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
274 fd_log_notice("internal error: unable to get header for AVP");
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
275 return 0;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
276 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
277 if (fd_msg_model(avp, &model) != 0) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
278 fd_log_notice("internal error: unable to get model for AVP (%d, vendor %d)", header->avp_code, header->avp_vendor);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
279 return 0;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
280 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
281 if (model == NULL) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
282 fd_log_notice("unknown AVP (%d, vendor %d) (not in dictionary), skipping", header->avp_code, header->avp_vendor);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
283
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
284 } else {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
285 struct dict_avp_data dictdata;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
286 struct avp_match *subtree_match;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
287 enum dict_avp_basetype basetype = AVP_TYPE_OCTETSTRING;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
288
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
289 fd_dict_getval(model, &dictdata);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
290 avp_name = dictdata.avp_name;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
291 basetype = dictdata.avp_basetype;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
292 /* check if it exists in the subtree */
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
293 if ((subtree_match = avp_to_be_replaced(avp_name, subtree))) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
294 /* if this should be deleted, mark as such */
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
295 if (subtree_match->drop) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
296 fd_log_notice("%s: dropping AVP '%s'", MODULE_NAME, avp_name);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
297 delete = 1;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
298 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
299 /* if grouped, dive down */
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
300 if (basetype == AVP_TYPE_GROUPED) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
301 msg_or_avp *child = NULL;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
302
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
303 fd_log_debug("%s: grouped AVP '%s'", MODULE_NAME, avp_name);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
304 if (fd_msg_browse(avp, MSG_BRW_FIRST_CHILD, &child, NULL) != 0) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
305 fd_log_notice("internal error: unable to browse message at AVP (%d, vendor %d)", header->avp_code, header->avp_vendor);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
306 return 0;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
307 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
308
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
309 /* replace_avps returns if the AVP was emptied out */
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
310 if (replace_avps(msg, child, subtree_match->children, store)) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
311 fd_log_notice("%s: removing empty grouped AVP '%s'", MODULE_NAME, avp_name);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
312 delete = 1;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
313 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
314 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
315 else {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
316 /* if single, remove it and add replacement AVP in target structure */
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
317 if (subtree_match->target) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
318 struct avp_target *final = subtree_match->target;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
319 while (final->child) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
320 final = final->child;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
321 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
322 fd_log_notice("%s: moving AVP '%s' to '%s'", MODULE_NAME, avp_name, final->name);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
323 move_avp_to_target(header->avp_value, subtree_match->target, store);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
324 delete = 1;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
325 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
326 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
327 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
328 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
329 fd_msg_browse(avp, MSG_BRW_NEXT, &next, NULL);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
330 if (delete) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
331 /* remove AVP from message */
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
332 fd_msg_free((msg_or_avp *)avp);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
333 } else {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
334 nothing_left = 0;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
335 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
336
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
337 avp = next;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
338 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
339
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
340 return nothing_left;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
341 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
342
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
343 static volatile int in_signal_handler = 0;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
344
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
345 /* signal handler */
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
346 static void sig_hdlr(void)
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
347 {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
348 struct avp_match *old_config;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
349
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
350 if (in_signal_handler) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
351 fd_log_error("%s: already handling a signal, ignoring new one", MODULE_NAME);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
352 return;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
353 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
354 in_signal_handler = 1;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
355
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
356 if (pthread_rwlock_wrlock(&rt_rewrite_lock) != 0) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
357 fd_log_error("%s: locking failed, aborting config reload", MODULE_NAME);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
358 return;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
359 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
360
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
361 /* save old config in case reload goes wrong */
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
362 old_config = avp_match_start;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
363 avp_match_start = NULL;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
364
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
365 if (rt_rewrite_conf_handle(config_file) != 0) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
366 fd_log_notice("%s: error reloading configuration, restoring previous configuration", MODULE_NAME);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
367 avp_match_free(avp_match_start);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
368 avp_match_start = old_config;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
369 } else {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
370 avp_match_free(old_config);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
371 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
372
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
373 if (pthread_rwlock_unlock(&rt_rewrite_lock) != 0) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
374 fd_log_error("%s: unlocking failed after config reload, exiting", MODULE_NAME);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
375 exit(1);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
376 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
377
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
378 fd_log_notice("%s: reloaded configuration", MODULE_NAME);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
379
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
380 in_signal_handler = 0;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
381 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
382
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
383 static int rt_rewrite(void * cbdata, struct msg **msg)
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
384 {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
385 int ret;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
386 msg_or_avp *avp = NULL;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
387 struct store *store = NULL;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
388
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
389 /* nothing configured */
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
390 if (avp_match_start == NULL) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
391 return 0;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
392 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
393
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
394 if ((store=store_new()) == NULL) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
395 fd_log_error("%s: malloc failure");
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
396 return ENOMEM;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
397 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
398 if ((ret = fd_msg_parse_dict(*msg, fd_g_config->cnf_dict, NULL)) != 0) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
399 fd_log_notice("%s: error parsing message", MODULE_NAME);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
400 free(store);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
401 return ret;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
402 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
403 if ((ret=fd_msg_browse(*msg, MSG_BRW_FIRST_CHILD, &avp, NULL)) != 0) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
404 fd_log_notice("internal error: message has no child");
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
405 free(store);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
406 return ret;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
407 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
408 if (replace_avps(*msg, avp, avp_match_start->children, store) != 0) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
409 fd_log_error("%s: replace AVP function failed", MODULE_NAME);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
410 store_free(store);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
411 return -1;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
412 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
413 return store_apply(*msg, &store);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
414 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
415
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
416 /* entry point */
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
417 static int rt_rewrite_entry(char * conffile)
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
418 {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
419 int ret;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
420 config_file = conffile;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
421
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
422 pthread_rwlock_init(&rt_rewrite_lock, NULL);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
423
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
424 if (pthread_rwlock_wrlock(&rt_rewrite_lock) != 0) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
425 fd_log_notice("%s: write-lock failed, aborting", MODULE_NAME);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
426 return EDEADLK;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
427 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
428
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
429 /* Parse the configuration file */
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
430 if ((ret=rt_rewrite_conf_handle(config_file)) != 0) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
431 pthread_rwlock_unlock(&rt_rewrite_lock);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
432 return ret;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
433 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
434
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
435 if (pthread_rwlock_unlock(&rt_rewrite_lock) != 0) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
436 fd_log_notice("%s: write-unlock failed, aborting", MODULE_NAME);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
437 return EDEADLK;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
438 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
439
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
440 /* Register reload callback */
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
441 CHECK_FCT(fd_event_trig_regcb(SIGUSR1, MODULE_NAME, sig_hdlr));
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
442
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
443 /* Register the callback */
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
444 if ((ret=fd_rt_fwd_register(rt_rewrite, NULL, RT_FWD_ALL, &rt_rewrite_handle)) != 0) {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
445 fd_log_error("Cannot register callback handler");
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
446 return ret;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
447 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
448
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
449 fd_log_notice("Extension 'Rewrite' initialized");
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
450 return 0;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
451 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
452
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
453 /* Unload */
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
454 void fd_ext_fini(void)
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
455 {
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
456 /* Unregister the callbacks */
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
457 fd_rt_fwd_unregister(rt_rewrite_handle, NULL);
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
458 return ;
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
459 }
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
460
b0401251d8c0 rt_rewrite: new extension
Thomas Klausner <tk@giga.or.at>
parents:
diff changeset
461 EXTENSION_ENTRY("rt_rewrite", rt_rewrite_entry);
"Welcome to our mercurial repository"