1 /*
2 * Copyright (C) Tildeslash Ltd. All rights reserved.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Affero General Public License version 3.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU Affero General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 *
15 * In addition, as a special exception, the copyright holders give
16 * permission to link the code of portions of this program with the
17 * OpenSSL library under certain conditions as described in each
18 * individual source file, and distribute linked combinations
19 * including the two.
20 *
21 * You must obey the GNU Affero General Public License in all respects
22 * for all of the code used other than OpenSSL.
23 */
24
25 #include "config.h"
26
27 #ifdef HAVE_STRING_H
28 #include <string.h>
29 #endif
30
31 #include "protocol.h"
32
33 // libmonit
34 #include "exceptions/IOException.h"
35 #include "exceptions/ProtocolException.h"
36
37 #define MEMCACHELEN 24
38
39 /* Magic Byte */
40 #define MAGIC_REQUEST 0x80
41 #define MAGIC_RESPONSE 0x81
42
43 /* Response Status */
44 #define NO_ERROR 0x0000
45 #define KEY_NOT_FOUND 0x0001
46 #define KEY_EXISTS 0x0002
47 #define VALUE_TOO_BIG 0x0003
48 #define INVALID_ARGUMENTS 0x0004
49 #define ITEM_NOT_STORED 0x0005
50 #define UNKNOWN_COMMAND 0x0081
51 #define OUT_OF_MEMORY 0x0082
52
53 /**
54 * Memcache binary protocol
55 *
56 * Send No-op request
57 *
58 * @file
59 */
check_memcache(Socket_T socket)60 void check_memcache(Socket_T socket) {
61 unsigned int length;
62 unsigned char response[MEMCACHELEN];
63 unsigned int status;
64
65 unsigned char request[MEMCACHELEN] = {
66 MAGIC_REQUEST, /** Magic */
67 0x0a, /** Opcode */
68 0x00, 0x00, /** Key length */
69 0x00, /** Extra length */
70 0x00, /** Data type */
71 0x00, 0x00, /** request Reserved / response Status */
72 0x00, 0x00, 0x00, 0x00, /** Total body */
73 0x00, 0x00, 0x00, 0x00, /** Opaque */
74 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /** CAS */
75 };
76
77 ASSERT(socket);
78
79 if (Socket_write(socket, (unsigned char *)request, sizeof(request)) <= 0)
80 THROW(IOException, "MEMCACHE: error sending data -- %s", STRERROR);
81
82 /* Response should have at least MEMCACHELEN bytes */
83 length = Socket_read(socket, (unsigned char *)response, sizeof(response));
84 if (length != MEMCACHELEN)
85 THROW(IOException, "MEMCACHE: Received %d bytes from server, expected %d bytes", length, MEMCACHELEN);
86
87 if (response[0] != MAGIC_RESPONSE)
88 THROW(ProtocolException, "MEMCACHELEN: Invalid response code -- error occurred");
89
90 status = (response[6] << 8) | response[7];
91 switch (status) {
92 case NO_ERROR:
93 break;
94 case OUT_OF_MEMORY:
95 THROW(ProtocolException, "MEMCACHELEN: Invalid response code -- Out of memory");
96 break;
97 case UNKNOWN_COMMAND:
98 THROW(ProtocolException, "MEMCACHELEN: Invalid response code -- Unknown command");
99 break;
100 case INVALID_ARGUMENTS:
101 THROW(ProtocolException, "MEMCACHELEN: Invalid response code -- Invalid arguments");
102 break;
103 case VALUE_TOO_BIG:
104 THROW(ProtocolException, "MEMCACHELEN: Invalid response code -- Value too big");
105 break;
106 case ITEM_NOT_STORED:
107 THROW(ProtocolException, "MEMCACHELEN: Invalid response code -- Item not stored");
108 break;
109 case KEY_NOT_FOUND:
110 THROW(ProtocolException, "MEMCACHELEN: Invalid response code -- Key not found");
111 break;
112 case KEY_EXISTS:
113 THROW(ProtocolException, "MEMCACHELEN: Invalid response code -- Key exists");
114 break;
115 default:
116 THROW(ProtocolException, "MEMCACHELEN: Unknown response code %u -- error occurred", status);
117 break;
118 }
119 }
120
121
122