MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
mcstat.c
1 /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 #include "config.h"
3 
4 #include <memcached/protocol_binary.h>
5 
6 #include <getopt.h>
7 #include <errno.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <stdlib.h>
11 
18 static int connect_server(const char *hostname, const char *port)
19 {
20  struct addrinfo *ai = NULL;
21  struct addrinfo hints = { .ai_family = AF_UNSPEC,
22  .ai_protocol = IPPROTO_TCP,
23  .ai_socktype = SOCK_STREAM };
24 
25  if (getaddrinfo(hostname, port, &hints, &ai) != 0) {
26  return -1;
27  }
28  int sock = -1;
29  if ((sock = socket(ai->ai_family, ai->ai_socktype,
30  ai->ai_protocol)) != -1) {
31  if (connect(sock, ai->ai_addr, ai->ai_addrlen) == -1) {
32  close(sock);
33  sock = -1;
34  }
35  }
36 
37  freeaddrinfo(ai);
38  return sock;
39 }
40 
48 static void retry_send(int sock, const void* buf, size_t len)
49 {
50  off_t offset = 0;
51  const char* ptr = buf;
52 
53  do {
54  size_t num_bytes = len - offset;
55  ssize_t nw = send(sock, ptr + offset, num_bytes, 0);
56  if (nw == -1) {
57  if (errno != EINTR) {
58  fprintf(stderr, "Failed to write: %s\n", strerror(errno));
59  close(sock);
60  exit(1);
61  }
62  } else {
63  offset += nw;
64  }
65  } while (offset < len);
66 }
67 
75 static void retry_recv(int sock, void *buf, size_t len) {
76  if (len == 0) {
77  return;
78  }
79  off_t offset = 0;
80  do {
81  ssize_t nr = recv(sock, ((char*)buf) + offset, len - offset, 0);
82  if (nr == -1) {
83  if (errno != EINTR) {
84  fprintf(stderr, "Failed to read: %s\n", strerror(errno));
85  close(sock);
86  exit(1);
87  }
88  } else {
89  if (nr == 0) {
90  fprintf(stderr, "Connection closed\n");
91  close(sock);
92  exit(1);
93  }
94  offset += nr;
95  }
96  } while (offset < len);
97 }
98 
106 static void print(const char *key, int keylen, const char *val, int vallen) {
107  fputs("STAT ", stdout);
108  (void)fwrite(key, keylen, 1, stdout);
109  fputs(" ", stdout);
110  (void)fwrite(val, vallen, 1, stdout);
111  fputs("\n", stdout);
112  fflush(stdout);
113 }
114 
120 static void request_stat(int sock, const char *key)
121 {
122  uint32_t buffsize = 0;
123  char *buffer = NULL;
124  uint16_t keylen = 0;
125  if (key != NULL) {
126  keylen = (uint16_t)strlen(key);
127  }
128 
130  .message.header.request = {
131  .magic = PROTOCOL_BINARY_REQ,
132  .opcode = PROTOCOL_BINARY_CMD_STAT,
133  .keylen = htons(keylen),
134  .bodylen = htonl(keylen)
135  }
136  };
137 
138  retry_send(sock, &request, sizeof(request));
139  if (keylen > 0) {
140  retry_send(sock, key, keylen);
141  }
142 
144  do {
145  retry_recv(sock, &response, sizeof(response.bytes));
146  if (response.message.header.response.keylen != 0) {
147  uint16_t keylen = ntohs(response.message.header.response.keylen);
148  uint32_t vallen = ntohl(response.message.header.response.bodylen);
149  if (vallen > buffsize) {
150  if ((buffer = realloc(buffer, vallen)) == NULL) {
151  fprintf(stderr, "Failed to allocate memory\n");
152  exit(1);
153  }
154  buffsize = vallen;
155  }
156  retry_recv(sock, buffer, vallen);
157  print(buffer, keylen, buffer + keylen, vallen - keylen);
158  }
159  } while (response.message.header.response.keylen != 0);
160 }
161 
170 int main(int argc, char **argv)
171 {
172  int cmd;
173  const char * const default_ports[] = { "memcache", "11211", NULL };
174  const char *port = NULL;
175  const char *host = NULL;
176  char *ptr;
177 
178  /* Initialize the socket subsystem */
179  initialize_sockets();
180 
181  while ((cmd = getopt(argc, argv, "h:p:")) != EOF) {
182  switch (cmd) {
183  case 'h' :
184  host = optarg;
185  ptr = strchr(optarg, ':');
186  if (ptr != NULL) {
187  *ptr = '\0';
188  port = ptr + 1;
189  }
190  break;
191  case 'p':
192  port = optarg;
193  break;
194  default:
195  fprintf(stderr,
196  "Usage mcstat [-h host[:port]] [-p port] [statkey]*\n");
197  return 1;
198  }
199  }
200 
201  if (host == NULL) {
202  host = "localhost";
203  }
204 
205  int sock = -1;
206  if (port == NULL) {
207  int ii = 0;
208  do {
209  port = default_ports[ii++];
210  sock = connect_server(host, port);
211  } while (sock == -1 && default_ports[ii] != NULL);
212  } else {
213  sock = connect_server(host, port);
214  }
215 
216  if (sock == -1) {
217  fprintf(stderr, "Failed to connect to memcached server (%s:%s): %s\n",
218  host, port, strerror(errno));
219  return 1;
220  }
221 
222  if (optind == argc) {
223  request_stat(sock, NULL);
224  } else {
225  for (int ii = optind; ii < argc; ++ii) {
226  request_stat(sock, argv[ii]);
227  }
228  }
229 
230  close(sock);
231 
232  return 0;
233 }