Python agent: Support Agent protocol v2.0
[lttng-ust.git] / liblttng-ust-python-agent / lttngust / cmd.py
CommitLineData
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
20from __future__ import unicode_literals
21import lttngust.debug as dbg
22import 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
37class _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
44def _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
54class _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
63class _ServerCmdList(_ServerCmd):
64 @classmethod
65 def from_data(cls, header, data):
66 return cls(header)
67
68
69class _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
107class _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
123class _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
137def _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
148class _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
158class _ClientCmdReplyEnable(_ClientCmdReplyHeader):
159 pass
160
161
162class _ClientCmdReplyDisable(_ClientCmdReplyHeader):
163 pass
164
165
166class _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
187class _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.031305 seconds and 4 git commands to generate.