Python agent: Support Agent protocol v2.0
[deliverable/lttng-ust.git] / liblttng-ust-python-agent / lttngust / cmd.py
1 # -*- coding: utf-8 -*-
2 #
3 # Copyright (C) 2015 - Philippe Proulx <pproulx@efficios.com>
4 # Copyright (C) 2014 - David Goulet <dgoulet@efficios.com>
5 # Copyright (C) 2015 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
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
33 # agent protocol symbol size
34 _LTTNG_SYMBOL_NAME_LEN = 256
35
36
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')
72 # filter expression size
73 _filter_exp_len_struct = struct.Struct('>I')
74
75 def __init__(self, header, loglevel, loglevel_type, name, filter_exp):
76 super(self.__class__, self).__init__(header)
77 self.loglevel = loglevel
78 self.loglevel_type = loglevel_type
79 self.name = name
80 self.filter_expression = filter_exp
81 dbg._pdebug('server enable command {}'.format(self.__dict__))
82
83 @classmethod
84 def from_data(cls, header, data):
85 try:
86 loglevel, loglevel_type = cls._loglevel_struct.unpack_from(data)
87 name_start = cls._loglevel_struct.size
88 name_end = name_start + _LTTNG_SYMBOL_NAME_LEN
89 data_name = data[name_start:name_end]
90 name = data_name.rstrip(b'\0').decode()
91
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)
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)
This page took 0.034345 seconds and 5 git commands to generate.