1 /* 2 * Copyright (c) 2004-2006 Maxim Sobolev <sobomax@FreeBSD.org> 3 * Copyright (c) 2006-2014 Sippy Software, Inc., http://www.sippysoft.com 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 */ 28 29 #include <sys/types.h> 30 #include <sys/socket.h> 31 #include <stdint.h> 32 #include <stdlib.h> 33 34 #include "rtpp_log.h" 35 #include "rtpp_cfg_stable.h" 36 #include "rtpp_defines.h" 37 #include "rtpp_command.h" 38 #include "rtpp_command_parse.h" 39 #include "rtpp_command_private.h" 40 #include "rtpp_command_query.h" 41 #include "rtpp_types.h" 42 #include "rtpp_stats.h" 43 #include "rtpp_log_obj.h" 44 45 struct cmd_props { 46 int max_argc; 47 int min_argc; 48 int has_cmods; 49 int has_call_id; 50 int fpos; 51 int tpos; 52 char *cmods; 53 }; 54 55 static int 56 fill_cmd_props(struct cfg *cf, struct rtpp_command *cmd, 57 struct cmd_props *cpp) 58 { 59 60 cpp->has_call_id = 1; 61 cpp->fpos = -1; 62 cpp->tpos = -1; 63 cpp->cmods = &(cmd->argv[0][1]); 64 switch (cmd->argv[0][0]) { 65 case 'u': 66 case 'U': 67 cmd->cca.op = UPDATE; 68 cmd->cca.rname = "update/create"; 69 cmd->cca.hint = "U[opts] callid remote_ip remote_port from_tag [to_tag] [notify_socket notify_tag]"; 70 cpp->max_argc = 8; 71 cpp->min_argc = 5; 72 cpp->has_cmods = 1; 73 cpp->fpos = 4; 74 cpp->tpos = 5; 75 break; 76 77 case 'l': 78 case 'L': 79 cmd->cca.op = LOOKUP; 80 cmd->cca.rname = "lookup"; 81 cmd->cca.hint = "L[opts] callid remote_ip remote_port from_tag [to_tag]"; 82 cpp->max_argc = 6; 83 cpp->min_argc = 5; 84 cpp->has_cmods = 1; 85 cpp->fpos = 4; 86 cpp->tpos = 5; 87 break; 88 89 case 'd': 90 case 'D': 91 cmd->cca.op = DELETE; 92 cmd->cca.rname = "delete"; 93 cmd->cca.hint = "D[w] callid from_tag [to_tag]"; 94 cpp->max_argc = 4; 95 cpp->min_argc = 3; 96 cpp->has_cmods = 1; 97 cpp->fpos = 2; 98 cpp->tpos = 3; 99 break; 100 101 case 'p': 102 case 'P': 103 cmd->cca.op = PLAY; 104 cmd->cca.rname = "play"; 105 cmd->cca.hint = "P[n] callid pname codecs from_tag [to_tag]"; 106 cpp->max_argc = 6; 107 cpp->min_argc = 5; 108 cpp->has_cmods = 1; 109 cpp->fpos = 4; 110 cpp->tpos = 5; 111 break; 112 113 case 'r': 114 case 'R': 115 cmd->cca.op = RECORD; 116 cmd->cca.rname = "record"; 117 if (cf->stable->record_pcap != 0) { 118 cmd->cca.hint = "R[s] call_id from_tag [to_tag]"; 119 } else { 120 cmd->cca.hint = "R call_id from_tag [to_tag]"; 121 } 122 cpp->max_argc = 4; 123 cpp->min_argc = 3; 124 cpp->has_cmods = 1; 125 cpp->fpos = 2; 126 cpp->tpos = 3; 127 break; 128 129 case 'c': 130 case 'C': 131 cmd->cca.op = COPY; 132 cmd->cca.rname = "copy"; 133 cmd->cca.hint = "C[-xxx-] call_id -XXX- from_tag [to_tag]"; 134 cpp->max_argc = 5; 135 cpp->min_argc = 4; 136 cpp->has_cmods = 1; 137 cpp->fpos = 3; 138 cpp->tpos = 4; 139 break; 140 141 case 's': 142 case 'S': 143 cmd->cca.op = NOPLAY; 144 cmd->cca.rname = "noplay"; 145 cmd->cca.hint = "S call_id from_tag [to_tag]"; 146 cpp->max_argc = 4; 147 cpp->min_argc = 3; 148 cpp->has_cmods = 0; 149 cpp->fpos = 2; 150 cpp->tpos = 3; 151 break; 152 153 case 'v': 154 case 'V': 155 if (cpp->cmods[0] == 'F' || cpp->cmods[0] == 'f') { 156 cpp->cmods += 1; 157 cmd->cca.op = VER_FEATURE; 158 cmd->cca.rname = "feature_check"; 159 cmd->cca.hint = "VF feature_num"; 160 cmd->no_glock = 1; 161 cpp->max_argc = 2; 162 cpp->min_argc = 2; 163 cpp->has_cmods = 0; 164 cpp->has_call_id = 0; 165 break; 166 } 167 cmd->cca.op = GET_VER; 168 cmd->cca.rname = "get_version"; 169 cmd->cca.hint = "V"; 170 cmd->no_glock = 1; 171 cpp->max_argc = 1; 172 cpp->min_argc = 1; 173 cpp->has_cmods = 0; 174 cpp->has_call_id = 0; 175 break; 176 177 case 'i': 178 case 'I': 179 cmd->cca.op = INFO; 180 cmd->cca.rname = "get_info"; 181 cmd->cca.hint = "I[b]"; 182 cpp->max_argc = 1; 183 cpp->min_argc = 1; 184 cpp->has_cmods = 1; 185 cpp->has_call_id = 0; 186 break; 187 188 case 'q': 189 case 'Q': 190 cmd->cca.op = QUERY; 191 cmd->cca.rname = "query"; 192 cmd->cca.hint = "Q[v] call_id from_tag [to_tag [stat_name1 ...[stat_nameN]]]"; 193 cpp->max_argc = 4 + RTPP_QUERY_NSTATS; 194 cpp->min_argc = 3; 195 cpp->has_cmods = 1; 196 cpp->fpos = 2; 197 cpp->tpos = 3; 198 break; 199 200 case 'x': 201 case 'X': 202 cmd->cca.op = DELETE_ALL; 203 cmd->cca.rname = "delete_all"; 204 cmd->cca.hint = "X"; 205 cpp->max_argc = 1; 206 cpp->min_argc = 1; 207 cpp->has_cmods = 0; 208 cpp->has_call_id = 0; 209 break; 210 211 case 'g': 212 case 'G': 213 cmd->cca.op = GET_STATS; 214 cmd->cca.rname = "get_stats"; 215 cmd->cca.hint = "G[v] [stat_name1 [stat_name2 [stat_name3 ...[stat_nameN]]]]"; 216 cmd->no_glock = 1; 217 cpp->max_argc = CALL_METHOD(cf->stable->rtpp_stats, getnstats) + 1; 218 cpp->min_argc = 1; 219 cpp->has_cmods = 1; 220 cpp->has_call_id = 0; 221 break; 222 223 default: 224 return (-1); 225 } 226 return (0); 227 } 228 229 int 230 rtpp_command_pre_parse(struct cfg *cf, struct rtpp_command *cmd) 231 { 232 struct cmd_props cprops; 233 234 if (fill_cmd_props(cf, cmd, &cprops) != 0) { 235 RTPP_LOG(cf->stable->glog, RTPP_LOG_ERR, "unknown command \"%c\"", 236 cmd->argv[0][0]); 237 reply_error(cmd, ECODE_CMDUNKN); 238 return (-1); 239 } 240 if (cmd->argc < cprops.min_argc || cmd->argc > cprops.max_argc) { 241 RTPP_LOG(cf->stable->glog, RTPP_LOG_ERR, "%s command syntax error" 242 ": invalid number of arguments (%d)", cmd->cca.rname, cmd->argc); 243 reply_error(cmd, ECODE_PARSE_NARGS); 244 return (-1); 245 } 246 if (cprops.has_cmods == 0 && cprops.cmods[0] != '\0') { 247 RTPP_LOG(cf->stable->glog, RTPP_LOG_ERR, "%s command syntax error" 248 ": modifiers are not supported by the command", cmd->cca.rname); 249 reply_error(cmd, ECODE_PARSE_MODS); 250 return (-1); 251 } 252 cmd->cca.call_id = cprops.has_call_id ? cmd->argv[1] : NULL; 253 cmd->cca.from_tag = cprops.fpos > 0 ? cmd->argv[cprops.fpos] : NULL; 254 cmd->cca.to_tag = cprops.tpos > 0 ? cmd->argv[cprops.tpos] : NULL; 255 return (0); 256 } 257