1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 **/
19 
20 #include "common.h"
21 #include "comms.h"
22 #include "zbxjson.h"
23 #include "log.h"
24 
25 /******************************************************************************
26  *                                                                            *
27  * Function: zbx_send_response                                                *
28  *                                                                            *
29  * Purpose: send json SUCCEED or FAIL to socket along with an info message    *
30  *                                                                            *
31  * Parameters: sock     - [IN] socket descriptor                              *
32  *             result   - [IN] SUCCEED or FAIL                                *
33  *             info     - [IN] info message (optional)                        *
34  *             version  - [IN] the version data (optional)                    *
35  *             protocol - [IN] the transport protocol                         *
36  *             timeout - [IN] timeout for this operation                      *
37  *                                                                            *
38  * Return value: SUCCEED - data successfully transmitted                      *
39  *               NETWORK_ERROR - network related error occurred               *
40  *                                                                            *
41  * Author: Alexander Vladishev, Alexei Vladishev                              *
42  *                                                                            *
43  * Comments:                                                                  *
44  *                                                                            *
45  ******************************************************************************/
zbx_send_response_ext(zbx_socket_t * sock,int result,const char * info,const char * version,int protocol,int timeout)46 int	zbx_send_response_ext(zbx_socket_t *sock, int result, const char *info, const char *version, int protocol,
47 		int timeout)
48 {
49 	struct zbx_json	json;
50 	const char	*resp;
51 	int		ret = SUCCEED;
52 
53 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
54 
55 	zbx_json_init(&json, ZBX_JSON_STAT_BUF_LEN);
56 
57 	resp = SUCCEED == result ? ZBX_PROTO_VALUE_SUCCESS : ZBX_PROTO_VALUE_FAILED;
58 
59 	zbx_json_addstring(&json, ZBX_PROTO_TAG_RESPONSE, resp, ZBX_JSON_TYPE_STRING);
60 
61 	if (NULL != info && '\0' != *info)
62 		zbx_json_addstring(&json, ZBX_PROTO_TAG_INFO, info, ZBX_JSON_TYPE_STRING);
63 
64 	if (NULL != version)
65 		zbx_json_addstring(&json, ZBX_PROTO_TAG_VERSION, version, ZBX_JSON_TYPE_STRING);
66 
67 	zabbix_log(LOG_LEVEL_DEBUG, "%s() '%s'", __func__, json.buffer);
68 
69 	if (FAIL == (ret = zbx_tcp_send_ext(sock, json.buffer, strlen(json.buffer), 0, protocol, timeout)))
70 	{
71 		zabbix_log(LOG_LEVEL_DEBUG, "Error sending result back: %s", zbx_socket_strerror());
72 		ret = NETWORK_ERROR;
73 	}
74 
75 	zbx_json_free(&json);
76 
77 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
78 
79 	return ret;
80 }
81 
82 /******************************************************************************
83  *                                                                            *
84  * Function: zbx_recv_response                                                *
85  *                                                                            *
86  * Purpose: read a response message (in JSON format) from socket, optionally  *
87  *          extract "info" value.                                             *
88  *                                                                            *
89  * Parameters: sock    - [IN] socket descriptor                               *
90  *             timeout - [IN] timeout for this operation                      *
91  *             error   - [OUT] pointer to error message                       *
92  *                                                                            *
93  * Return value: SUCCEED - "response":"success" successfully retrieved        *
94  *               FAIL    - otherwise                                          *
95  * Comments:                                                                  *
96  *     Allocates memory.                                                      *
97  *                                                                            *
98  *     If an error occurs, the function allocates dynamic memory for an error *
99  *     message and writes its address into location pointed to by "error"     *
100  *     parameter.                                                             *
101  *                                                                            *
102  *     When the "info" value is present in the response message then function *
103  *     copies the "info" value into the "error" buffer as additional          *
104  *     information                                                            *
105  *                                                                            *
106  *     IMPORTANT: it is a responsibility of the caller to release the         *
107  *                "error" memory !                                            *
108  *                                                                            *
109  ******************************************************************************/
zbx_recv_response(zbx_socket_t * sock,int timeout,char ** error)110 int	zbx_recv_response(zbx_socket_t *sock, int timeout, char **error)
111 {
112 	struct zbx_json_parse	jp;
113 	char			value[16];
114 	int			ret = FAIL;
115 
116 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
117 
118 	if (SUCCEED != zbx_tcp_recv_to(sock, timeout))
119 	{
120 		/* since we have successfully sent data earlier, we assume the other */
121 		/* side is just too busy processing our data if there is no response */
122 		*error = zbx_strdup(*error, zbx_socket_strerror());
123 		goto out;
124 	}
125 
126 	zabbix_log(LOG_LEVEL_DEBUG, "%s() '%s'", __func__, sock->buffer);
127 
128 	/* deal with empty string here because zbx_json_open() does not produce an error message in this case */
129 	if ('\0' == *sock->buffer)
130 	{
131 		*error = zbx_strdup(*error, "empty string received");
132 		goto out;
133 	}
134 
135 	if (SUCCEED != zbx_json_open(sock->buffer, &jp))
136 	{
137 		*error = zbx_strdup(*error, zbx_json_strerror());
138 		goto out;
139 	}
140 
141 	if (SUCCEED != zbx_json_value_by_name(&jp, ZBX_PROTO_TAG_RESPONSE, value, sizeof(value), NULL))
142 	{
143 		*error = zbx_strdup(*error, "no \"" ZBX_PROTO_TAG_RESPONSE "\" tag");
144 		goto out;
145 	}
146 
147 	if (0 != strcmp(value, ZBX_PROTO_VALUE_SUCCESS))
148 	{
149 		char	*info = NULL;
150 		size_t	info_alloc = 0;
151 
152 		if (SUCCEED == zbx_json_value_by_name_dyn(&jp, ZBX_PROTO_TAG_INFO, &info, &info_alloc, NULL))
153 			*error = zbx_strdup(*error, info);
154 		else
155 			*error = zbx_dsprintf(*error, "negative response \"%s\"", value);
156 		zbx_free(info);
157 		goto out;
158 	}
159 
160 	ret = SUCCEED;
161 out:
162 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
163 
164 	return ret;
165 }
166