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]) | |
b52ff352 JG |
95 | filter_exp_end = filter_exp_start + filter_exp_len |
96 | ||
97 | filter_exp = data[filter_exp_start:filter_exp_end].rstrip( | |
98 | b'\0').decode() | |
99 | ||
100 | return cls(header, loglevel, loglevel_type, name, filter_exp) | |
de4dee04 PP |
101 | except (Exception) as e: |
102 | dbg._pdebug('cannot decode enable command: {}'.format(e)) | |
103 | return None | |
104 | ||
105 | ||
106 | class _ServerCmdDisable(_ServerCmd): | |
107 | def __init__(self, header, name): | |
108 | super(self.__class__, self).__init__(header) | |
109 | self.name = name | |
110 | ||
111 | @classmethod | |
112 | def from_data(cls, header, data): | |
113 | try: | |
114 | name = data.rstrip(b'\0').decode() | |
115 | ||
116 | return cls(header, name) | |
117 | except (Exception) as e: | |
118 | dbg._pdebug('cannot decode disable command: {}'.format(e)) | |
119 | return None | |
120 | ||
121 | ||
122 | class _ServerCmdRegistrationDone(_ServerCmd): | |
123 | @classmethod | |
124 | def from_data(cls, header, data): | |
125 | return cls(header) | |
126 | ||
127 | ||
128 | _SERVER_CMD_ID_TO_SERVER_CMD = { | |
129 | 1: _ServerCmdList, | |
130 | 2: _ServerCmdEnable, | |
131 | 3: _ServerCmdDisable, | |
132 | 4: _ServerCmdRegistrationDone, | |
133 | } | |
134 | ||
135 | ||
136 | def _server_cmd_from_data(header, data): | |
137 | if header.cmd_id not in _SERVER_CMD_ID_TO_SERVER_CMD: | |
138 | return None | |
139 | ||
140 | return _SERVER_CMD_ID_TO_SERVER_CMD[header.cmd_id].from_data(header, data) | |
141 | ||
142 | ||
143 | _CLIENT_CMD_REPLY_STATUS_SUCCESS = 1 | |
144 | _CLIENT_CMD_REPLY_STATUS_INVALID_CMD = 2 | |
145 | ||
146 | ||
147 | class _ClientCmdReplyHeader(object): | |
148 | _payload_struct = struct.Struct('>I') | |
149 | ||
150 | def __init__(self, status_code=_CLIENT_CMD_REPLY_STATUS_SUCCESS): | |
151 | self.status_code = status_code | |
152 | ||
153 | def get_data(self): | |
154 | return self._payload_struct.pack(self.status_code) | |
155 | ||
156 | ||
157 | class _ClientCmdReplyEnable(_ClientCmdReplyHeader): | |
158 | pass | |
159 | ||
160 | ||
161 | class _ClientCmdReplyDisable(_ClientCmdReplyHeader): | |
162 | pass | |
163 | ||
164 | ||
165 | class _ClientCmdReplyList(_ClientCmdReplyHeader): | |
166 | _nb_events_struct = struct.Struct('>I') | |
167 | _data_size_struct = struct.Struct('>I') | |
168 | ||
169 | def __init__(self, names, status_code=_CLIENT_CMD_REPLY_STATUS_SUCCESS): | |
170 | super(self.__class__, self).__init__(status_code) | |
171 | self.names = names | |
172 | ||
173 | def get_data(self): | |
174 | upper_data = super(self.__class__, self).get_data() | |
175 | nb_events_data = self._nb_events_struct.pack(len(self.names)) | |
176 | names_data = bytes() | |
177 | ||
178 | for name in self.names: | |
179 | names_data += name.encode() + b'\0' | |
180 | ||
181 | data_size_data = self._data_size_struct.pack(len(names_data)) | |
182 | ||
183 | return upper_data + data_size_data + nb_events_data + names_data | |
184 | ||
185 | ||
186 | class _ClientRegisterCmd(object): | |
187 | _payload_struct = struct.Struct('>IIII') | |
188 | ||
189 | def __init__(self, domain, pid, major, minor): | |
190 | self.domain = domain | |
191 | self.pid = pid | |
192 | self.major = major | |
193 | self.minor = minor | |
194 | ||
195 | def get_data(self): | |
196 | return self._payload_struct.pack(self.domain, self.pid, self.major, | |
197 | self.minor) |