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