1 /*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
2  *
3  *  Libmemcached library
4  *
5  *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
6  *  Copyright (C) 2006-2009 Brian Aker All rights reserved.
7  *
8  *  Redistribution and use in source and binary forms, with or without
9  *  modification, are permitted provided that the following conditions are
10  *  met:
11  *
12  *      * Redistributions of source code must retain the above copyright
13  *  notice, this list of conditions and the following disclaimer.
14  *
15  *      * Redistributions in binary form must reproduce the above
16  *  copyright notice, this list of conditions and the following disclaimer
17  *  in the documentation and/or other materials provided with the
18  *  distribution.
19  *
20  *      * The names of its contributors may not be used to endorse or
21  *  promote products derived from this software without specific prior
22  *  written permission.
23  *
24  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27  *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28  *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29  *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34  *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35  *
36  */
37 
38 /*
39   This is a partial implementation for fetching/creating memcached_server_st objects.
40 */
41 #include <libmemcached/common.h>
42 
_server_init(memcached_server_st * self,Memcached * root,const memcached_string_t & hostname,in_port_t port,uint32_t weight,memcached_connection_t type)43 static inline void _server_init(memcached_server_st *self, Memcached *root,
44                                 const memcached_string_t& hostname,
45                                 in_port_t port,
46                                 uint32_t weight, memcached_connection_t type)
47 {
48   self->options.is_shutting_down= false;
49   self->options.is_dead= false;
50   self->number_of_hosts= 0;
51   self->cursor_active= 0;
52   self->port= port;
53   self->io_bytes_sent= 0;
54   self->request_id= 0;
55   self->server_failure_counter= 0;
56   self->server_failure_counter_query_id= 0;
57   self->server_timeout_counter= 0;
58   self->server_timeout_counter_query_id= 0;
59   self->weight= weight ? weight : 1; // 1 is the default weight value
60   self->io_wait_count.read= 0;
61   self->io_wait_count.write= 0;
62   self->io_wait_count.timeouts= 0;
63   self->io_wait_count._bytes_read= 0;
64   self->major_version= UINT8_MAX;
65   self->micro_version= UINT8_MAX;
66   self->minor_version= UINT8_MAX;
67   self->type= type;
68   self->error_messages= NULL;
69 
70   self->state= MEMCACHED_SERVER_STATE_NEW;
71   self->next_retry= 0;
72 
73   self->root= root;
74   if (root)
75   {
76     self->version= ++root->server_info.version;
77   }
78   else
79   {
80     self->version= UINT_MAX;
81   }
82   self->limit_maxbytes= 0;
83   memcpy(self->hostname, hostname.c_str, hostname.size);
84   self->hostname[hostname.size]= 0;
85 }
86 
_server_create(memcached_server_st * self,const Memcached * memc)87 static memcached_server_st *_server_create(memcached_server_st *self, const Memcached *memc)
88 {
89   if (self == NULL)
90   {
91    self= libmemcached_xmalloc(memc, struct memcached_server_st);
92 
93     if (self == NULL)
94     {
95       return NULL; /*  MEMCACHED_MEMORY_ALLOCATION_FAILURE */
96     }
97 
98     self->options.is_allocated= true;
99   }
100   else
101   {
102     self->options.is_allocated= false;
103   }
104 
105   self->options.is_initialized= true;
106 
107   return self;
108 }
109 
__server_create_with(Memcached * memc,memcached_server_st * allocated_instance,const memcached_string_t & hostname,const in_port_t port,uint32_t weight,const memcached_connection_t type)110 memcached_server_st *__server_create_with(Memcached *memc,
111                                           memcached_server_st* allocated_instance,
112                                           const memcached_string_t& hostname,
113                                           const in_port_t port,
114                                           uint32_t weight,
115                                           const memcached_connection_t type)
116 {
117   if (memcached_is_valid_servername(hostname) == false)
118   {
119     memcached_set_error(*memc, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("Invalid hostname provided"));
120     return NULL;
121   }
122 
123   allocated_instance= _server_create(allocated_instance, memc);
124 
125   if (allocated_instance == NULL)
126   {
127     return NULL;
128   }
129 
130   _server_init(allocated_instance, const_cast<Memcached *>(memc), hostname, port, weight, type);
131 
132   return allocated_instance;
133 }
134 
__server_free(memcached_server_st * self)135 void __server_free(memcached_server_st *self)
136 {
137   memcached_error_free(*self);
138 
139   if (memcached_is_allocated(self))
140   {
141     libmemcached_free(self->root, self);
142   }
143   else
144   {
145     self->options.is_initialized= false;
146   }
147 }
148 
memcached_server_free(memcached_server_st * self)149 void memcached_server_free(memcached_server_st *self)
150 {
151   if (self == NULL)
152   {
153     return;
154   }
155 
156   if (memcached_server_list_count(self))
157   {
158     memcached_server_list_free(self);
159     return;
160   }
161 
162   __server_free(self);
163 }
164 
memcached_server_error_reset(memcached_server_st * self)165 void memcached_server_error_reset(memcached_server_st *self)
166 {
167   WATCHPOINT_ASSERT(self);
168   if (self == NULL)
169   {
170     return;
171   }
172 
173   memcached_error_free(*self);
174 }
175 
memcached_servers_set_count(memcached_server_st * servers,uint32_t count)176 uint32_t memcached_servers_set_count(memcached_server_st *servers, uint32_t count)
177 {
178   WATCHPOINT_ASSERT(servers);
179   if (servers == NULL)
180   {
181     return 0;
182   }
183 
184   return servers->number_of_hosts= count;
185 }
186 
memcached_server_count(const memcached_st * self)187 uint32_t memcached_server_count(const memcached_st *self)
188 {
189   WATCHPOINT_ASSERT(self);
190   if (self == NULL)
191     return 0;
192 
193   return self->number_of_hosts;
194 }
195 
memcached_server_name(const memcached_instance_st * self)196 const char *memcached_server_name(const memcached_instance_st * self)
197 {
198   WATCHPOINT_ASSERT(self);
199   if (self)
200   {
201     return self->_hostname;
202   }
203 
204   return NULL;
205 }
206 
memcached_server_port(const memcached_instance_st * self)207 in_port_t memcached_server_port(const memcached_instance_st * self)
208 {
209   WATCHPOINT_ASSERT(self);
210   if (self == NULL)
211   {
212     return 0;
213   }
214 
215   return self->port();
216 }
217 
memcached_server_srcport(const memcached_instance_st * self)218 in_port_t memcached_server_srcport(const memcached_instance_st * self)
219 {
220   WATCHPOINT_ASSERT(self);
221   if (self == NULL || self->fd == INVALID_SOCKET || (self->type != MEMCACHED_CONNECTION_TCP && self->type != MEMCACHED_CONNECTION_UDP))
222   {
223     return 0;
224   }
225 
226   struct sockaddr_in sin;
227   socklen_t addrlen= sizeof(sin);
228   if (getsockname(self->fd, (struct sockaddr*)&sin, &addrlen) != -1)
229   {
230     return ntohs(sin.sin_port);
231   }
232 
233   return -1;
234 }
235 
memcached_server_response_count(const memcached_instance_st * self)236 uint32_t memcached_server_response_count(const memcached_instance_st * self)
237 {
238   WATCHPOINT_ASSERT(self);
239   if (self == NULL)
240   {
241     return 0;
242   }
243 
244   return self->cursor_active_;
245 }
246 
memcached_server_type(const memcached_instance_st * ptr)247 const char *memcached_server_type(const memcached_instance_st * ptr)
248 {
249   if (ptr)
250   {
251     switch (ptr->type)
252     {
253     case MEMCACHED_CONNECTION_TCP:
254       return "TCP";
255 
256     case MEMCACHED_CONNECTION_UDP:
257       return "UDP";
258 
259     case MEMCACHED_CONNECTION_UNIX_SOCKET:
260       return "SOCKET";
261     }
262   }
263 
264   return "UNKNOWN";
265 }
266 
memcached_server_major_version(const memcached_instance_st * instance)267 uint8_t memcached_server_major_version(const memcached_instance_st * instance)
268 {
269   if (instance)
270   {
271     return instance->major_version;
272   }
273 
274   return UINT8_MAX;
275 }
276 
memcached_server_minor_version(const memcached_instance_st * instance)277 uint8_t memcached_server_minor_version(const memcached_instance_st * instance)
278 {
279   if (instance)
280   {
281     return instance->minor_version;
282   }
283 
284   return UINT8_MAX;
285 }
286 
memcached_server_micro_version(const memcached_instance_st * instance)287 uint8_t memcached_server_micro_version(const memcached_instance_st * instance)
288 {
289   if (instance)
290   {
291     return instance->micro_version;
292   }
293 
294   return UINT8_MAX;
295 }
296