Skip to content

Commit a8f60e0

Browse files
committed
app_softmodem: Add AMI command to retrieve list of active sessions.
Add an AMI command that will retrieve a list of active Softmodem sessions (currently, all sessions are automatically tracked, though this could be put behind an optional option if needed). This allows an external program that is the target of a TCP connection initiated by the softmodem to determine the identity of the caller, by using the TCP port to correlate the session. One use case of this is to retrieve the Caller ID of the modem caller from the TCP server, which could be used for identification, authentication, or various other purposes.
1 parent e133437 commit a8f60e0

File tree

1 file changed

+142
-1
lines changed

1 file changed

+142
-1
lines changed

apps/app_softmodem.c

Lines changed: 142 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,24 @@
160160
<para>Simulates a FSK(V.23), V.22bis, or Baudot modem. The modem on the other end is connected to the specified server using a simple TCP connection (like Telnet).</para>
161161
</description>
162162
</application>
163+
<manager name="SoftmodemSessions" language="en_US" module="res_xmpp">
164+
<synopsis>
165+
List all tracked softmodem sessions.
166+
</synopsis>
167+
<syntax>
168+
<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
169+
<parameter name="Port" required="false">
170+
<para>Port used by softmodem client for connection. This is the local client port,
171+
not the remote server-side port to which the client connected.</para>
172+
<para>If provided, only the session with this local port will be returned.
173+
This can be used to retrieve information about a softmodem session from
174+
another system, which can correlate the session using the TCP port number.</para>
175+
</parameter>
176+
</syntax>
177+
<description>
178+
<para>List information about actively tracked softmodem sessions.</para>
179+
</description>
180+
</manager>
163181
***/
164182

165183
static const char app[] = "Softmodem";
@@ -234,6 +252,7 @@ typedef struct {
234252
volatile int finished;
235253
int paritytype;
236254
unsigned int flipmode:1;
255+
unsigned int track_session:1;
237256
} modem_session;
238257

239258
#define MODEM_BITBUFFER_SIZE 16
@@ -678,6 +697,107 @@ struct ast_generator v18_generator = {
678697
generate: v18_generator_generate,
679698
};
680699

