Commit | Line | Data |
---|---|---|
de4dee04 PP |
1 | # -*- coding: utf-8 -*- |
2 | # | |
3 | # Copyright (C) 2015 - Philippe Proulx <pproulx@efficios.com> | |
4 | # Copyright (C) 2014 - David Goulet <dgoulet@efficios.com> | |
b52ff352 | 5 | # Copyright (C) 2015 - Jérémie Galarneau <jeremie.galarneau@efficios.com> |
de4dee04 PP |
6 | # |
7 | # This library is free software; you can redistribute it and/or modify it under | |
8 | # the terms of the GNU Lesser General Public License as published by the Free | |
9 | # Software Foundation; version 2.1 of the License. | |
10 | # | |
11 | # This library is distributed in the hope that it will be useful, but WITHOUT | |
12 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |
13 | # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | |
14 | # details. | |
15 | # | |
16 | # You should have received a copy of the GNU Lesser General Public License | |
17 | # along with this library; if not, write to the Free Software Foundation, Inc., | |
18 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
19 | ||
20 | from __future__ import unicode_literals | |
21 | import lttngust.debug as dbg | |
22 | import struct | |
23 | ||
24 | ||
25 | # server command header | |
26 | _server_cmd_header_struct = struct.Struct('>QII') | |
27 | ||
28 | ||
29 | # server command header size | |
30 | _SERVER_CMD_HEADER_SIZE = _server_cmd_header_struct.size | |
31 | ||
32 | ||
b52ff352 JG |
33 | # agent protocol symbol size |
34 | _LTTNG_SYMBOL_NAME_LEN = 256 | |
35 | ||
36 | ||
de4dee04 PP |
37 | class _ServerCmdHeader(object): |
38 | def __init__(self, data_size, cmd_id, cmd_version): | |
39 | self.data_size = data_size | |
40 | self.cmd_id = cmd_id | |
41 | self.cmd_version = cmd_version | |
42 | ||
43 | ||
44 | def _server_cmd_header_from_data(data): | |
45 | try: | |
46 | data_size, cmd_id, cmd_version = _server_cmd_header_struct.unpack(data) | |
47 | except (Exception) as e: | |
48 | dbg._pdebug('cannot decode command header: {}'.format(e)) | |
49 | return None | |
50 | ||
51 | return _ServerCmdHeader(data_size, cmd_id, cmd_version) | |
52 | ||
53 | ||
54 | class _ServerCmd(object): | |
55 | def __init__(self, header): | |
56 | self.header = header | |
57 | ||
58 | @classmethod | |
59 | def from_data(cls, header, data): | |
60 | raise NotImplementedError() | |
61 | ||
62 | ||
63 | class _ServerCmdList(_ServerCmd): | |
64 | @classmethod | |
65 | def from_data(cls, header, data): | |
66 | return cls(header) | |
67 | ||
68 | ||
69 | class _ServerCmdEnable(_ServerCmd): | |
70 | _NAME_OFFSET = 8 | |
71 | _loglevel_struct = struct.Struct('>II') | |
b52ff352 JG |
72 | # filter expression size |
73 | _filter_exp_len_struct = struct.Struct('>I') | |
de4dee04 | 74 | |
b52ff352 | 75 | def __init__(self, header, loglevel, loglevel_type, name, filter_exp): |
de4dee04 PP |
76 | super(self.__class__, self).__init__(header) |
77 | self.loglevel = loglevel | |
78 | self.loglevel_type = loglevel_type | |
79 | self.name = name | |
b52ff352 JG |
80 | self.filter_expression = filter_exp |
81 | dbg._pdebug('server enable command {}'.format(self.__dict__)) | |
de4dee04 PP |
82 | |
83 | @classmethod | |
84 | def from_data(cls, header, data): | |
85 | try: | |
86 | loglevel, loglevel_type = cls._loglevel_struct.unpack_from(data) | |
b52ff352 JG |
87 | name_start = cls._loglevel_struct.size |
88 | name_end = name_start + _LTTNG_SYMBOL_NAME_LEN | |
89 | data_name = data[name_start:name_end] | |
de4dee04 PP |
90 | name = data_name.rstrip(b'\0').decode() |
91 | ||
b52ff352 JG |
92 | filter_exp_start = name_end + cls._filter_exp_len_struct.size |
93 | filter_exp_len, = cls._filter_exp_len_struct.unpack_from( | |
94 | data[name_end:filter_exp_start]) | |
95 | print(filter_exp_len) | |
96 | filter_exp_end = filter_exp_start + filter_exp_len | |
97 | ||
98 | filter_exp = data[filter_exp_start:filter_exp_end].rstrip( | |
99 | b'\0').decode() | |
100 | ||
101 | return cls(header, loglevel, loglevel_type, name, filter_exp) | |
de4dee04 PP |
102 | except (Exception) as e: |
103 | dbg._pdebug('cannot decode enable command: {}'.format(e)) | |
104 | return None | |
105 | ||
106 | ||
107 | class _ServerCmdDisable(_ServerCmd): | |
108 | def __init__(self, header, name): | |
109 | super(self.__class__, self).__init__(header) | |
110 | self.name = name | |
111 | ||
112 | @classmethod | |
113 | def from_data(cls, header, data): | |
114 | try: | |
115 | name = data.rstrip(b'\0').decode() | |
116 | ||
117 | return cls(header, name) | |
118 | except (Exception) as e: | |
119 | dbg._pdebug('cannot decode disable command: {}'.format(e)) | |
120 | return None | |
121 | ||
122 | ||
123 | class _ServerCmdRegistrationDone(_ServerCmd): | |
124 | @classmethod | |
125 | def from_data(cls, header, data): | |
126 | return cls(header) | |
127 | ||
128 | ||
129 | _SERVER_CMD_ID_TO_SERVER_CMD = { | |
130 | 1: _ServerCmdList, | |
131 | 2: _ServerCmdEnable, | |
132 | 3: _ServerCmdDisable, | |
133 | 4: _ServerCmdRegistrationDone, | |
134 | } | |
135 | ||
136 | ||
137 | def _server_cmd_from_data(header, data): | |
138 | if header.cmd_id not in _SERVER_CMD_ID_TO_SERVER_CMD: | |
139 | return None | |
140 | ||
141 | return _SERVER_CMD_ID_TO_SERVER_CMD[header.cmd_id].from_data(header, data) | |
142 | ||
143 | ||
144 | _CLIENT_CMD_REPLY_STATUS_SUCCESS = 1 | |
145 | _CLIENT_CMD_REPLY_STATUS_INVALID_CMD = 2 | |
146 | ||
147 | ||
148 | class _ClientCmdReplyHeader(object): | |
149 | _payload_struct = struct.Struct('>I') | |
150 | ||
151 | def __init__(self, status_code=_CLIENT_CMD_REPLY_STATUS_SUCCESS): | |
152 | self.status_code = status_code | |
153 | ||
154 | def get_data(self): | |
155 | return self._payload_struct.pack(self.status_code) | |
156 | ||
157 | ||
158 | class _ClientCmdReplyEnable(_ClientCmdReplyHeader): | |
159 | pass | |
160 | ||
161 | ||
162 | class _ClientCmdReplyDisable(_ClientCmdReplyHeader): | |
163 | pass | |
164 | ||
165 | ||
166 | class _ClientCmdReplyList(_ClientCmdReplyHeader): | |
167 | _nb_events_struct = struct.Struct('>I') | |
168 | _data_size_struct = struct.Struct('>I') | |
169 | ||
170 | def __init__(self, names, status_code=_CLIENT_CMD_REPLY_STATUS_SUCCESS): | |
171 | super(self.__class__, self).__init__(status_code) | |
172 | self.names = names | |
173 | ||
174 | def get_data(self): | |
175 | upper_data = super(self.__class__, self).get_data() | |
176 | nb_events_data = self._nb_events_struct.pack(len(self.names)) | |
177 | names_data = bytes() | |
178 | ||
179 | for name in self.names: | |
180 | names_data += name.encode() + b'\0' | |
181 | ||
182 | data_size_data = self._data_size_struct.pack(len(names_data)) | |
183 | ||
184 | return upper_data + data_size_data + nb_events_data + names_data | |
185 | ||
186 | ||
187 | class _ClientRegisterCmd(object): | |
188 | _payload_struct = struct.Struct('>IIII') | |
189 | ||
190 | def __init__(self, domain, pid, major, minor): | |
191 | self.domain = domain | |
192 | self.pid = pid | |
193 | self.major = major | |
194 | self.minor = minor | |
195 | ||
196 | def get_data(self): | |
197 | return self._payload_struct.pack(self.domain, self.pid, self.major, | |
198 | self.minor) |