1 /*
2  * nghttp2 - HTTP/2 C Library
3  *
4  * Copyright (c) 2015 Tatsuhiro Tsujikawa
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25 #ifndef SHRPX_MEMCACHED_CONNECTION_H
26 #define SHRPX_MEMCACHED_CONNECTION_H
27 
28 #include "shrpx.h"
29 
30 #include <memory>
31 #include <deque>
32 
33 #include <ev.h>
34 
35 #include "shrpx_connection.h"
36 #include "shrpx_tls.h"
37 #include "shrpx_connect_blocker.h"
38 #include "buffer.h"
39 #include "network.h"
40 
41 using namespace nghttp2;
42 
43 namespace shrpx {
44 
45 struct MemcachedRequest;
46 enum class MemcachedOp : uint8_t;
47 enum class MemcachedStatusCode : uint16_t;
48 
49 enum class MemcachedParseState {
50   HEADER24,
51   EXTRA,
52   VALUE,
53 };
54 
55 // Stores state when parsing response from memcached server
56 struct MemcachedParseContext {
57   // Buffer for value, dynamically allocated.
58   std::vector<uint8_t> value;
59   // cas in response
60   uint64_t cas;
61   // keylen in response
62   size_t keylen;
63   // extralen in response
64   size_t extralen;
65   // totalbody in response.  The length of value is totalbody -
66   // extralen - keylen.
67   size_t totalbody;
68   // Number of bytes left to read variable length field.
69   size_t read_left;
70   // Parser state; see enum above
71   MemcachedParseState state;
72   // status_code in response
73   MemcachedStatusCode status_code;
74   // op in response
75   MemcachedOp op;
76 };
77 
78 struct MemcachedSendbuf {
79   // Buffer for header + extra + key
80   Buffer<512> headbuf;
81   // MemcachedRequest associated to this object
82   MemcachedRequest *req;
83   // Number of bytes left when sending value
84   size_t send_value_left;
85   // Returns the number of bytes this object transmits.
leftMemcachedSendbuf86   size_t left() const { return headbuf.rleft() + send_value_left; }
87 };
88 
89 constexpr uint8_t MEMCACHED_REQ_MAGIC = 0x80;
90 constexpr uint8_t MEMCACHED_RES_MAGIC = 0x81;
91 
92 // MemcachedConnection implements part of memcached binary protocol.
93 // This is not full brown implementation.  Just the part we need is
94 // implemented.  We only use GET and ADD.
95 //
96 // https://github.com/memcached/memcached/blob/master/doc/protocol-binary.xml
97 // https://code.google.com/p/memcached/wiki/MemcacheBinaryProtocol
98 class MemcachedConnection {
99 public:
100   MemcachedConnection(const Address *addr, struct ev_loop *loop,
101                       SSL_CTX *ssl_ctx, const StringRef &sni_name,
102                       MemchunkPool *mcpool, std::mt19937 &gen);
103   ~MemcachedConnection();
104 
105   void disconnect();
106 
107   int add_request(std::unique_ptr<MemcachedRequest> req);
108   int initiate_connection();
109 
110   int connected();
111   int on_write();
112   int on_read();
113 
114   int write_clear();
115   int read_clear();
116 
117   int tls_handshake();
118   int write_tls();
119   int read_tls();
120 
121   size_t fill_request_buffer(struct iovec *iov, size_t iovlen);
122   void drain_send_queue(size_t nwrite);
123 
124   void make_request(MemcachedSendbuf *sendbuf, MemcachedRequest *req);
125   int parse_packet();
126   size_t serialized_size(MemcachedRequest *req);
127 
128   void signal_write();
129 
130   int noop();
131 
132   void reconnect_or_fail();
133 
134 private:
135   Connection conn_;
136   std::deque<std::unique_ptr<MemcachedRequest>> recvq_;
137   std::deque<std::unique_ptr<MemcachedRequest>> sendq_;
138   std::deque<MemcachedSendbuf> sendbufv_;
139   std::function<int(MemcachedConnection &)> do_read_, do_write_;
140   StringRef sni_name_;
141   tls::TLSSessionCache tls_session_cache_;
142   ConnectBlocker connect_blocker_;
143   MemcachedParseContext parse_state_;
144   const Address *addr_;
145   SSL_CTX *ssl_ctx_;
146   // Sum of the bytes to be transmitted in sendbufv_.
147   size_t sendsum_;
148   size_t try_count_;
149   bool connected_;
150   Buffer<8_k> recvbuf_;
151 };
152 
153 } // namespace shrpx
154 
155 #endif // SHRPX_MEMCACHED_CONNECTION_H
156