700+
struct softmodem_session {
701+
struct ast_channel *chan; /* The channel itself cannot go away while this application is using it, even with a masquerade, so storing the channel pointer is safe */
702+
int port;
703+
time_t started;
704+
AST_RWLIST_ENTRY(softmodem_session) entry;
705+
};
706+
707+
static AST_RWLIST_HEAD_STATIC(sessions, softmodem_session);
708+
709+
static void untrack_session(modem_session *s)
710+
{
711+
struct softmodem_session *ss;
712+
int port = 0;
713+
714+
AST_RWLIST_WRLOCK(&sessions);
715+
AST_RWLIST_TRAVERSE_SAFE_BEGIN(&sessions, ss, entry) {
716+
if (ss->chan == s->chan) {
717+
AST_RWLIST_REMOVE_CURRENT(entry);
718+
port = ss->port;
719+
ast_free(ss);
720+
break;
721+
}
722+
}
723+
AST_RWLIST_TRAVERSE_SAFE_END;
724+
AST_RWLIST_UNLOCK(&sessions);
725+
if (!ss) {
726+
ast_log(LOG_WARNING, "Couldn't find tracked softmodem session in session list?\n");
727+
} else {
728+
ast_debug(3, "Removed session %d from track list\n", port);
729+
}
730+
}
731+
732+
static void track_session(modem_session *s, int lport)
733+
{
734+
struct softmodem_session *ss;
735+
736+
ss = ast_calloc(1, sizeof(*ss));
737+
if (!ss) {
738+
return;
739+
}
740+
ss->chan = s->chan;
741+
ss->port = lport;
742+
ss->started = time(NULL);
743+
AST_RWLIST_WRLOCK(&sessions);
744+
AST_RWLIST_INSERT_HEAD(&sessions, ss, entry);
745+
AST_RWLIST_UNLOCK(&sessions);
746+
ast_debug(3, "Added session %d to track list\n", lport);
747+
}
748+
749+
static int manager_softmodem_sessions(struct mansession *s, const struct message *m)
750+
{
751+
const char *actionid = astman_get_header(m, "ActionID");
752+
const char *portstr = astman_get_header(m, "Port");
753+
char idText[256];
754+
struct softmodem_session *ss;
755+
int sessions_found = 0;
756+
unsigned int port = 0;
757+
time_t now = time(NULL);
758+
759+
if (!ast_strlen_zero(portstr)) {
760+
port = atoi(portstr);
761+
}
762+
763+
if (!ast_strlen_zero(actionid)) {
764+
snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
765+
} else {
766+
idText[0] = '\0';
767+
}
768+
astman_send_listack(s, m, "Sessions will follow", "start");
769+
770+
AST_RWLIST_RDLOCK(&sessions);
771+
AST_RWLIST_TRAVERSE(&sessions, ss, entry) {
772+
time_t elapsed;
773+
if (port && ss->port != port) {
774+
continue; /* Doesn't match filter */
775+
}
776+
elapsed = (long int) (now - ss->started);
777+
sessions_found++;
778+
astman_append(s,
779+
"Event: SoftmodemSession\r\n"
780+
"%s"
781+
"Channel: %s\r\n"
782+
"CallerIDNumber: %s\r\n"
783+
"CallerIDName: %s\r\n"
784+
"Port: %d\r\n"
785+
"Duration: %ld\r\n"
786+
"\r\n",
787+
idText,
788+
ast_channel_name(ss->chan),
789+
S_OR(ast_channel_caller(ss->chan)->id.number.str, "<unknown>"),
790+
S_OR(ast_channel_caller(ss->chan)->id.name.str, "<unknown>"),
791+
ss->port, elapsed);
792+
}
793+
AST_RWLIST_UNLOCK(&sessions);
794+
795+
astman_send_list_complete_start(s, m, "SoftmodemSessionsComplete", sessions_found);
796+
astman_append(s, "Total: %d\r\n", sessions_found);
797+
astman_send_list_complete_end(s);
798+
return 0;
799+
}
800+
681801
static int softmodem_communicate(modem_session *s, int tls)
682802
{
683803
int res = -1;
@@ -743,11 +863,24 @@ static int softmodem_communicate(modem_session *s, int tls)
743863
ast_autoservice_start(s->chan);
744864

745865
if (connect(sock, (struct sockaddr*)&server, sizeof(server)) < 0) {
746-
ast_log(LOG_ERROR, "Cannot connect to remote host: '%s': %s\n", s->host, strerror(errno));
866+
ast_log(LOG_ERROR, "Cannot connect to remote host '%s': %s\n", s->host, strerror(errno));
747867
ast_autoservice_stop(s->chan);
748868
return res;
749869
}
750870

871+
if (s->track_session) {
872+
int lport;
873+
struct sockaddr_in sin;
874+
socklen_t slen = sizeof(sin);
875+
/* Figure out what port we're using locally for this connection */
876+
if (getsockname(sock, (struct sockaddr *) &sin, &slen)) {
877+
ast_log(LOG_WARNING, "getsockname failed: %s\n", strerror(errno));
878+
} else {
879+
lport = ntohs(sin.sin_port);
880+
track_session(s, lport);
881+
}
882+
}
883+
751884
ast_autoservice_stop(s->chan);
752885

753886
fcntl(sock, F_SETFL, O_NONBLOCK);
@@ -1161,17 +1294,25 @@ static int softmodem_exec(struct ast_channel *chan, const char *data)
11611294
session.flipmode = ast_test_flag(&options, OPT_FLIP_MODE) ? 1 : 0;
11621295
}
11631296

1297+
session.track_session = 1;
11641298
res = softmodem_communicate(&session, ast_test_flag(&options, OPT_TLS));
1299+
if (session.track_session) {
1300+
untrack_session(&session);
1301+
}
11651302
return res;
11661303
}
11671304

11681305
static int unload_module(void)
11691306
{
1307+
ast_manager_unregister("SoftmodemSessions");
11701308
return ast_unregister_application(app);
11711309
}
11721310

11731311
static int load_module(void)
11741312
{
1313+
if (ast_manager_register_xml("SoftmodemSessions", EVENT_FLAG_CALL, manager_softmodem_sessions)) {
1314+
return -1;
1315+
}
11751316
return ast_register_application_xml(app, softmodem_exec);
11761317
}
11771318

0 commit comments

Comments
 (0)