*/
bRC METAPLUGIN::queryParameter(bpContext *ctx, struct query_pkt *qp)
{
- bRC ret = bRC_More;
- OutputWriter ow(qp->api_opts);
- POOL_MEM cmd(PM_MESSAGE);
- char *p, *q, *t;
- alist values(10, not_owned_by_alist);
- key_pair *kp;
-
DMSG0(ctx, D1, "METAPLUGIN::queryParameter\n");
// check if it is our Plugin command
}
}
+ POOL_MEM cmd(PM_MESSAGE);
+
if (listing == None) {
listing = Query;
Mmsg(cmd, "%s query=%s", qp->command, qp->parameter);
}
/* read backend response */
- if (backend.ctx->read_command(ctx, cmd) < 0){
+ char pkt = 0;
+ int32_t pktlen = backend.ctx->read_any(ctx, &pkt, cmd);
+ if (pktlen < 0) {
DMSG(ctx, DERROR, "Cannot read backend query response for %s command.\n", qp->parameter);
JMSG(ctx, backend.ctx->jmsg_err_level(), "Cannot read backend query response for %s command.\n", qp->parameter);
return bRC_Error;
}
+ bRC ret = bRC_More;
+
/* check EOD */
if (backend.ctx->is_eod()){
/* got EOD so the backend finish response, so terminate the chat */
qp->result = NULL;
ret = bRC_OK;
} else {
- /*
- * here we have:
- * key=value[,key2=value2[,...]]
- * parameters we should decompose
- */
- p = cmd.c_str();
- while (*p != '\0'){
- q = strchr(p, ',');
- if (q != NULL){
- *q++ = '\0';
- }
- // single key=value
- DMSG(ctx, D1, "METAPLUGIN::queryParameter:scan %s\n", p);
- if ((t = strchr(p, '=')) != NULL){
- *t++ = '\0';
- } else {
- t = (char*)""; // pointer to empty string
- }
- DMSG2(ctx, D1, "METAPLUGIN::queryParameter:pair '%s' = '%s'\n", p, t);
- if (strlen(p) > 0){
- // push values only when we have key name
- kp = New(key_pair(p, t));
- values.append(kp);
- }
- p = q != NULL ? q : (char*)"";
- }
+ switch (pkt)
+ {
+ case 'C':
+ {
+ OutputWriter ow(qp->api_opts);
+ char *p, *q, *t;
+ alist values(10, not_owned_by_alist);
+ key_pair *kp;
+
+ /*
+ * here we have:
+ * key=value[,key2=value2[,...]]
+ * parameters we should decompose
+ */
+ p = cmd.c_str();
+ while (*p != '\0') {
+ q = strchr(p, ',');
+ if (q != NULL) {
+ *q++ = '\0';
+ }
+ // single key=value
+ DMSG(ctx, D1, "METAPLUGIN::queryParameter:scan %s\n", p);
+ if ((t = strchr(p, '=')) != NULL) {
+ *t++ = '\0';
+ } else {
+ t = (char*)""; // pointer to empty string
+ }
+ DMSG2(ctx, D1, "METAPLUGIN::queryParameter:pair '%s' = '%s'\n", p, t);
+ if (strlen(p) > 0) {
+ // push values only when we have key name
+ kp = New(key_pair(p, t));
+ values.append(kp);
+ }
+ p = q != NULL ? q : (char*)"";
+ }
- // if more values then one then it is a list
- if (values.size() > 1){
- DMSG0(ctx, D1, "METAPLUGIN::queryParameter: will render list\n")
- ow.start_list(qp->parameter);
- }
- // render all values
- foreach_alist(kp, &values){
- ow.get_output(OT_STRING, kp->key.c_str(), kp->value.c_str(), OT_END);
- delete kp;
- }
- if (values.size() > 1){
- ow.end_list();
+ // if more values then one then it is a list
+ if (values.size() > 1) {
+ DMSG0(ctx, D1, "METAPLUGIN::queryParameter: will render list\n")
+ ow.start_list(qp->parameter);
+ }
+ // render all values
+ foreach_alist(kp, &values) {
+ ow.get_output(OT_STRING, kp->key.c_str(), kp->value.c_str(), OT_END);
+ delete kp;
+ }
+ if (values.size() > 1) {
+ ow.end_list();
+ }
+ pm_strcpy(robjbuf, ow.get_output(OT_END));
+ qp->result = robjbuf.c_str();
+ }
+ break;
+ case 'D':
+ pm_memcpy(robjbuf, cmd.c_str(), pktlen);
+ qp->result = robjbuf.c_str();
+ break;
+ default:
+ DMSG(ctx, DERROR, "METAPLUGIN::queryParameter: got invalid packet: %c\n", pkt);
+ JMSG(ctx, M_ERROR, "METAPLUGIN::queryParameter: got invalid packet: %c\n", pkt);
+ backend.ctx->signal_term(ctx);
+ backend.ctx->terminate(ctx);
+ qp->result = NULL;
+ ret = bRC_Error;
+ break;
}
- pm_strcpy(robjbuf, ow.get_output(OT_END));
- qp->result = robjbuf.c_str();
}
return ret;
* @param cmd - an expected command to read: `C` or `D`
* @return int32_t - the size of the packet payload
*/
-int32_t PTCOMM::recvbackend_header(bpContext *ctx, char cmd)
+int32_t PTCOMM::recvbackend_header(bpContext *ctx, char *cmd, bool any)
{
- if (is_closed()){
+ if (is_closed()) {
DMSG0(ctx, DERROR, "BPIPE to backend is closed, cannot receive data.\n");
JMSG0(ctx, is_fatal() ? M_FATAL : M_ERROR, "BPIPE to backend is closed, cannot receive data.\n");
return -1;
}
+ if (cmd == NULL) {
+ DMSG0(ctx, DERROR, "Runtime error. cmd == NULL. Cannot read data.\n");
+ JMSG0(ctx, is_fatal() ? M_FATAL : M_ERROR, "Runtime error. cmd == NULL. Cannot read data.\n");
+ return -1;
+ }
+
PTHEADER header;
bool workdone = false;
// convert packet length from ASCII to binary
int32_t msglen = atoi(header.length);
- if (header.status == 'C' || header.status == 'D')
- {
- if (header.status != cmd)
- {
- DMSG2(ctx, DERROR, "Protocol error. Expected packet: %c got: %c\n", cmd, header.status);
- JMSG2(ctx, M_FATAL, "Protocol error. Expected packet: %c got: %c\n", cmd, header.status);
- return -1;
+ if (header.status == 'C' || header.status == 'D') {
+ if (!any) {
+ if (header.status != *cmd) {
+ DMSG2(ctx, DERROR, "Protocol error. Expected packet: %c got: %c\n", *cmd, header.status);
+ JMSG2(ctx, M_FATAL, "Protocol error. Expected packet: %c got: %c\n", *cmd, header.status);
+ return -1;
+ }
+ } else {
+ *cmd = header.status;
}
-
// this means no additional handling required
return msglen;
}
* @param cmd
* @return int32_t
*/
-int32_t PTCOMM::handle_read_header(bpContext *ctx, char cmd)
+int32_t PTCOMM::handle_read_header(bpContext *ctx, char *cmd, bool any)
{
// first read is the packet header where we will have info about data
// which is sent to us; the packet header is 8 chars/bytes length fixed
// nbytes shows how many bytes we expects to read
- int32_t length = recvbackend_header(ctx, cmd);
- if (length < 0)
- {
+ int32_t length = recvbackend_header(ctx, cmd, any);
+ if (length < 0) {
// error
DMSG0(ctx, DERROR, "PTCOMM cannot get packet header from backend.\n");
JMSG0(ctx, is_fatal() ? M_FATAL : M_ERROR, "PTCOMM cannot get packet header from backend.\n");
* ctx is not NULL
* <n>: the size of received message
*/
-int32_t PTCOMM::recvbackend(bpContext *ctx, char cmd, POOL_MEM &buf)
+int32_t PTCOMM::recvbackend(bpContext *ctx, char *cmd, POOL_MEM &buf, bool any)
{
// handle header
- int32_t length = handle_read_header(ctx, cmd);
- if (length < 0)
+ int32_t length = handle_read_header(ctx, cmd, any);
+ if (length < 0) {
return -1;
+ }
// handle data payload
- if (length > 0)
- {
+ if (length > 0) {
// check requested buffer size
buf.check_size(length + 1);
return handle_payload(ctx, buf.c_str(), length);
int32_t PTCOMM::recvbackend_fixed(bpContext *ctx, char cmd, char *buf, int32_t bufsize)
{
int32_t length = remaininglen;
+ char lcmd = cmd;
- if (!f_cont){
+ if (!f_cont) {
// handle header
- length = handle_read_header(ctx, cmd);
+ length = handle_read_header(ctx, &lcmd);
if (length < 0)
return -1;
}
// handle data payload
- if (length > 0){
+ if (length > 0) {
// we will need subsequent call to handle remaining data only when `buf` to short
f_cont = length > bufsize;
int32_t nbytes = f_cont * bufsize + (!f_cont) * length;
*/
int32_t PTCOMM::read_command(bpContext *ctx, POOL_MEM &buf)
{
- int32_t status = recvbackend(ctx, 'C', buf);
- if (status > 0)
- {
+ char cmd = 'C';
+ int32_t status = recvbackend(ctx, &cmd, buf, false);
+ if (status > 0) {
/* mark end of string because every command is a string */
+ buf.check_size(status + 1);
buf.c_str()[status] = '\0';
/* strip any junk in command like '\n' or trailing spaces */
strip_trailing_junk(buf.c_str());
return status;
}
+/**
+ * @brief Reads the next packet from the backend communication channel.
+ *
+ * It accepts any command or data packet. The next byte after
+ * the received data will be terminated with '\0' for easy string
+ * handling.
+ *
+ * @param ctx bpContext - for Bacula debug and jobinfo messages
+ * @param cmd a pointer to a `char` which show what kind of packet was received
+ * @param buf buffer allocated for command
+ * @return int32_t
+ * -1 - when encountered any error
+ * 0 - when backend sent signal, i.e. EOD or Term
+ * <n> - the number of bytes received, success
+ */
+int32_t PTCOMM::read_any(bpContext *ctx, char *cmd, POOL_MEM &buf)
+{
+ int32_t status = recvbackend(ctx, cmd, buf, true);
+ if (status > 0) {
+ /* mark end of string for easy usage */
+ buf.check_size(status + 1);
+ buf.c_str()[status] = '\0';
+ status++;
+ }
+
+ return status;
+}
+
/*
* Reads the next data message from the backend.
* The number of bytes received will not exceed the buffer length even when
int32_t PTCOMM::read_data(bpContext *ctx, POOL_MEM &buf)
{
int32_t status;
+ char cmd = 'D';
- if (extpipe > 0){
+ if (extpipe > 0) {
status = read(extpipe, buf.c_str(), buf.size());
} else {
- status = recvbackend(ctx, 'D', buf);
+ status = recvbackend(ctx, &cmd, buf, false);
}
return status;
bool PTCOMM::read_ack(bpContext *ctx)
{
POOL_MEM buf(PM_FNAME);
+ char cmd = 'F';
- if (recvbackend(ctx, 'F', buf) == 0 && f_eod)
- {
+ if (recvbackend(ctx, &cmd, buf, false) == 0 && f_eod) {
f_eod = false;
return true;
}
signal_eod();
}
+const unsigned char m_json[] = {
+ 0x7b, 0x22, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x22, 0x3a, 0x20, 0x7b,
+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x62, 0x75, 0x67, 0x22,
+ 0x3a, 0x20, 0x22, 0x6f, 0x6e, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20,
+ 0x22, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x22, 0x3a, 0x20, 0x7b, 0x0a,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x69, 0x74,
+ 0x6c, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65,
+ 0x20, 0x4b, 0x6f, 0x6e, 0x66, 0x61, 0x62, 0x75, 0x6c, 0x61, 0x74, 0x6f,
+ 0x72, 0x20, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x22, 0x2c, 0x0a, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6e, 0x61, 0x6d, 0x65,
+ 0x22, 0x3a, 0x20, 0x22, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x77, 0x69, 0x6e,
+ 0x64, 0x6f, 0x77, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x22, 0x77, 0x69, 0x64, 0x74, 0x68, 0x22, 0x3a, 0x20, 0x35,
+ 0x30, 0x30, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x22, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x22, 0x3a, 0x20, 0x35, 0x30,
+ 0x30, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0x0a, 0x20, 0x20, 0x20,
+ 0x20, 0x22, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x22, 0x3a, 0x20, 0x7b, 0x20,
+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x72,
+ 0x63, 0x22, 0x3a, 0x20, 0x22, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x2f,
+ 0x53, 0x75, 0x6e, 0x2e, 0x70, 0x6e, 0x67, 0x22, 0x2c, 0x0a, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22,
+ 0x3a, 0x20, 0x22, 0x73, 0x75, 0x6e, 0x31, 0x22, 0x2c, 0x0a, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x68, 0x4f, 0x66, 0x66, 0x73,
+ 0x65, 0x74, 0x22, 0x3a, 0x20, 0x32, 0x35, 0x30, 0x2c, 0x0a, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x4f, 0x66, 0x66, 0x73,
+ 0x65, 0x74, 0x22, 0x3a, 0x20, 0x32, 0x35, 0x30, 0x2c, 0x0a, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x6c, 0x69, 0x67, 0x6e,
+ 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x63, 0x65, 0x6e, 0x74,
+ 0x65, 0x72, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0x0a, 0x20,
+ 0x20, 0x20, 0x20, 0x22, 0x74, 0x65, 0x78, 0x74, 0x22, 0x3a, 0x20, 0x7b,
+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x61,
+ 0x74, 0x61, 0x22, 0x3a, 0x20, 0x22, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x20,
+ 0x48, 0x65, 0x72, 0x65, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x22, 0x73, 0x69, 0x7a, 0x65, 0x22, 0x3a, 0x20, 0x33,
+ 0x36, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+ 0x73, 0x74, 0x79, 0x6c, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x62, 0x6f, 0x6c,
+ 0x64, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x74, 0x65, 0x78,
+ 0x74, 0x31, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x22, 0x68, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x22, 0x3a, 0x20,
+ 0x32, 0x35, 0x30, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x22, 0x76, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x22, 0x3a, 0x20,
+ 0x31, 0x30, 0x30, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x22, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x22,
+ 0x3a, 0x20, 0x22, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x22, 0x2c, 0x0a,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6f, 0x6e, 0x4d,
+ 0x6f, 0x75, 0x73, 0x65, 0x55, 0x70, 0x22, 0x3a, 0x20, 0x22, 0x73, 0x75,
+ 0x6e, 0x31, 0x2e, 0x6f, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x20, 0x3d,
+ 0x20, 0x28, 0x73, 0x75, 0x6e, 0x31, 0x2e, 0x6f, 0x70, 0x61, 0x63, 0x69,
+ 0x74, 0x79, 0x20, 0x2f, 0x20, 0x31, 0x30, 0x30, 0x29, 0x20, 0x2a, 0x20,
+ 0x39, 0x30, 0x3b, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x7d,
+ 0x7d, 0x0a, 0x00
+};
+unsigned int m_json_len = 603;
+
/*
* The query param procedure
* return 3 simple parameters
*/
-void perform_queryparam(char *query)
+void perform_queryparam(const char *query)
{
/* Query Loop (5) */
- snprintf(buf, BIGBUFLEN, "%s=test1\n", query);
- write_plugin('C', buf);
- snprintf(buf, BIGBUFLEN, "%s=test2\n", query);
- write_plugin('C', buf);
- snprintf(buf, BIGBUFLEN, "%s=test3\n", query);
- write_plugin('C', buf);
+ if (strcmp(query, "m_id") == 0) {
+ snprintf(buf, BIGBUFLEN, "%s=test1\n", query);
+ write_plugin('C', buf);
+ snprintf(buf, BIGBUFLEN, "%s=test2\n", query);
+ write_plugin('C', buf);
+ snprintf(buf, BIGBUFLEN, "%s=test3\n", query);
+ write_plugin('C', buf);
+ } else
+ if (strcmp(query, "m_json") == 0) {
+ write_plugin_bin((const char*)m_json, m_json_len);
+ write_plugin('D', "UmFkb3PFgmF3IEtvcnplbmlld3NraQo=\n");
+ }
/* this is the end of all data */
signal_eod();