I am new to the world of compiled programming languages. I do most of my work with Perl and bash scripting. I was recently asked to pursue a listener to the Asterisk Manager Interface that will be able to pull out caller ID information based on the extension that the call is being sent to.
I have built a basic telnet listener that will login to the asterisk box on the managers interface and supply the credentials so that it will have full access to the AMI.
my issue that I am having trouble with finding a way to parse the output and grab what i want.
reading socket to a CR+LF would be ideal so I can parse each line separately and check for conditions to exist, then process the data that I need. I have only been working with C++ for about 2 weeks now with no formal training, so I am still pretty green. Any help would be appreciated.
below is a copy of my code, names addresses and ports have been changed to protect the innocent.
/*
** client.cpp -- Asterisk Manager Interface monitor client
*/
#include <unistd.h>
#include <errno.h>
#include <string>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <iostream>
using namespace std;
#define PORT "99999" // the port client will be connecting to
#define MAXDATASIZE 512 // max number of bytes we can get at once
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main()
{
int loop = 1;
char *senddata;
char *address = "foo.com";
int sendlen;
int bytes_sent;
int sockfd, numbytes;
char buf[MAXDATASIZE];
struct addrinfo hints, *servinfo, *p;
int rv;
char s[INET6_ADDRSTRLEN];
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if ((rv = getaddrinfo(address, PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and connect to the first we can
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("client: socket");
continue;
}
if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
perror("client: connect");
continue;
}
break;
}
// exit if we cant connect
if (p == NULL) {
fprintf(stderr, "client: failed to connect\n");
return 2;
}
inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr),
s, sizeof s);
cout<<"client: connecting to " << s <<"\n";
freeaddrinfo(servinfo); // all done with this structure
// get the initial login prompt from AMI
if ((numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1) {
perror("recv");
exit(1);
}
buf[numbytes] = '\0';
cout<< buf << "\n";
// send the login information and actions to the server using the hex codes for CR+LF because \r\n was not liked by asterisk
// I should really break this out into a function, but will do that later, I really hate repeating code but it worked this way
// so I didnt want to change it until I was closer to production.
senddata = "Action: Login\x0D\x0A";
sendlen = strlen(senddata);
cout<< senddata;
if ((bytes_sent = send(sockfd, senddata, sendlen, 0)) == -1) {
perror("send");
exit(1);
}
senddata = "ActionID: 1\x0D\x0A";
sendlen = strlen(senddata);
cout<< senddata;
if ((bytes_sent = send(sockfd, senddata, sendlen, 0)) == -1) {
perror("send");
exit(1);
}
senddata = "Username: user\x0D\x0A";
sendlen = strlen(senddata);
cout<< senddata;
if ((bytes_sent = send(sockfd, senddata, sendlen, 0)) == -1) {
perror("send");
exit(1);
}
// AMI requires you to send to CR+LF to signify that you are wanting to have the login processed
senddata = "Secret: pass\x0D\x0A\x0D\x0A";
sendlen = strlen(senddata);
cout<< senddata;
if ((bytes_sent = send(sockfd, senddata, sendlen, 0)) == -1) {
perror("send");
exit(1);
}
// Now i am going to read from the socket until I kill it, I really need to make it interactive so I can close the socket nicely but this
// will have to do until I can figure out that part
while ( loop == 1 )
{
if ((numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1) {
perror("recv");
exit(1);
}
buf[numbytes] = '\0';
cout<< buf << "\n";
} // end while loop
// after i am done with the socket there is no need to keep it open
close(sockfd);
// program exited cleanly
return 0;
}// end main function