squidclient.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 #include "squid.h"
10 #include "base64.h"
11 #include "ip/Address.h"
12 #include "ip/tools.h"
13 #include "rfc1123.h"
16 #include "tools/squidclient/Ping.h"
18 
19 #if _SQUID_WINDOWS_
20 
21 using namespace Squid;
23 #endif
24 
25 #include <cerrno>
26 #include <csignal>
27 #include <cstring>
28 #include <iostream>
29 #if _SQUID_WINDOWS_
30 #include <io.h>
31 #endif
32 #if HAVE_SYS_SOCKET_H
33 #include <sys/socket.h>
34 #endif
35 #if HAVE_UNISTD_H
36 #include <unistd.h>
37 #endif
38 #if HAVE_NETDB_H
39 #include <netdb.h>
40 #endif
41 #if HAVE_SYS_STAT_H
42 #include <sys/stat.h>
43 #endif
44 #if HAVE_FCNTL_H
45 #include <fcntl.h>
46 #endif
47 #if HAVE_NETINET_IN_H
48 #include <netinet/in.h>
49 #endif
50 #if HAVE_GETOPT_H
51 #include <getopt.h>
52 #endif
53 
54 #ifndef BUFSIZ
55 #define BUFSIZ 8192
56 #endif
57 #ifndef MESSAGELEN
58 #define MESSAGELEN 65536
59 #endif
60 #ifndef HEADERLEN
61 #define HEADERLEN 65536
62 #endif
63 
64 /* Local functions */
65 static void usage(const char *progname);
66 
67 void pipe_handler(int sig);
68 static void set_our_signal(void);
69 
71 
72 static int put_fd;
73 static char *put_file = NULL;
74 
75 static struct stat sb;
76 int total_bytes = 0;
77 
78 #if _SQUID_AIX_
79 /* Bug 3854: AIX 6.1 tries to link in this fde.h global symbol
80  * despite squidclient not using any of the fd_* code.
81  */
83 #endif
84 
85 #if _SQUID_WINDOWS_
86 void
87 Win32SockCleanup(void)
88 {
89  WSACleanup();
90  return;
91 }
92 #endif
93 
94 static void
95 usage(const char *progname)
96 {
97  std::cerr << "Version: " << VERSION << std::endl
98  << "Usage: " << progname << " [Basic Options] [HTTP Options]" << std::endl
99  << std::endl;
100  std::cerr
101  << " -s | --quiet Silent. Do not print response message to stdout." << std::endl
102  << " -v | --verbose Verbose debugging. Repeat (-vv) to increase output level." << std::endl
103  << " Levels:" << std::endl
104  << " 1 - Print outgoing request message to stderr." << std::endl
105  << " 2 - Print action trace to stderr." << std::endl
106  << " --help Display this help text." << std::endl
107  << std::endl;
110  std::cerr
111  << "HTTP Options:" << std::endl
112  << " -a Do NOT include Accept: header." << std::endl
113  << " -A User-Agent: header. Use \"\" to omit." << std::endl
114  << " -H 'string' Extra headers to send. Supports '\\\\', '\\n', '\\r' and '\\t'." << std::endl
115  << " -i IMS If-Modified-Since time (in Epoch seconds)." << std::endl
116  << " -j hosthdr Host header content" << std::endl
117  << " -k Keep the connection active. Default is to do only one request then close." << std::endl
118  << " -m method Request method, default is GET." << std::endl
119 #if HAVE_GSSAPI
120  << " -n Proxy Negotiate(Kerberos) authentication" << std::endl
121  << " -N WWW Negotiate(Kerberos) authentication" << std::endl
122 #endif
123  << " -P file Send content from the named file as request payload" << std::endl
124  << " -r Force cache to reload URL" << std::endl
125  << " -t count Trace count cache-hops" << std::endl
126  << " -u user Proxy authentication username" << std::endl
127  << " -U user WWW authentication username" << std::endl
128  << " -V version HTTP Version. Use '-' for HTTP/0.9 omitted case" << std::endl
129  << " -w password Proxy authentication password" << std::endl
130  << " -W password WWW authentication password" << std::endl
131  ;
132  exit(EXIT_FAILURE);
133 }
134 
135 static void
137 {
138  if (!buf)
139  return;
140 
141  unsigned char *p, *d;
142 
143  d = p = reinterpret_cast<unsigned char *>(buf);
144 
145  while (auto ch = *p) {
146 
147  if (ch == '\\') {
148  ++p;
149 
150  switch (*p) {
151  case 'n':
152  ch = '\n';
153  break;
154  case 'r':
155  ch = '\r';
156  break;
157  case 't':
158  ch = '\t';
159  break;
160  case '\\':
161  ch = '\\';
162  break;
163  default:
164  ch = *p;
165  debugVerbose(1, "Warning: unsupported shell code '\\" << ch << "'");
166  break;
167  }
168 
169  *d = ch;
170 
171  if (!ch)
172  continue;
173 
174  } else {
175  *d = *p;
176  }
177 
178  ++p;
179  ++d;
180  }
181 
182  *d = '\0';
183 }
184 
185 int
186 main(int argc, char *argv[])
187 {
188  int len, bytesWritten;
189  bool to_stdout, reload;
190  int keep_alive = 0;
191  int opt_noaccept = 0;
192 #if HAVE_GSSAPI
193  int www_neg = 0, proxy_neg = 0;
194 #endif
195  char url[BUFSIZ], msg[MESSAGELEN], buf[BUFSIZ];
196  char extra_hdrs[HEADERLEN];
197  const char *method = "GET";
198  extern char *optarg;
199  time_t ims = 0;
200  int max_forwards = -1;
201 
202  const char *proxy_user = NULL;
203  const char *proxy_password = NULL;
204  const char *www_user = NULL;
205  const char *www_password = NULL;
206  const char *host = NULL;
207  const char *version = "1.0";
208  const char *useragent = NULL;
209 
210  /* set the defaults */
211  extra_hdrs[0] = '\0';
212  to_stdout = true;
213  reload = false;
214 
215  Ip::ProbeTransport(); // determine IPv4 or IPv6 capabilities before parsing.
216  if (argc < 2 || argv[argc-1][0] == '-') {
217  usage(argv[0]); /* need URL */
218  } else if (argc >= 2) {
219  strncpy(url, argv[argc - 1], BUFSIZ);
220  url[BUFSIZ - 1] = '\0';
221 
222  int optIndex = 0;
223  const char *shortOpStr = "aA:h:j:V:l:P:i:km:nNp:rsvt:H:T:u:U:w:W:?";
224 
225  // options for controlling squidclient
226  static struct option basicOptions[] = {
227  /* These are the generic options for squidclient itself */
228  {"help", no_argument, 0, '?'},
229  {"verbose", no_argument, 0, 'v'},
230  {"quiet", no_argument, 0, 's'},
231  {"host", required_argument, 0, 'h'},
232  {"local", required_argument, 0, 'l'},
233  {"port", required_argument, 0, 'p'},
234  {"ping", no_argument, 0, '\1'},
235  {"https", no_argument, 0, '\3'},
236  {0, 0, 0, 0}
237  };
238 
239  int c;
240  while ((c = getopt_long(argc, argv, shortOpStr, basicOptions, &optIndex)) != -1) {
241 
242  // modules parse their own specific options
243  switch (c) {
244  case '\1':
245  to_stdout = 0;
246  Ping::Config.parseCommandOpts(argc, argv, c, optIndex);
247  continue;
248 
249  case 'h': /* remote host */
250  case 'l': /* local host */
251  case 'p': /* port number */
252  // rewind and let the Transport::Config parser handle
253  optind -= 2;
254 
255  case '\3': // request over a TLS connection
256  Transport::Config.parseCommandOpts(argc, argv, c, optIndex);
257  continue;
258 
259  default: // fall through to next switch
260  break;
261  }
262 
263  switch (c) {
264 
265  case '\0': // dummy value for end-of-options
266  break;
267 
268  case 'a':
269  opt_noaccept = 1;
270  break;
271 
272  case 'A':
273  useragent = optarg;
274  break;
275 
276  case 'j':
277  host = optarg;
278  break;
279 
280  case 'V':
281  version = optarg;
282  break;
283 
284  case 's': /* silent */
285  to_stdout = false;
286  break;
287 
288  case 'k': /* backward compat */
289  keep_alive = 1;
290  break;
291 
292  case 'r': /* reload */
293  reload = true;
294  break;
295 
296  case 'P':
297  put_file = xstrdup(optarg);
298  break;
299 
300  case 'i': /* IMS */
301  ims = (time_t) atoi(optarg);
302  break;
303 
304  case 'm':
305  method = xstrdup(optarg);
306  break;
307 
308  case 't':
309  method = xstrdup("TRACE");
310  max_forwards = atoi(optarg);
311  break;
312 
313  case 'H':
314  if (strlen(optarg)) {
315  strncpy(extra_hdrs, optarg, sizeof(extra_hdrs));
316  shellUnescape(extra_hdrs);
317  }
318  break;
319 
320  case 'T':
321  Transport::Config.ioTimeout = atoi(optarg);
322  break;
323 
324  case 'u':
325  proxy_user = optarg;
326  break;
327 
328  case 'w':
329  proxy_password = optarg;
330  break;
331 
332  case 'U':
333  www_user = optarg;
334  break;
335 
336  case 'W':
337  www_password = optarg;
338  break;
339 
340  case 'n':
341 #if HAVE_GSSAPI
342  proxy_neg = 1;
343 #else
344  std::cerr << "ERROR: Negotiate authentication not supported." << std::endl;
345  usage(argv[0]);
346 #endif
347  break;
348 
349  case 'N':
350 #if HAVE_GSSAPI
351  www_neg = 1;
352 #else
353  std::cerr << "ERROR: Negotiate authentication not supported." << std::endl;
354  usage(argv[0]);
355 #endif
356  break;
357 
358  case 'v':
359  /* undocumented: may increase verb-level by giving more -v's */
361  debugVerbose(2, "verbosity level set to " << scParams.verbosityLevel);
362  break;
363 
364  case '?': /* usage */
365 
366  default:
367  usage(argv[0]);
368  break;
369  }
370  }
371  }
372 #if _SQUID_WINDOWS_
373  {
374  WSADATA wsaData;
375  WSAStartup(2, &wsaData);
376  atexit(Win32SockCleanup);
377  }
378 #endif
379  /* Build the HTTP request */
380  if (strncmp(url, "mgr:", 4) == 0) {
381  char *t = xstrdup(url + 4);
382  const char *at = NULL;
383  if (!strrchr(t, '@')) { // ignore any -w password if @ is explicit already.
384  at = proxy_password;
385  }
386  // embed the -w proxy password into old-style cachemgr URLs
387  if (at)
388  snprintf(url, BUFSIZ, "cache_object://%s/%s@%s", Transport::Config.hostname, t, at);
389  else
390  snprintf(url, BUFSIZ, "cache_object://%s/%s", Transport::Config.hostname, t);
391  xfree(t);
392  }
393  if (put_file) {
394  put_fd = open(put_file, O_RDONLY);
395  set_our_signal();
396 
397  if (put_fd < 0) {
398  int xerrno = errno;
399  std::cerr << "ERROR: can't open file (" << xstrerr(xerrno) << ")" << std::endl;
400  exit(EXIT_FAILURE);
401  }
402 #if _SQUID_WINDOWS_
403  setmode(put_fd, O_BINARY);
404 #endif
405 
406  if (fstat(put_fd, &sb) < 0) {
407  int xerrno = errno;
408  std::cerr << "ERROR: can't identify length of file (" << xstrerr(xerrno) << ")" << std::endl;
409  }
410  }
411 
412  if (!host) {
413  char *newhost = strstr(url, "://");
414  if (newhost) {
415  char *t;
416  newhost += 3;
417  newhost = xstrdup(newhost);
418  t = newhost + strcspn(newhost, "@/?");
419  if (*t == '@') {
420  newhost = t + 1;
421  t = newhost + strcspn(newhost, "@/?");
422  }
423  *t = '\0';
424  host = newhost;
425  }
426  }
427 
428  if (version[0] == '-' || !version[0]) {
429  /* HTTP/0.9, no headers, no version */
430  snprintf(msg, BUFSIZ, "%s %s\r\n", method, url);
431  } else {
432  if (!xisdigit(version[0])) // not HTTP/n.n
433  snprintf(msg, BUFSIZ, "%s %s %s\r\n", method, url, version);
434  else
435  snprintf(msg, BUFSIZ, "%s %s HTTP/%s\r\n", method, url, version);
436 
437  if (host) {
438  snprintf(buf, BUFSIZ, "Host: %s\r\n", host);
439  strcat(msg,buf);
440  }
441 
442  if (useragent == NULL) {
443  snprintf(buf, BUFSIZ, "User-Agent: squidclient/%s\r\n", VERSION);
444  strcat(msg,buf);
445  } else if (useragent[0] != '\0') {
446  snprintf(buf, BUFSIZ, "User-Agent: %s\r\n", useragent);
447  strcat(msg,buf);
448  }
449 
450  if (reload) {
451  snprintf(buf, BUFSIZ, "Cache-Control: no-cache\r\n");
452  strcat(msg, buf);
453  }
454  if (put_fd > 0) {
455  snprintf(buf, BUFSIZ, "Content-length: %" PRId64 "\r\n", (int64_t) sb.st_size);
456  strcat(msg, buf);
457  }
458  if (opt_noaccept == 0) {
459  snprintf(buf, BUFSIZ, "Accept: */*\r\n");
460  strcat(msg, buf);
461  }
462  if (ims) {
463  snprintf(buf, BUFSIZ, "If-Modified-Since: %s\r\n", mkrfc1123(ims));
464  strcat(msg, buf);
465  }
466  if (max_forwards > -1) {
467  snprintf(buf, BUFSIZ, "Max-Forwards: %d\r\n", max_forwards);
468  strcat(msg, buf);
469  }
470  struct base64_encode_ctx ctx;
471  base64_encode_init(&ctx);
472  size_t blen;
473  if (proxy_user) {
474  const char *user = proxy_user;
475  const char *password = proxy_password;
476 #if HAVE_GETPASS
477  if (!password)
478  password = getpass("Proxy password: ");
479 #endif
480  if (!password) {
481  std::cerr << "ERROR: Proxy password missing" << std::endl;
482  exit(EXIT_FAILURE);
483  }
484  uint8_t *pwdBuf = new uint8_t[base64_encode_len(strlen(user)+1+strlen(password))];
485  blen = base64_encode_update(&ctx, pwdBuf, strlen(user), reinterpret_cast<const uint8_t*>(user));
486  blen += base64_encode_update(&ctx, pwdBuf+blen, 1, reinterpret_cast<const uint8_t*>(":"));
487  blen += base64_encode_update(&ctx, pwdBuf+blen, strlen(password), reinterpret_cast<const uint8_t*>(password));
488  blen += base64_encode_final(&ctx, pwdBuf+blen);
489  snprintf(buf, BUFSIZ, "Proxy-Authorization: Basic %.*s\r\n", (int)blen, reinterpret_cast<char*>(pwdBuf));
490  strcat(msg, buf);
491  delete[] pwdBuf;
492  }
493  if (www_user) {
494  const char *user = www_user;
495  const char *password = www_password;
496 #if HAVE_GETPASS
497  if (!password)
498  password = getpass("WWW password: ");
499 #endif
500  if (!password) {
501  std::cerr << "ERROR: WWW password missing" << std::endl;
502  exit(EXIT_FAILURE);
503  }
504  uint8_t *pwdBuf = new uint8_t[base64_encode_len(strlen(user)+1+strlen(password))];
505  blen = base64_encode_update(&ctx, pwdBuf, strlen(user), reinterpret_cast<const uint8_t*>(user));
506  blen += base64_encode_update(&ctx, pwdBuf+blen, 1, reinterpret_cast<const uint8_t*>(":"));
507  blen += base64_encode_update(&ctx, pwdBuf+blen, strlen(password), reinterpret_cast<const uint8_t*>(password));
508  blen += base64_encode_final(&ctx, pwdBuf+blen);
509  snprintf(buf, BUFSIZ, "Authorization: Basic %.*s\r\n", (int)blen, reinterpret_cast<char*>(pwdBuf));
510  strcat(msg, buf);
511  delete[] pwdBuf;
512  }
513 #if HAVE_GSSAPI
514  if (www_neg) {
515  if (host) {
516  const char *token = GSSAPI_token(host);
517  snprintf(buf, BUFSIZ, "Authorization: Negotiate %s\r\n", token);
518  strcat(msg, buf);
519  delete[] token;
520  } else
521  std::cerr << "ERROR: server host missing" << std::endl;
522  }
523  if (proxy_neg) {
524  if (Transport::Config.hostname) {
525  const char *token = GSSAPI_token(Transport::Config.hostname);
526  snprintf(buf, BUFSIZ, "Proxy-Authorization: Negotiate %s\r\n", token);
527  strcat(msg, buf);
528  delete[] token;
529  } else
530  std::cerr << "ERROR: proxy server host missing" << std::endl;
531  }
532 #endif
533 
534  /* HTTP/1.0 may need keep-alive explicitly */
535  if (strcmp(version, "1.0") == 0 && keep_alive)
536  strcat(msg, "Connection: keep-alive\r\n");
537 
538  /* HTTP/1.1 may need close explicitly */
539  if (!keep_alive)
540  strcat(msg, "Connection: close\r\n");
541 
542  strcat(msg, extra_hdrs);
543  strcat(msg, "\r\n");
544  }
545 
546  debugVerbose(1, "Request:" << std::endl << msg << std::endl << ".");
547 
548  uint32_t loops = Ping::Init();
549 
550  for (uint32_t i = 0; loops == 0 || i < loops; ++i) {
551  size_t fsize = 0;
552 
553  if (!Transport::Connect())
554  continue;
555 
556  /* Send the HTTP request */
557  debugVerbose(2, "Sending HTTP request ... ");
558  bytesWritten = Transport::Write(msg, strlen(msg));
559 
560  if (bytesWritten < 0) {
561  std::cerr << "ERROR: write" << std::endl;
562  exit(EXIT_FAILURE);
563  } else if ((unsigned) bytesWritten != strlen(msg)) {
564  std::cerr << "ERROR: Cannot send request?: " << std::endl << msg << std::endl;
565  exit(EXIT_FAILURE);
566  }
567  debugVerbose(2, "done.");
568 
569  if (put_file) {
570  debugVerbose(1, "Sending HTTP request payload ...");
571  int x;
572  if ((x = lseek(put_fd, 0, SEEK_SET)) < 0) {
573  int xerrno = errno;
574  std::cerr << "ERROR: lseek: " << xstrerr(xerrno) << std::endl;
575 
576  } else while ((x = read(put_fd, buf, sizeof(buf))) > 0) {
577 
578  x = Transport::Write(buf, x);
579 
580  total_bytes += x;
581 
582  if (x <= 0)
583  break;
584  }
585 
586  if (x != 0)
587  std::cerr << "ERROR: Cannot send file." << std::endl;
588  else
589  debugVerbose(1, "done.");
590  }
591  /* Read the data */
592 
593 #if _SQUID_WINDOWS_
594  setmode(1, O_BINARY);
595 #endif
596 
597  while ((len = Transport::Read(buf, sizeof(buf))) > 0) {
598  fsize += len;
599 
600  if (to_stdout && fwrite(buf, len, 1, stdout) != 1) {
601  int xerrno = errno;
602  std::cerr << "ERROR: writing to stdout: " << xstrerr(xerrno) << std::endl;
603  }
604  }
605 
606 #if USE_GNUTLS
607  if (Transport::Config.tlsEnabled) {
608  if (len == 0) {
609  std::cerr << "- Peer has closed the TLS connection" << std::endl;
610  } else if (!gnutls_error_is_fatal(len)) {
611  std::cerr << "WARNING: " << gnutls_strerror(len) << std::endl;
612  } else {
613  std::cerr << "ERROR: " << gnutls_strerror(len) << std::endl;
614  }
615  }
616 #endif
617 
618 #if _SQUID_WINDOWS_
619  setmode(1, O_TEXT);
620 #endif
621 
623 
624  if (Ping::LoopDone(i))
625  break;
626 
627  Ping::TimerStop(fsize);
628  }
629 
632  return EXIT_SUCCESS;
633 }
634 
635 void
637 {
638  std::cerr << "SIGPIPE received." << std::endl;
639 }
640 
641 static void
643 {
644 #if HAVE_SIGACTION
645  struct sigaction sa;
646  sa.sa_handler = pipe_handler;
647  sa.sa_flags = SA_RESTART;
648  sigemptyset(&sa.sa_mask);
649 
650  if (sigaction(SIGPIPE, &sa, NULL) < 0) {
651  std::cerr << "ERROR: Cannot set PIPE signal." << std::endl;
652  exit(EXIT_FAILURE);
653  }
654 #else
655  signal(SIGPIPE, pipe_handler);
656 #endif
657 }
658 
int ioTimeout
I/O operation timeout.
Definition: Transport.h:50
Ping::TheConfig Config
Definition: Ping.cc:24
bool parseCommandOpts(int argc, char *argv[], int c, int &optIndex)
Definition: Transport.cc:53
static char * put_file
Definition: squidclient.cc:73
const char * mkrfc1123(time_t)
Definition: rfc1123.c:202
int main(int argc, char *argv[])
Definition: squidclient.cc:186
static fde * Table
global table of FD and their state.
Definition: fde.h:81
void CloseConnection()
close the current connection
Definition: Transport.cc:285
int i
Definition: membanger.c:49
#define xstrdup
#define PRId64
Definition: types.h:110
static int version
TheConfig Config
Definition: Transport.cc:23
static struct stat sb
Definition: squidclient.cc:75
char * p
Definition: membanger.c:43
void usage()
display Ping Options command line help to stderr
Definition: Ping.cc:155
void usage()
display Transport Options command line help to stderr
Definition: Transport.cc:29
#define HEADERLEN
Definition: squidclient.cc:61
#define BUFSIZ
Definition: squidclient.cc:55
int verbosityLevel
Definition: Parameters.h:27
static void shellUnescape(char *buf)
Definition: squidclient.cc:136
const char * xstrerr(int error)
Definition: xstrerror.cc:83
void pipe_handler(int sig)
Definition: squidclient.cc:636
size_t base64_encode_final(struct base64_encode_ctx *ctx, uint8_t *dst)
DST should point to an area of size at least BASE64_ENCODE_FINAL_LENGTH.
Definition: base64.c:253
static void usage(const char *progname)
Definition: squidclient.cc:95
bool LoopDone(int i)
whether ping loop is completed at the given iteration.
Definition: Ping.h:45
static int put_fd
Definition: squidclient.cc:72
ssize_t Write(void *buf, size_t len)
Definition: Transport.cc:238
bool Connect()
locate and connect to the configured server
Definition: Transport.cc:214
void base64_encode_init(struct base64_encode_ctx *ctx)
Definition: base64.c:182
#define debugVerbose(LEVEL, MESSAGE)
display debug messages at varying verbosity levels
Definition: Parameters.h:31
void ProbeTransport(void)
Probe to discover IPv6 capabilities.
uint32_t Init()
initialize the squidclient ping mode
Definition: Ping.cc:54
int unsigned int const char *desc STUB void int len
Definition: stub_fd.cc:20
void TimerStop(size_t fsize)
Definition: Ping.cc:92
void const char * buf
Definition: stub_helper.cc:16
#define SA_RESTART
#define O_TEXT
Definition: defines.h:201
int optind
Definition: getopt.c:48
ssize_t Read(void *buf, size_t len)
Definition: Transport.cc:262
static void Win32SockCleanup(void)
Definition: WinSvc.cc:981
#define xisdigit(x)
Definition: xis.h:20
Parameters scParams
global squidcleint parameters
Definition: squidclient.cc:70
#define VERSION
size_t HttpReply *STUB StoreEntry const KeyScope scope const HttpRequestMethod & method
Definition: stub_store.cc:126
void DisplayStats()
display summary of ping data collected
Definition: Ping.cc:141
Definition: fde.h:49
static void set_our_signal(void)
Definition: squidclient.cc:642
void ShutdownTls()
De-initialize TLS library environment when necessary.
Definition: Transport.cc:511
#define O_BINARY
Definition: defines.h:204
size_t base64_encode_update(struct base64_encode_ctx *ctx, uint8_t *dst, size_t length, const uint8_t *src)
Definition: base64.c:213
#define xfree
int total_bytes
Definition: squidclient.cc:76
char * optarg
Definition: getopt.c:51
#define NULL
Definition: types.h:166
char progname[]
bool parseCommandOpts(int argc, char *argv[], int c, int &optIndex)
Definition: Ping.cc:167
#define MESSAGELEN
Definition: squidclient.cc:58
#define base64_encode_len(length)
Definition: base64.h:93

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors