1 /* 2 * Copyright (c) 2014 Sippy Software, Inc., http://www.sippysoft.com 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 */ 27 28 #include <sys/socket.h> 29 #include <sys/types.h> 30 #include <stdint.h> 31 #include <stdio.h> 32 #include <string.h> 33 34 #include "config.h" 35 36 #include "rtpp_ssrc.h" 37 #include "rtpa_stats.h" 38 #include "rtpp_log.h" 39 #include "rtpp_types.h" 40 #include "rtpp_log_obj.h" 41 #include "rtpp_analyzer.h" 42 #include "rtpp_command.h" 43 #include "rtpp_command_private.h" 44 #include "rtpp_pcount.h" 45 #include "rtpp_pcnt_strm.h" 46 #include "rtpp_pipe.h" 47 #include "rtpp_stream.h" 48 #include "rtpp_util.h" 49 #include "rtpp_command_query.h" 50 51 #define CHECK_OVERFLOW() \ 52 if (len > sizeof(cmd->buf_t) - 2) { \ 53 RTPP_LOG(spp->log, RTPP_LOG_ERR, \ 54 "QUERY: output buffer overflow"); \ 55 return (ECODE_RTOOBIG_2); \ 56 } 57 58 static int 59 handle_query_simple(struct cfg *cf, struct rtpp_command *cmd, 60 struct rtpp_pipe *spp, int idx, int verbose) 61 { 62 int len, ttl; 63 struct rtpps_pcount pcnts; 64 struct rtpp_pcnts_strm pst[2]; 65 66 ttl = CALL_METHOD(spp, get_ttl); 67 CALL_METHOD(spp->pcount, get_stats, &pcnts); 68 CALL_METHOD(spp->stream[idx]->pcnt_strm, get_stats, &pst[0]); 69 CALL_METHOD(spp->stream[NOT(idx)]->pcnt_strm, get_stats, &pst[1]); 70 if (verbose == 0) { 71 len = snprintf(cmd->buf_t, sizeof(cmd->buf_t), "%d %lu %lu %lu %lu\n", 72 ttl, pst[0].npkts_in, pst[1].npkts_in, pcnts.nrelayed, pcnts.ndropped); 73 } else { 74 len = snprintf(cmd->buf_t, sizeof(cmd->buf_t), "ttl=%d npkts_ina=%lu " 75 "npkts_ino=%lu nrelayed=%lu ndropped=%lu\n", ttl, 76 pst[0].npkts_in, pst[1].npkts_in, pcnts.nrelayed, pcnts.ndropped); 77 } 78 rtpc_doreply(cmd, cmd->buf_t, len, 0); 79 return (0); 80 } 81 82 #define PULL_RST() \ 83 if (rst_pulled == 0) { \ 84 CALL_METHOD(spp->stream[idx]->analyzer, get_stats, &rst); \ 85 rst_pulled = 1; \ 86 } 87 88 #define PULL_PCNT() \ 89 if (pcnt_pulled == 0) { \ 90 CALL_METHOD(spp->pcount, get_stats, &pcnts); \ 91 pcnt_pulled = 1; \ 92 } 93 94 #define PULL_PCNT_STRM() \ 95 if (pcnt_strm_pulled == 0) { \ 96 CALL_METHOD(spp->stream[idx]->pcnt_strm, get_stats, &pst[0]); \ 97 CALL_METHOD(spp->stream[NOT(idx)]->pcnt_strm, get_stats, &pst[1]); \ 98 pcnt_strm_pulled = 1; \ 99 } 100 101 int 102 handle_query(struct cfg *cf, struct rtpp_command *cmd, 103 struct rtpp_pipe *spp, int idx) 104 { 105 int len, i, verbose, rst_pulled, pcnt_pulled, pcnt_strm_pulled; 106 char *cp; 107 struct rtpa_stats rst; 108 struct rtpps_pcount pcnts; 109 struct rtpp_pcnts_strm pst[2]; 110 111 verbose = 0; 112 for (cp = cmd->argv[0] + 1; *cp != '\0'; cp++) { 113 switch (*cp) { 114 case 'v': 115 case 'V': 116 verbose = 1; 117 break; 118 119 default: 120 RTPP_LOG(spp->log, RTPP_LOG_ERR, 121 "QUERY: unknown command modifier `%c'", *cp); 122 return (ECODE_PARSE_8); 123 } 124 } 125 if (cmd->argc <= 4) { 126 return (handle_query_simple(cf, cmd, spp, idx, verbose)); 127 } 128 len = 0; 129 rst_pulled = pcnt_pulled = pcnt_strm_pulled = 0; 130 for (i = 4; i < cmd->argc && len < (sizeof(cmd->buf_t) - 2); i++) { 131 if (i > 4) { 132 CHECK_OVERFLOW(); 133 len += snprintf(cmd->buf_t + len, sizeof(cmd->buf_t) - len, " "); 134 } 135 if (verbose != 0) { 136 CHECK_OVERFLOW(); 137 len += snprintf(cmd->buf_t + len, sizeof(cmd->buf_t) - len, "%s=", \ 138 cmd->argv[i]); 139 } 140 CHECK_OVERFLOW(); 141 if (strcmp(cmd->argv[i], "ttl") == 0) { 142 int ttl = CALL_METHOD(spp, get_ttl); 143 len += snprintf(cmd->buf_t + len, sizeof(cmd->buf_t) - len, "%d", 144 ttl); 145 continue; 146 } 147 if (strcmp(cmd->argv[i], "npkts_ina") == 0) { 148 PULL_PCNT_STRM(); 149 len += snprintf(cmd->buf_t + len, sizeof(cmd->buf_t) - len, "%lu", 150 pst[0].npkts_in); 151 continue; 152 } 153 if (strcmp(cmd->argv[i], "npkts_ino") == 0) { 154 PULL_PCNT_STRM(); 155 len += snprintf(cmd->buf_t + len, sizeof(cmd->buf_t) - len, "%lu", 156 pst[1].npkts_in); 157 continue; 158 } 159 if (strcmp(cmd->argv[i], "nrelayed") == 0) { 160 PULL_PCNT(); 161 len += snprintf(cmd->buf_t + len, sizeof(cmd->buf_t) - len, "%lu", 162 pcnts.nrelayed); 163 continue; 164 } 165 if (strcmp(cmd->argv[i], "ndropped") == 0) { 166 PULL_PCNT(); 167 len += snprintf(cmd->buf_t + len, sizeof(cmd->buf_t) - len, "%lu", 168 pcnts.ndropped); 169 continue; 170 } 171 if (strcmp(cmd->argv[i], "rtpa_nsent") == 0) { 172 PULL_RST(); 173 len += snprintf(cmd->buf_t + len, sizeof(cmd->buf_t) - len, "%lu", 174 rst.psent); 175 continue; 176 } 177 if (strcmp(cmd->argv[i], "rtpa_nrcvd") == 0) { 178 PULL_RST(); 179 len += snprintf(cmd->buf_t + len, sizeof(cmd->buf_t) - len, "%lu", 180 rst.precvd); 181 continue; 182 } 183 if (strcmp(cmd->argv[i], "rtpa_ndups") == 0) { 184 PULL_RST(); 185 len += snprintf(cmd->buf_t + len, sizeof(cmd->buf_t) - len, "%lu", 186 rst.pdups); 187 continue; 188 } 189 if (strcmp(cmd->argv[i], "rtpa_nlost") == 0) { 190 PULL_RST(); 191 len += snprintf(cmd->buf_t + len, sizeof(cmd->buf_t) - len, "%lu", 192 rst.plost); 193 continue; 194 } 195 if (strcmp(cmd->argv[i], "rtpa_perrs") == 0) { 196 PULL_RST(); 197 len += snprintf(cmd->buf_t + len, sizeof(cmd->buf_t) - len, "%lu", 198 rst.pecount); 199 continue; 200 } 201 RTPP_LOG(spp->log, RTPP_LOG_ERR, 202 "QUERY: unsupported/invalid counter name `%s'", cmd->argv[i]); 203 return (ECODE_QRYFAIL); 204 } 205 CHECK_OVERFLOW(); 206 len += snprintf(cmd->buf_t + len, sizeof(cmd->buf_t) - len, "\n"); 207 rtpc_doreply(cmd, cmd->buf_t, len, 0); 208 return (0); 209 } 210