1 // -*- c++ -*-
2 //------------------------------------------------------------------------------
3 //                               MonitorConn.cpp
4 //------------------------------------------------------------------------------
5 // $Id: MonitorConn.cpp,v 1.2 2006/07/20 02:30:55 vlg Exp $
6 //------------------------------------------------------------------------------
7 //  Copyright (c) 2003 by Vladislav Grinchenko
8 //
9 //  This program is free software; you can redistribute it and/or
10 //  modify it under the terms of the GNU General Public License
11 //  as published by the Free Software Foundation; either version
12 //  2 of the License, or (at your option) any later version.
13 //------------------------------------------------------------------------------
14 // Created: Thu Apr 17 23:22:39 EDT 2003
15 //------------------------------------------------------------------------------
16 
17 #include <assa/CommonUtils.h>
18 #include "MonitorConn.h"
19 #include "Conn.h"
20 #include "LogServer-main.h"
21 #include "LogServer.h"
22 
23 /** Convert user input to upper case
24  */
25 template <class T>
26 class ToUpper {
27 public:
operator ()(T & elem_) const28     void operator ()(T& elem_) const { elem_ = ::toupper (elem_); }
29 };
30 
31 MonitorConn::
MonitorConn(IPv4Socket * stream_)32 MonitorConn (IPv4Socket* stream_) :
33 	ServiceHandler<IPv4Socket> (stream_),
34 	m_iolen (0),
35 	m_current_conn (NULL)
36 {
37 	trace ("MonitorConn::MonitorConn");
38 
39 	m_eor [0] = 0xA;			// ASCII LF (line feed)
40 	m_eor [1] = 0xD;			// ASCII CR (carrige return)
41 }
42 
43 MonitorConn::
~MonitorConn()44 ~MonitorConn ()
45 {
46 	trace ("MonitorConn::~MonitorConn");
47 	if (m_current_conn) {
48 		m_current_conn->unsubscribe (this);
49 	}
50 	/* no-op */
51 }
52 
53 int
54 MonitorConn::
handle_close(int)55 handle_close (int /* fd */)
56 {
57 	trace("MonitorConn::handle_close");
58 
59 	DL((ASSA::APP,"=> Monitoring client disconnected\n"));
60 	delete (this);
61 	return 0;
62 }
63 
64 int
65 MonitorConn::
open()66 open ()
67 {
68 	trace("MonitorConn::open");
69 
70 	ASSA::IPv4Socket& s = *this;
71 	REACTOR->registerIOHandler (this, s.getHandler (), ASSA::READ_EVENT);
72 	DL((ASSA::APP,"=> Monitoring client connected\n"));
73 	set_id ("Logmon Client");
74 	return 0;
75 }
76 
77 void
78 MonitorConn::
notify(const char * msg_)79 notify (const char* msg_)
80 {
81 	trace("MonitorConn::notify");
82 
83 	ASSA::IPv4Socket& s = *this;
84 	static const char abort_msg [] = "DISCONNECTED\r\n";
85 
86 	if (msg_ == NULL) {
87 		s.write (abort_msg, strlen (abort_msg));
88 		m_current_conn = NULL;
89 	}
90 	else {
91 		s.write (msg_, ::strlen (msg_));
92 	}
93 	s << ASSA::flush;
94 }
95 
96 int
97 MonitorConn::
handle_read(int fd_)98 handle_read (int fd_)
99 {
100 	trace("MonitorConn::handle_read");
101 
102 	ASSA::IPv4Socket& s = *this;
103 	if (s.getHandler () != fd_) {
104 		DL ((ASSA::ASSAERR,"FDs don't match (fd_=%d != %d)\n",
105 			 fd_, s.getHandler ()));
106 		return (-1);
107 	}
108 
109 	char c = 0;
110 	int ret = 0;
111 	bool seen_eor = false;		// have we seen end-of-record?
112 
113 	while ((ret = s.read (&c, 1)) == 1 && m_iolen < MAXMSGLEN) {
114 		if (c == '\n') {
115 			continue;
116 		}
117 		if (c == '\r') {
118 			seen_eor = true;
119 			m_iobuf [m_iolen] = '\0';
120 			break;
121 		}
122 		m_iobuf [m_iolen++] = c;
123 	}
124 
125 	if (m_iolen >= MAXMSGLEN) {
126 		DL((ASSA::ASSAERR,"Message length exceeded %d bytes!\n",MAXMSGLEN));
127 		return -1;
128 	}
129 
130 	if (seen_eor) {
131 		parse_record ();
132 	}
133 
134 	return s.eof () ? -1 : s.in_avail ();
135 }
136 
137 void
138 MonitorConn::
parse_record()139 parse_record ()
140 {
141 	trace("MonitorConn::parse_record");
142 
143 	DL((ASSA::APP,"=> Message from client:\n\n%s\n\n", m_iobuf));
144 	std::vector<std::string> tokens;
145 	ASSA::Utils::split (m_iobuf, tokens);
146 	for_each (tokens [0].begin (), tokens [0].end (), ToUpper<char> ());
147 
148 	if (tokens [0] == "LIST") {
149 		process_list_cmd ();
150 	}
151 	else if (tokens [0] == "STOP") {
152 		m_current_conn->unsubscribe (this);
153 	}
154 	else if (tokens [0] == "GET") {
155 		process_get_cmd (tokens [1]);
156 	}
157 	else {
158 		DL((ASSA::APP,"Unknown command \"%s\"\n", m_iobuf));
159 	}
160 	m_iolen = 0;
161 }
162 
163 void
164 MonitorConn::
process_list_cmd()165 process_list_cmd ()
166 {
167 	trace("MonitorConn::process_list_cmd");
168 
169 	ASSA::IPv4Socket& s = *this;
170 	ASSA::Repository<Conn>::const_iterator cit = REPO->begin ();
171 	if (cit != REPO->end ()) {
172 		s.write ((*cit)->get_app_name().c_str(),
173 				 (*cit)->get_app_name().size ());
174 		cit++;
175 	}
176 	while (cit != REPO->end ()) {
177 		s.write (":", 1);
178 		s.write ((*cit)->get_app_name().c_str(),
179 				 (*cit)->get_app_name().size ());
180 		cit++;
181 	}
182 	s.write (m_eor, 2);
183 	s << ASSA::flush;
184 }
185 
186 void
187 MonitorConn::
process_get_cmd(const std::string & name_)188 process_get_cmd (const std::string& name_)
189 {
190 	trace("MonitorConn::process_get_cmd");
191 
192 	ASSA::Repository<Conn>::const_iterator cit = REPO->begin ();
193 	while (cit != REPO->end ()) {
194 		if ((*cit)->get_app_name() == name_) {
195 			m_current_conn = *cit;
196 			m_current_conn->subscribe (this);
197 			break;
198 		}
199 		cit++;
200 	}
201 }
202