|
160 | 160 | <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>
|
161 | 161 | </description>
|
162 | 162 | </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> |
163 | 181 | ***/
|
164 | 182 |
|
165 | 183 | static const char app[] = "Softmodem";
|
@@ -234,6 +252,7 @@ typedef struct {
|
234 | 252 | volatile int finished;
|
235 | 253 | int paritytype;
|
236 | 254 | unsigned int flipmode:1;
|
| 255 | + unsigned int track_session:1; |
237 | 256 | } modem_session;
|
238 | 257 |
|
239 | 258 | #define MODEM_BITBUFFER_SIZE 16
|
@@ -678,6 +697,107 @@ struct ast_generator v18_generator = {
|
678 | 697 | generate: v18_generator_generate,
|
679 | 698 | };
|
680 | 699 |
|
| 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 | + |
681 | 801 | static int softmodem_communicate(modem_session *s, int tls)
|
682 | 802 | {
|
683 | 803 | int res = -1;
|
@@ -743,11 +863,24 @@ static int softmodem_communicate(modem_session *s, int tls)
|
743 | 863 | ast_autoservice_start(s->chan);
|
744 | 864 |
|
745 | 865 | 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)); |
747 | 867 | ast_autoservice_stop(s->chan);
|
748 | 868 | return res;
|
749 | 869 | }
|
750 | 870 |
|
| 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 | + |
751 | 884 | ast_autoservice_stop(s->chan);
|
752 | 885 |
|
753 | 886 | fcntl(sock, F_SETFL, O_NONBLOCK);
|
@@ -1161,17 +1294,25 @@ static int softmodem_exec(struct ast_channel *chan, const char *data)
|
1161 | 1294 | session.flipmode = ast_test_flag(&options, OPT_FLIP_MODE) ? 1 : 0;
|
1162 | 1295 | }
|
1163 | 1296 |
|
| 1297 | + session.track_session = 1; |
1164 | 1298 | res = softmodem_communicate(&session, ast_test_flag(&options, OPT_TLS));
|
| 1299 | + if (session.track_session) { |
| 1300 | + untrack_session(&session); |
| 1301 | + } |
1165 | 1302 | return res;
|
1166 | 1303 | }
|
1167 | 1304 |
|
1168 | 1305 | static int unload_module(void)
|
1169 | 1306 | {
|
| 1307 | + ast_manager_unregister("SoftmodemSessions"); |
1170 | 1308 | return ast_unregister_application(app);
|
1171 | 1309 | }
|
1172 | 1310 |
|
1173 | 1311 | static int load_module(void)
|
1174 | 1312 | {
|
| 1313 | + if (ast_manager_register_xml("SoftmodemSessions", EVENT_FLAG_CALL, manager_softmodem_sessions)) { |
| 1314 | + return -1; |
| 1315 | + } |
1175 | 1316 | return ast_register_application_xml(app, softmodem_exec);
|
1176 | 1317 | }
|
1177 | 1318 |
|
|
0 commit comments