00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "asterisk.h"
00027
00028 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 257851 $")
00029
00030 #include "asterisk/module.h"
00031 #include "asterisk/srv.h"
00032 #include "asterisk/pbx.h"
00033 #include "asterisk/app.h"
00034 #include "asterisk/datastore.h"
00035 #include "asterisk/channel.h"
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074 struct srv_result_datastore {
00075 struct srv_context *context;
00076 char id[1];
00077 };
00078
00079 static void srds_destroy_cb(void *data)
00080 {
00081 struct srv_result_datastore *datastore = data;
00082 ast_srv_cleanup(&datastore->context);
00083 ast_free(datastore);
00084 }
00085
00086 static const struct ast_datastore_info srv_result_datastore_info = {
00087 .type = "SRVQUERY",
00088 .destroy = srds_destroy_cb,
00089 };
00090
00091 static struct srv_context *srv_datastore_setup(const char *service, struct ast_channel *chan)
00092 {
00093 struct srv_result_datastore *srds;
00094 struct ast_datastore *datastore;
00095 const char *host;
00096 unsigned short port;
00097
00098 if (!(srds = ast_calloc(1, sizeof(*srds) + strlen(service)))) {
00099 return NULL;
00100 }
00101
00102 ast_autoservice_start(chan);
00103 if (ast_srv_lookup(&srds->context, service, &host, &port) < 0) {
00104 ast_autoservice_stop(chan);
00105 ast_log(LOG_NOTICE, "Error performing lookup of service '%s'\n", service);
00106 ast_free(srds);
00107 return NULL;
00108 }
00109 ast_autoservice_stop(chan);
00110
00111 strcpy(srds->id, service);
00112
00113 if (!(datastore = ast_datastore_alloc(&srv_result_datastore_info, srds->id))) {
00114 ast_srv_cleanup(&srds->context);
00115 ast_free(srds);
00116 return NULL;
00117 }
00118
00119 datastore->data = srds;
00120 ast_channel_lock(chan);
00121 ast_channel_datastore_add(chan, datastore);
00122 ast_channel_unlock(chan);
00123 return srds->context;
00124 }
00125
00126 static int srv_query_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00127 {
00128 struct ast_datastore *datastore;
00129
00130 if (!chan) {
00131 ast_log(LOG_WARNING, "%s cannot be used without a channel\n", cmd);
00132 return -1;
00133 }
00134
00135 if (ast_strlen_zero(data)) {
00136 ast_log(LOG_WARNING, "%s requires a service as an argument\n", cmd);
00137 return -1;
00138 }
00139
00140
00141
00142
00143 ast_channel_lock(chan);
00144 datastore = ast_channel_datastore_find(chan, &srv_result_datastore_info, data);
00145 ast_channel_unlock(chan);
00146
00147 if (datastore) {
00148 ast_channel_datastore_remove(chan, datastore);
00149 ast_datastore_free(datastore);
00150 }
00151
00152 if (!srv_datastore_setup(data, chan)) {
00153 return -1;
00154 }
00155
00156 ast_copy_string(buf, data, len);
00157
00158 return 0;
00159 }
00160
00161 static struct ast_custom_function srv_query_function = {
00162 .name = "SRVQUERY",
00163 .read = srv_query_read,
00164 };
00165
00166 static int srv_result_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00167 {
00168 struct srv_result_datastore *srds;
00169 struct ast_datastore *datastore;
00170 struct srv_context *srv_context;
00171 char *parse;
00172 const char *host;
00173 unsigned short port, priority, weight;
00174 unsigned int num;
00175 AST_DECLARE_APP_ARGS(args,
00176 AST_APP_ARG(id);
00177 AST_APP_ARG(resultnum);
00178 AST_APP_ARG(field);
00179 );
00180
00181 if (!chan) {
00182 ast_log(LOG_WARNING, "%s cannot be used without a channel\n", cmd);
00183 return -1;
00184 }
00185
00186 if (ast_strlen_zero(data)) {
00187 ast_log(LOG_WARNING, "%s requires two arguments (id and resultnum)\n", cmd);
00188 return -1;
00189 }
00190
00191 parse = ast_strdupa(data);
00192
00193 AST_STANDARD_APP_ARGS(args, parse);
00194
00195 ast_channel_lock(chan);
00196 datastore = ast_channel_datastore_find(chan, &srv_result_datastore_info, args.id);
00197 ast_channel_unlock(chan);
00198
00199 if (!datastore) {
00200
00201
00202
00203 srv_context = srv_datastore_setup(args.id, chan);
00204 if (!srv_context) {
00205 return -1;
00206 }
00207 } else {
00208 srds = datastore->data;
00209 srv_context = srds->context;
00210 }
00211
00212 if (!strcasecmp(args.resultnum, "getnum")) {
00213 snprintf(buf, len, "%u", ast_srv_get_record_count(srv_context));
00214 return 0;
00215 }
00216
00217 if (ast_strlen_zero(args.field)) {
00218 ast_log(LOG_ERROR, "A field must be provided when requesting SRV data\n");
00219 return -1;
00220 }
00221
00222 if (sscanf(args.resultnum, "%30u", &num) != 1) {
00223 ast_log(LOG_ERROR, "Invalid value '%s' for resultnum to %s\n", args.resultnum, cmd);
00224 return -1;
00225 }
00226
00227 if (ast_srv_get_nth_record(srv_context, num, &host, &port, &priority, &weight)) {
00228 ast_log(LOG_ERROR, "Failed to get record number %u for %s\n", num, cmd);
00229 return -1;
00230 }
00231
00232 if (!strcasecmp(args.field, "host")) {
00233 ast_copy_string(buf, host, len);
00234 } else if (!strcasecmp(args.field, "port")) {
00235 snprintf(buf, len, "%u", port);
00236 } else if (!strcasecmp(args.field, "priority")) {
00237 snprintf(buf, len, "%u", priority);
00238 } else if (!strcasecmp(args.field, "weight")) {
00239 snprintf(buf, len, "%u", weight);
00240 } else {
00241 ast_log(LOG_WARNING, "Unrecognized SRV field '%s'\n", args.field);
00242 return -1;
00243 }
00244
00245 return 0;
00246 }
00247
00248 static struct ast_custom_function srv_result_function = {
00249 .name = "SRVRESULT",
00250 .read = srv_result_read,
00251 };
00252
00253 static int unload_module(void)
00254 {
00255 int res = 0;
00256
00257 res |= ast_custom_function_unregister(&srv_query_function);
00258 res |= ast_custom_function_unregister(&srv_result_function);
00259
00260 return res;
00261 }
00262
00263 static int load_module(void)
00264 {
00265 int res = ast_custom_function_register(&srv_query_function);
00266 if (res < 0) {
00267 return AST_MODULE_LOAD_DECLINE;
00268 }
00269 res = ast_custom_function_register(&srv_result_function);
00270 if (res < 0) {
00271 return AST_MODULE_LOAD_DECLINE;
00272 }
00273
00274 return AST_MODULE_LOAD_SUCCESS;;
00275 }
00276
00277 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "SRV related dialplan functions");