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