NCBI C++ ToolKit
ncbi_service_connector.c
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: ncbi_service_connector.c 102056 2024-03-23 01:56:16Z lavr $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Author: Anton Lavrentiev
27  *
28  * File Description:
29  * Implementation of CONNECTOR to a named service
30  *
31  */
32 
33 #include "ncbi_ansi_ext.h"
34 #include "ncbi_comm.h"
35 #include "ncbi_priv.h"
36 #include "ncbi_servicep.h"
37 #include "ncbi_socketp.h"
40 #include <ctype.h>
41 #include <stdlib.h>
42 
43 #define NCBI_USE_ERRCODE_X Connect_Service
44 
45 
46 typedef struct SServiceConnectorTag {
47  SMetaConnector meta; /* Lower level comm.conn. and its VT */
48  const char* type; /* Verbal connector type */
49  const char* descr; /* Verbal connector description */
50  const SConnNetInfo* net_info; /* R/O connection parameters */
51  const char* user_header; /* User header currently set */
52 
53  SERV_ITER iter; /* Dispatcher information (when open)*/
54 
55  SSERVICE_Extra extra; /* Extra params as passed to ctor */
56  EIO_Status status; /* Status of last I/O */
57 
58  TSERV_TypeOnly types; /* Server types w/o any specials */
59 
60  unsigned short retry; /* Open retry count since last okay */
61 
62  ticket_t ticket; /* Network byte order (none if zero) */
63  unsigned int host; /* Parsed connection info... (n.b.o) */
64  unsigned short port; /* ... (h.b.o) */
65 
66  /* flags */
67  unsigned reset:1; /* Non-zero if iter was just reset */
68  unsigned warned:1; /* Non-zero when adjusted via HTTP */
69  unsigned unused:5;
70  unsigned secure:1; /* Set when must start SSL on SOCK */
71 
72  const char name[1]; /* Original (unsubstituted) svc name */
74 
75 
76 static const char kHttpHostTag[] = "Host: ";
77 
78 
79 /***********************************************************************
80  * INTERNAL -- "s_VT_*" functions for the "virt. table" of connector methods
81  ***********************************************************************/
82 
83 #ifdef __cplusplus
84 extern "C" {
85 #endif /*__cplusplus*/
86  static const char* s_VT_GetType(CONNECTOR connector);
87  static char* s_VT_Descr (CONNECTOR connector);
88  static EIO_Status s_VT_Open (CONNECTOR connector,
89  const STimeout* timeout);
90  static EIO_Status s_VT_Status (CONNECTOR connector,
91  EIO_Event direction);
92  static EIO_Status s_VT_Close (CONNECTOR connector,
93  const STimeout* timeout);
94  static void s_Setup (CONNECTOR connector);
95  static void s_Destroy (CONNECTOR connector);
96 #ifdef __cplusplus
97 } /* extern "C" */
98 #endif /*__cplusplus*/
99 
100 
101 static int/*bool*/ s_OpenDispatcher(SServiceConnector* uuu)
102 {
103  if (!(uuu->iter = SERV_Open(uuu->name, uuu->types,
104  SERV_LOCALHOST, uuu->net_info))) {
106  ("[%s] Service not found", uuu->name));
107  return 0/*false*/;
108  }
109  uuu->reset = 1/*true*/;
110  return 1/*true*/;
111 }
112 
113 
115 {
116  SERV_Close(uuu->iter);
117  uuu->iter = 0;
118 }
119 
120 
121 /* Reset functions, which are implemented only in transport
122  * connectors, but not in this connector.
123  */
124 static void s_Reset(SMetaConnector *meta, CONNECTOR connector)
125 {
126  CONN_SET_METHOD(meta, descr, s_VT_Descr, connector);
127  CONN_SET_METHOD(meta, wait, 0, 0);
128  CONN_SET_METHOD(meta, write, 0, 0);
129  CONN_SET_METHOD(meta, flush, 0, 0);
130  CONN_SET_METHOD(meta, read, 0, 0);
131  CONN_SET_METHOD(meta, status, s_VT_Status, connector);
132 }
133 
134 
135 static EHTTP_HeaderParse s_ParseHeader(const char* header,
136  void* user_data,
137  int server_error,
138  int/*bool*/ user_callback_enabled)
139 {
140  static const char kStateless[] = "TRY_STATELESS";
141  static const size_t kSLen = sizeof(kStateless) - 1;
142  SServiceConnector* uuu = (SServiceConnector*) user_data;
143  EHTTP_HeaderParse header_parse;
144 
145  assert(header);
146  SERV_Update(uuu->iter, header, server_error);
147  if (user_callback_enabled && uuu->extra.parse_header) {
148  header_parse
149  = uuu->extra.parse_header(header, uuu->extra.data, server_error);
150  if (server_error || !header_parse)
151  return header_parse;
152  } else {
153  if (server_error)
154  return eHTTP_HeaderSuccess;
155  header_parse = eHTTP_HeaderError;
156  }
157  if (user_callback_enabled && !uuu->warned)
158  uuu->retry = 0;
159 
160  while (header && *header) {
161  if (strncasecmp(header, HTTP_CONNECTION_INFO,
162  sizeof(HTTP_CONNECTION_INFO) - 1) == 0) {
163  if (user_callback_enabled || uuu->host)
164  break/*failed - unexpected / duplicate connection info*/;
165  header += sizeof(HTTP_CONNECTION_INFO) - 1;
166  while (*header && isspace((unsigned char)(*header)))
167  ++header;
168  if (strncasecmp(header, kStateless, kSLen) == 0 &&
169  (!header[kSLen] || isspace((unsigned char) header[kSLen]))) {
170  /* Special keyword for switching into stateless mode */
171  uuu->host = (unsigned int)(-1);
172 #if defined(_DEBUG) && !defined(NDEBUG)
173  if (uuu->net_info->debug_printout) {
175  ("[%s] Fallback to stateless", uuu->name));
176  }
177 #endif /*_DEBUG && !NDEBUG*/
178  } else {
179  unsigned int i1, i2, i3, i4, tkt, n, m;
180  unsigned char o1, o2, o3, o4;
181  char ipaddr[40];
182 
183  if (sscanf(header, "%u.%u.%u.%u%n", &i1, &i2, &i3, &i4, &n) < 4
184  || sscanf(header + n, "%hu%x%n", &uuu->port, &tkt, &m) < 2
185  || (header[m += n] && !(header[m] == '$') &&
186  !isspace((unsigned char)((header + m)
187  [header[m] == '$'])))) {
188  break/*failed - unreadable connection info*/;
189  }
190  o1 = (unsigned char) i1;
191  o2 = (unsigned char) i2;
192  o3 = (unsigned char) i3;
193  o4 = (unsigned char) i4;
194  sprintf(ipaddr, "%u.%u.%u.%u", o1, o2, o3, o4);
195  if (strncmp(header, ipaddr, n) != 0
196  || !(uuu->host = SOCK_gethostbyname(ipaddr))
197  || !uuu->port) {
198  break/*failed - bad host:port in connection info*/;
199  }
200  uuu->ticket = SOCK_HostToNetLong(tkt);
201  if (header[m] == '$')
202  uuu->secure = 1;
203  }
204  }
205  if ((header = strchr(header, '\n')) != 0)
206  ++header;
207  }
208 
209  if (header && *header)
210  uuu->host = 0;
211  else if (!header_parse)
212  header_parse = eHTTP_HeaderSuccess;
213  return header_parse;
214 }
215 
216 
217 #ifdef __cplusplus
218 extern "C" {
219 #endif /*__cplusplus*/
220 static EHTTP_HeaderParse
221 s_ParseHeaderUCB (const char* header, void* data, int server_error)
222 {
223  return s_ParseHeader(header, data, server_error, 1/*enable user CB*/);
224 }
225 #ifdef __cplusplus
226 }
227 #endif /*__cplusplus*/
228 
229 
230 #ifdef __cplusplus
231 extern "C" {
232 #endif /*__cplusplus*/
233 static EHTTP_HeaderParse
234 s_ParseHeaderNoUCB(const char* header, void* data, int server_error)
235 {
236  return s_ParseHeader(header, data, server_error, 0/*disable user CB*/);
237 }
238 #ifdef __cplusplus
239 }
240 #endif /*__cplusplus*/
241 
242 
243 /*ARGSUSED*/
244 static int/*bool*/ s_IsContentTypeDefined(const char* service,
245  const SConnNetInfo* net_info,
246  EMIME_Type mime_t,
247  EMIME_SubType mime_s,
248  EMIME_Encoding mime_e)
249 {
250  static const char kContentType[] = "content-type:";
251  static const size_t kCTLen = sizeof(kContentType)-1;
252  const char* s;
253 
254  assert(net_info);
255  for (s = net_info->http_user_header; s; s = strchr(s, '\n')) {
256  if (s != net_info->http_user_header)
257  s++;
258  if (!*s)
259  break;
260  if (strncasecmp(s, kContentType, kCTLen) == 0
261  && isspace((unsigned char) s[kCTLen])) {
262 #if defined(_DEBUG) && !defined(NDEBUG)
263  EMIME_Type m_t;
264  EMIME_SubType m_s;
265  EMIME_Encoding m_e;
266  char c_t[CONN_CONTENT_TYPE_LEN+1];
267  if (net_info->debug_printout &&
268  mime_t != eMIME_T_Undefined &&
269  mime_t != eMIME_T_Unknown &&
270  (!MIME_ParseContentTypeEx(s, &m_t, &m_s, &m_e)
271  || mime_t != m_t
272  || (mime_s != eMIME_Undefined &&
273  mime_s != eMIME_Unknown &&
274  m_s != eMIME_Unknown && mime_s != m_s)
275  || (mime_e != eENCOD_None &&
276  m_e != eENCOD_None && mime_e != m_e))) {
277  const char* c;
278  size_t len;
279  char* t;
280  for (s += kCTLen + 1; *s; ++s) {
281  if (!isspace((unsigned char)(*s)))
282  break;
283  }
284  if (!(c = strchr(s, '\n')))
285  c = s + strlen(s);
286  if (c > s && c[-1] == '\r')
287  c--;
288  len = (size_t)(c - s);
289  if ((t = (char*) malloc(len + 1)) != 0) {
290  memcpy(t, s, len);
291  t[len] = '\0';
292  }
293  if (!MIME_ComposeContentTypeEx(mime_t, mime_s, mime_e,
294  c_t, sizeof(c_t))) {
295  *c_t = '\0';
296  }
298  ("[%s] Content-Type mismatch: "
299  "%s%s%s%s%s%s%s", service,
300  t && *t ? "specified=<" : "",
301  t && *t ? t : "",
302  t && *t ? ">" : "",
303  t && *t && *c_t ? ", " : "",
304  *c_t ? "configured=<" : "",
305  *c_t ? c_t : "",
306  *c_t ? ">" : ""));
307  if (t)
308  free(t);
309  }
310 #endif /*_DEBUG && !NDEBUG*/
311  return 1/*true*/;
312  }
313  }
314  return 0/*false*/;
315 }
316 
317 
318 static const char* s_AdjustNetParams(const char* service,
319  const char* svcname,
320  SConnNetInfo* net_info,
321  EReqMethod req_method,
322  const char* cgi_path,
323  const char* cgi_args,
324  const char* args,
325  const char* static_header,
326  EMIME_Type mime_t,
327  EMIME_SubType mime_s,
328  EMIME_Encoding mime_e,
329  const char* extend_header)
330 {
331  const char *retval = 0;
332 
333  net_info->req_method = req_method;
334 
335  if (cgi_path)
336  ConnNetInfo_SetPath(net_info, cgi_path);
337  if (args)
338  ConnNetInfo_SetArgs(net_info, args);
339 
340  if (ConnNetInfo_PreOverrideArg(net_info, cgi_args, 0)) {
341  size_t sh_len = static_header ? strlen(static_header) : 0;
342  size_t eh_len = extend_header ? strlen(extend_header) : 0;
343  char c_t[CONN_CONTENT_TYPE_LEN+1];
344  size_t len;
345 
346  if (s_IsContentTypeDefined(service, net_info, mime_t, mime_s, mime_e)
347  || !MIME_ComposeContentTypeEx(mime_t, mime_s, mime_e,
348  c_t, sizeof(c_t))) {
349  *c_t = '\0';
350  len = 0;
351  } else
352  len = strlen(c_t);
353  if ((len += sh_len + eh_len) != 0) {
354  char* temp = (char*) malloc(++len/*w/EOL*/);
355  if (temp) {
356  retval = temp;
357  if (static_header) {
358  memcpy(temp, static_header, sh_len);
359  temp += sh_len;
360  }
361  if (extend_header) {
362  memcpy(temp, extend_header, eh_len);
363  temp += eh_len;
364  }
365  strcpy(temp, c_t);
366  assert(*retval);
367  }
368  } else
369  retval = "";
370  }
371 
372  if (!ConnNetInfo_SetupStandardArgs(net_info, svcname)) {
373  if (retval && *retval)
374  free((void*) retval);
375  retval = 0;
376  }
377  return retval;
378 }
379 
380 
381 static SSERV_InfoCPtr s_GetNextInfo(SServiceConnector* uuu, int/*bool*/ http)
382 {
383  for (;;) {
385  ? uuu->extra.get_next_info(uuu->extra.data, uuu->iter)
386  : SERV_GetNextInfo(uuu->iter);
387  if (info) {
388  if (http) {
389  /* Skip any 'stateful_capable' or unconnectable entries here,
390  * which might have been left behind by either
391  * a/ a failed stateful dispatching that fallen back to
392  * stateless HTTP mode, or
393  * b/ a too relaxed server type selection.
394  */
395  if ((info->mode & fSERV_Stateful) || info->type == fSERV_Dns)
396  continue;
397  }
398  uuu->reset = 0/*false*/;
399  return info;
400  }
401  if (uuu->reset)
402  break;
403  if (uuu->extra.reset)
404  uuu->extra.reset(uuu->extra.data);
405  SERV_Reset(uuu->iter);
406  uuu->reset = 1/*true*/;
407  }
408  return 0;
409 }
410 
411 
412 static char* x_HostPort(const char* host, unsigned short aport)
413 {
414  char* hostport, port[16];
415  size_t hostlen = strlen(host);
416  size_t portlen = (size_t) sprintf(port, ":%hu", aport) + 1;
417  hostport = (char*) malloc(hostlen + portlen);
418  if (hostport) {
419  memcpy(hostport, host, hostlen);
420  memcpy(hostport + hostlen, port, portlen);
421  }
422  return hostport;
423 }
424 
425 
426 /* Until r294766, this code used to send a ticket along with building the
427  * tunnel, but for buggy proxies, which ignore HTTP body as connection data
428  * (and thus violate the standard), that shortcut could not be utilized;
429  * so the longer multi-step sequence was introduced below, instead.
430  * Cf. ncbi_conn_stream.cpp: s_SocketConnectorBuilder().
431  */
433  const char* hostport,
434  EIO_Status* status,
435  const void* data,
436  size_t size,
438 {
439  int/*bool*/ proxy = 0/*false*/;
440  SOCK sock = 0, s;
442  CONNECTOR c;
443 
444  flags |= (net_info->debug_printout == eDebugPrintout_Data
446  if (net_info->http_proxy_host[0] && net_info->http_proxy_port
447  && net_info->http_proxy_mask != fProxy_Http) {
448  /* NB: ideally, should have pushed data:size here if proxy not buggy */
449  *status = HTTP_CreateTunnel(net_info, fHTTP_NoAutoRetry, &sock);
450  assert(!sock ^ !(*status != eIO_Success));
451  if (*status == eIO_Success
452  && (size || (flags & (TSOCK_Flags)(~(fSOCK_LogOn |
453  fSOCK_LogDefault))))) {
454  /* push initial data through the proxy, as-is (i.e. clear-text) */
455  TSOCK_Flags tempf = flags;
456  if (size)
457  tempf &= (TSOCK_Flags)(~fSOCK_Secure);
458  memset(&init, 0, sizeof(init));
459  init.data = data;
460  init.size = size;
461  init.host = net_info->host;
462  init.cred = net_info->credentials;
463  *status = SOCK_CreateOnTopInternal(sock, 0, &s,
464  &init, tempf);
465  assert(!s ^ !(*status != eIO_Success));
466  SOCK_Destroy(sock);
467  sock = s;
468  if (*status == eIO_Success && tempf != flags) {
469  init.size = 0;
470  *status = SOCK_CreateOnTopInternal(sock, 0, &s,
471  &init, flags);
472  assert(!s ^ !(*status != eIO_Success));
473  SOCK_Destroy(sock);
474  sock = s;
475  }
476  }
477  proxy = 1/*true*/;
478  }
479  if (!sock && (!proxy || net_info->http_proxy_leak)) {
480  TSOCK_Flags tempf = flags;
481  if (size)
482  tempf &= (TSOCK_Flags)(~fSOCK_Secure);
483  if (!proxy && net_info->debug_printout) {
484  assert(net_info->scheme == eURL_Unspec);
485  net_info->req_method = eReqMethod_Any;
486  net_info->external = 0;
487  net_info->firewall = 0;
488  net_info->stateless = 0;
489  net_info->lb_disable = 0;
490  net_info->http_version = 0;
491  net_info->http_push_auth = 0;
492  net_info->http_proxy_leak = 0;
493  net_info->http_proxy_skip = 0;
494  net_info->http_proxy_mask = 0;
495  net_info->user[0] = '\0';
496  net_info->pass[0] = '\0';
497  net_info->path[0] = '\0';
498  net_info->http_proxy_host[0] = '\0';
499  net_info->http_proxy_port = 0;
500  net_info->http_proxy_user[0] = '\0';
501  net_info->http_proxy_pass[0] = '\0';
502  ConnNetInfo_SetUserHeader(net_info, 0);
503  if (net_info->http_referer) {
504  free((void*) net_info->http_referer);
505  net_info->http_referer = 0;
506  }
508  ConnNetInfo_Log(net_info, eLOG_Note, CORE_GetLOG());
509  CORE_UNLOCK;
510  }
511  memset(&init, 0, sizeof(init));
512  init.data = data;
513  init.size = size;
514  init.host = net_info->host;
515  init.cred = net_info->credentials;
516  *status = SOCK_CreateInternal(net_info->host, net_info->port,
517  net_info->timeout, &sock,
518  &init, tempf);
519  assert(!sock ^ !(*status != eIO_Success));
520  if (*status == eIO_Success && tempf != flags) {
521  init.size = 0;
522  *status = SOCK_CreateOnTopInternal(sock, 0, &s,
523  &init, flags);
524  assert(!s ^ !(*status != eIO_Success));
525  SOCK_Destroy(sock);
526  sock = s;
527  }
528  }
529  if (!(c = SOCK_CreateConnectorOnTopEx(sock, 1/*own*/, hostport))) {
530  SOCK_Abort(sock);
531  SOCK_Close(sock);
532  }
533  return c;
534 }
535 
536 
537 static int/*bool*/ x_SetHostPort(SConnNetInfo* net_info,
538  const SSERV_Info* info)
539 {
540  const char* vhost = SERV_HostOfInfo(info);
541 
542  if (vhost) {
543  char* tag;
544  assert(info->vhost);
545  if (!(tag = (char*) malloc(sizeof(kHttpHostTag) + info->vhost)))
546  return 0/*failure*/;
547  sprintf(tag, "%s%.*s", kHttpHostTag, (int) info->vhost, vhost);
548  if (!ConnNetInfo_OverrideUserHeader(net_info, tag)) {
549  free(tag);
550  return 0/*failure*/;
551  }
552  free(tag);
553  if (!net_info->http_proxy_host[0] || !net_info->http_proxy_port)
554  vhost = 0;
555  }
556  if (vhost) {
557  assert((size_t) info->vhost < sizeof(net_info->host));
558  strncpy0(net_info->host, vhost, (size_t) info->vhost);
559  } else if (info->host == SOCK_HostToNetLong((unsigned int)(-1))) {
560  int/*bool*/ ipv6 = !NcbiIsIPv4(&info->addr);
561  char* end = NcbiAddrToString(net_info->host + ipv6,
562  sizeof(net_info->host) - (size_t)(2*ipv6),
563  &info->addr);
564  if (!end) {
565  *net_info->host = '\0';
566  return 0/*failure*/;
567  }
568  if (ipv6) {
569  *net_info->host = '[';
570  *end++ = ']';
571  *end = '\0';
572  }
573  } else if (info->host) {
574  SOCK_ntoa(info->host, net_info->host, sizeof(net_info->host));
575  assert(*net_info->host);
576  } else
577  *net_info->host = '\0';
578 
579  net_info->port = info->port;
580  return 1/*success*/;
581 }
582 
583 
584 /* Although all additional HTTP tags that comprise the dispatching have their
585  * default values, which in most cases are fine with us, we will use these tags
586  * explicitly to distinguish the calls originated within the service connector
587  * from other calls (e.g. by Web browsers), and let the dispatcher decide
588  * whether to use more expensive dispatching (involving loopback connections)
589  * in the latter case.
590  */
591 
592 
593 #ifdef __cplusplus
594 extern "C" {
595  static int s_Adjust(SConnNetInfo*, void*, unsigned int);
596 }
597 #endif /*__cplusplus*/
598 
599 /* NB: This callback is only for services called via direct HTTP */
600 static int/*bool*/ s_Adjust(SConnNetInfo* net_info,
601  void* data,
602  unsigned int n)
603 {
605  SERV_ITER iter = uuu->iter;
606  char* iter_header;
607  const char* user_header;
609 
610  assert(n || uuu->extra.adjust);
611  assert(net_info != uuu->net_info);
612  assert(!net_info->firewall || net_info->stateless);
613 
614  if (n == (unsigned int)(-1))
615  return -1/*no new URL*/;
616  if (!n/*redirect*/)
617  return uuu->extra.adjust(net_info, uuu->extra.data, 0);
618 
619  uuu->warned = 1/*true*/;
620  if (uuu->retry >= uuu->net_info->max_try)
621  return 0/*failure - too many errors*/;
622  uuu->retry++;
623  if (!(info = s_GetNextInfo(uuu, 1/*http*/)))
624  return 0/*failure - not adjusted*/;
625 
626  iter_header = SERV_Print(iter, 0/*net_info*/, 0);
627  switch (info->type) {
628  case fSERV_Ncbid:
629  user_header = "Connection-Mode: STATELESS\r\n"; /*default*/
630  user_header = s_AdjustNetParams(uuu->name, iter->name, net_info,
633  SERV_NCBID_ARGS(&info->u.ncbid),
635  user_header, info->mime_t,
636  info->mime_s, info->mime_e,
637  iter_header);
638  break;
639  case fSERV_Http:
640  case fSERV_HttpGet:
641  case fSERV_HttpPost:
642  user_header = "Client-Mode: STATELESS_ONLY\r\n"; /*default*/
643  user_header = s_AdjustNetParams(uuu->name, iter->name, net_info,
644  info->type == fSERV_HttpPost
646  : (info->type == fSERV_HttpGet
648  : eReqMethod_Any),
649  SERV_HTTP_PATH(&info->u.http),
650  SERV_HTTP_ARGS(&info->u.http),
652  user_header, info->mime_t,
653  info->mime_s, info->mime_e,
654  iter_header);
655  break;
656  case fSERV_Firewall:
657  case fSERV_Standalone:
658  user_header = "Client-Mode: STATELESS_ONLY\r\n"; /*default*/
659  user_header = s_AdjustNetParams(uuu->name, iter->name, net_info,
660  eReqMethod_Any, uuu->net_info->path, 0,
662  user_header, info->mime_t,
663  info->mime_s, info->mime_e,
664  iter_header);
665  break;
666  default:
667  user_header = 0;
668  assert(0);
669  break;
670  }
671  if (iter_header)
672  free(iter_header);
673  if (!user_header)
674  return 0/*false - not adjusted*/;
675 
676  if (uuu->user_header) {
677  assert(*uuu->user_header);
679  free((void*) uuu->user_header);
680  }
681  if (*user_header) {
682  uuu->user_header = user_header;
683  if (!ConnNetInfo_OverrideUserHeader(net_info, user_header))
684  return 0/*failure - not adjusted*/;
685  } else /*NB: special case ""*/
686  uuu->user_header = 0;
687 
688  if (info->type != fSERV_Ncbid && !(info->type & fSERV_Http)) {
690  strcpy(net_info->host, uuu->net_info->host);
691  net_info->port = uuu->net_info->port;
692  } else if (!x_SetHostPort(net_info, info))
693  return 0/*failure - not adjusted*/;
694 
695  return uuu->extra.adjust
696  && !uuu->extra.adjust(net_info, uuu->extra.data, uuu->retry)
697  ? 0/*failure - not adjusted*/
698  : 1/*success - adjusted*/;
699 }
700 
701 
702 static void x_SetDefaultReferer(SConnNetInfo* net_info, SERV_ITER iter)
703 {
704  char* str, *referer;
705  const char* mapper = SERV_MapperName(iter);
706  assert(iter && !net_info->http_referer);
707  assert(mapper && *mapper);
708 
709  if (strcasecmp(mapper, "DISPD") == 0) {
710  /* the swap is to make sure URL prints correctly */
711  EBURLScheme scheme = net_info->scheme;
712  TReqMethod req_method = net_info->req_method;
713  net_info->scheme = eURL_Https;
714  net_info->req_method = eReqMethod_Get;
715  referer = ConnNetInfo_URL(net_info);
716  net_info->scheme = scheme;
717  net_info->req_method = req_method;
718  } else if ((str = strdup(mapper)) != 0) {
719  const char* args = strchr(net_info->path, '?');
720  const char* host = net_info->client_host;
721  const char* name = iter->name;
722  size_t len = strlen(strlwr(str));
723 
724  if (!*net_info->client_host
725  && !SOCK_gethostbyaddr(0, net_info->client_host,
726  sizeof(net_info->client_host))) {
727  SOCK_gethostname(net_info->client_host,
728  sizeof(net_info->client_host));
729  }
730  if (!(referer = (char*) realloc(str,
731  3 + 1 + 1/*EOL*/ + (len << 1) +
732  strlen(host) + (args && args[1]
733  ? strlen(args)
734  : 9 + strlen(name))))){
735  free(str);
736  return;
737  }
738  str = referer + len;
739  str += sprintf(str, "://%s/", host);
740  memmove(str, referer, len);
741  str += len;
742  if (args && args[1])
743  strcpy( str, args);
744  else
745  strcpy(strcpy(str, "?service="/*9*/) + 9, name);
746  } else
747  return;
748  net_info->http_referer = referer;
749 }
750 
751 
752 #ifdef __GNUC__
753 inline
754 #endif /*__GNUC__*/
756 {
757  assert(!c->meta && !c->next);
758  if (c->destroy)
759  c->destroy(c);
760 }
761 
762 
764  const STimeout* timeout,
766  SConnNetInfo* net_info,
767  EIO_Status* status)
768 {
769  int/*bool*/ but_last = 0/*false*/;
770  SERV_ITER iter = uuu->iter;
771  char* iter_header;
772  const char* user_header; /* either static "" or non-empty dynamic string */
773  EReqMethod req_method;
774 
775  *status = eIO_Success;
776  assert(net_info->firewall || info);
778  if (!net_info->http_referer)
779  x_SetDefaultReferer(net_info, iter);
780  if ((!net_info->firewall && info->type != fSERV_Firewall)
781  || (info && ((info->type & fSERV_Http) ||
782  (info->type == fSERV_Ncbid && net_info->stateless)))){
783  /* Not a firewall/relay connection here:
784  We know the connection point, so let's try to use it! */
785  if ((info->type != fSERV_Standalone || !net_info->stateless)
786  && !x_SetHostPort(net_info, info)) {
787  return 0;
788  }
789 
790  switch (info->type) {
791  case fSERV_Ncbid:
792  /* Connection directly to NCBID, add NCBID-specific tags */
793  net_info->scheme
794  = info->mode & fSERV_Secure ? eURL_Https : eURL_Http;
795  req_method = eReqMethod_Any; /* replaced with GET if aux HTTP */
796  user_header = net_info->stateless
797  /* Connection request with data */
798  ? "Connection-Mode: STATELESS\r\n" /*default*/
799  /* We will be waiting for conn-info back */
800  : "Connection-Mode: STATEFUL\r\n";
801  user_header = s_AdjustNetParams(uuu->name, iter->name, net_info,
802  req_method,
804  SERV_NCBID_ARGS(&info->u.ncbid),
805  0, user_header, info->mime_t,
806  info->mime_s, info->mime_e, 0);
807  break;
808  case fSERV_Http:
809  case fSERV_HttpGet:
810  case fSERV_HttpPost:
811  /* Connection directly to a CGI */
812  net_info->scheme
813  = info->mode & fSERV_Secure ? eURL_Https : eURL_Http;
814  req_method = info->type == fSERV_HttpGet
815  ? eReqMethod_Get : (info->type == fSERV_HttpPost
817  net_info->stateless = 1/*true*/;
818  user_header = "Client-Mode: STATELESS_ONLY\r\n"; /*default*/
819  user_header = s_AdjustNetParams(uuu->name, iter->name, net_info,
820  req_method,
821  SERV_HTTP_PATH(&info->u.http),
822  SERV_HTTP_ARGS(&info->u.http),
823  0, user_header, info->mime_t,
824  info->mime_s, info->mime_e, 0);
825  break;
826  case fSERV_Standalone:
827  if (!net_info->stateless) {
828  net_info->scheme = eURL_Unspec;
829  assert(!uuu->descr);
830  uuu->descr = x_HostPort(net_info->host, net_info->port);
831  return s_SocketConnectorBuilder(net_info, uuu->descr, status,
832  0, 0, info->mode & fSERV_Secure
833  ? fSOCK_Secure : 0);
834  }
835  /* Otherwise, it will be a pass-thru connection via dispatcher */
836  if (!net_info->scheme)
837  net_info->scheme = eURL_Https;
838  user_header = "Client-Mode: STATELESS_ONLY\r\n"; /*default*/
839  user_header = s_AdjustNetParams(uuu->name, iter->name, net_info,
840  eReqMethod_Any, 0, 0,
841  0, user_header, info->mime_t,
842  info->mime_s, info->mime_e, 0);
843  but_last = 1/*true*/;
844  break;
845  default:
846  user_header = 0;
847  assert(0);
848  break;
849  }
850  } else {
851  /* Firewall/relay connection via dispatcher */
853  EMIME_Type mime_t;
854  EMIME_SubType mime_s;
855  EMIME_Encoding mime_e;
856 
857  if (!net_info->scheme)
858  net_info->scheme = eURL_Https;
859  if (info && (fSERV_Http & (type = info->type == fSERV_Firewall
860  ? info->u.firewall.type
861  : info->type))) {
862  req_method = (type == fSERV_HttpGet
864  : (type == fSERV_HttpPost
866  : eReqMethod_Any));
867  net_info->stateless = 1/*true*/;
868  } else
869  req_method = eReqMethod_Any; /* may downgrade to GET w/aux HTTP */
870 
871  if (info) {
872  mime_t = info->mime_t;
873  mime_s = info->mime_s;
874  mime_e = info->mime_e;
875  but_last = 1/*true*/;
876  } else {
877  mime_t = eMIME_T_Undefined;
878  mime_s = eMIME_Undefined;
879  mime_e = eENCOD_None;
880  }
881 
882  /* Firewall/relay connection thru dispatcher, special tags */
883  user_header = (net_info->stateless
884  ? "Client-Mode: STATELESS_ONLY\r\n" /*default*/
885  : "Client-Mode: STATEFUL_CAPABLE\r\n");
886  user_header = s_AdjustNetParams(uuu->name, iter->name, net_info,
887  req_method, 0, 0,
888  0, user_header, mime_t,
889  mime_s, mime_e, 0);
890  }
891  if (!user_header)
892  return 0;
893 
894  if ((iter_header = SERV_Print(iter, net_info, but_last)) != 0) {
895  size_t uh_len;
896  if ((uh_len = strlen(user_header)) > 0) {
897  char* ih;
898  size_t ih_len = strlen(iter_header);
899  if ((ih = (char*) realloc(iter_header, ++uh_len + ih_len)) != 0) {
900  memcpy(ih + ih_len, user_header, uh_len);
901  iter_header = ih;
902  }
903  free((void*) user_header);
904  }
905  user_header = iter_header;
906  } else if (!*user_header)
907  user_header = 0; /* special case of assignment of literal "" */
908 
909  if (uuu->user_header) {
910  /* delete previously set user header first */
912  free((void*) uuu->user_header);
913  }
914  /* then set a new one */
915  uuu->user_header = user_header;
916  if (user_header && !ConnNetInfo_OverrideUserHeader(net_info, user_header))
917  return 0;
918 
920  (net_info, "User-Agent: NCBIServiceConnector/"
922 #ifdef NCBI_CXX_TOOLKIT
923  " (CXX Toolkit)"
924 #else
925  " (C Toolkit)"
926 #endif /*NCBI_CXX_TOOLKIT*/
927  );
928 
929  if (!net_info->stateless && (net_info->firewall ||
930  info->type == fSERV_Firewall ||
931  info->type == fSERV_Ncbid)) {
932  /* Auxiliary HTTP connector first */
933  EIO_Status aux_status;
934  CONNECTOR c;
935  CONN conn;
936 
937  /* Clear connection info */
938  uuu->host = 0;
939  uuu->port = 0;
940  uuu->ticket = 0;
941  uuu->secure = 0;
942  assert(net_info->scheme == eURL_Https ||
943  net_info->scheme == eURL_Http);
944  assert(!net_info->req_method/*Any*/);
945  net_info->req_method = eReqMethod_Get;
946  c = HTTP_CreateConnectorEx(net_info,
948  s_ParseHeaderNoUCB, uuu/*user_data*/,
949  0/*adjust*/, 0/*cleanup*/);
950  /* Wait for connection info back from dispatcher */
951  if (c && (*status = CONN_Create(c, &conn)) == eIO_Success) {
952  CONN_SetTimeout(conn, eIO_Open, timeout);
954  CONN_SetTimeout(conn, eIO_Close, timeout);
955  /* Send all the HTTP data... */
956  *status = CONN_Flush(conn);
957  /* ...then trigger the header callback */
958  aux_status = CONN_Close(conn);
959  if (aux_status != eIO_Success &&
960  aux_status != eIO_Closed &&
961  *status < aux_status) {
962  *status = aux_status;
963  }
964  } else {
965  /* can only happen if we're out of memory */
966  const char* error;
967  if (c) {
968  error = IO_StatusStr(*status);
970  } else
971  error = 0;
973  ("[%s] Unable to create auxiliary HTTP %s%s%s",
974  uuu->name, c ? "connection" : "connector",
975  error && *error ? ": " : "", error ? error : ""));
976  assert(!uuu->host);
977  }
978  if (uuu->host == (unsigned int)(-1)) {
979  assert(net_info->firewall || info->type == fSERV_Firewall);
980  assert(!net_info->stateless);
981  assert(!uuu->port);
982  net_info->stateless = 1/*true*/;
983  /* Fallback to try to use stateless mode instead */
984  return s_Open(uuu, timeout, info, net_info, status);
985  }
986  if (!uuu->host || !uuu->port) {
987  /* no connection info found */
988  ConnNetInfo_SetArgs(net_info, 0);
989  assert(!uuu->descr);
990  return 0;
991  }
992  if (net_info->firewall == eFWMode_Fallback
993  && !SERV_IsFirewallPort(uuu->port)) {
995  ("[%s] Firewall port :%hu is not in the fallback set",
996  uuu->name, uuu->port));
997  }
999  net_info->scheme = eURL_Unspec;
1000  SOCK_ntoa(uuu->host, net_info->host, sizeof(net_info->host));
1001  net_info->port = uuu->port;
1002  assert(!uuu->descr);
1003  uuu->descr = x_HostPort(net_info->host, net_info->port);
1004  return s_SocketConnectorBuilder(net_info, uuu->descr, status,
1005  &uuu->ticket,
1006  uuu->ticket ? sizeof(uuu->ticket) : 0,
1007  uuu->secure ? fSOCK_Secure : 0);
1008  }
1009  if (info && (info->mode & fSERV_Secure))
1010  net_info->scheme = eURL_Https;
1011  else if (!net_info->scheme)
1012  net_info->scheme = eURL_Http;
1013  assert(!uuu->descr);
1014  return !uuu->extra.adjust
1015  || uuu->extra.adjust(net_info, uuu->extra.data, (unsigned int)(-1))
1016  ? HTTP_CreateConnectorEx(net_info,
1017  (uuu->extra.flags
1020  (uuu->extra.adjust
1022  : 0)))
1024  s_ParseHeaderUCB, uuu/*user_data*/,
1025  s_Adjust, 0/*cleanup*/)
1026  : 0/*failure*/;
1027 }
1028 
1029 
1030 static void s_Cleanup(SServiceConnector* uuu)
1031 {
1032  if (uuu->type) {
1033  free((void*) uuu->type);
1034  uuu->type = 0;
1035  }
1036  if (uuu->descr) {
1037  free((void*) uuu->descr);
1038  uuu->descr = 0;
1039  }
1040  if (uuu->user_header) {
1041  free((void*) uuu->user_header);
1042  uuu->user_header = 0;
1043  }
1044 }
1045 
1046 
1047 static EIO_Status s_Close(CONNECTOR connector,
1048  const STimeout* timeout,
1049  int/*bool*/ cleanup)
1050 {
1051  SServiceConnector* uuu = (SServiceConnector*) connector->handle;
1052  EIO_Status status;
1053 
1054  if (cleanup) {
1055  status = uuu->meta.close
1056  ? uuu->meta.close(uuu->meta.c_close, timeout)
1057  : eIO_Success;
1058  if (uuu->extra.reset)
1059  uuu->extra.reset(uuu->extra.data);
1060  s_CloseDispatcher(uuu);
1061  s_Cleanup(uuu);
1062  } else
1063  status = eIO_Success/*unused*/;
1064 
1065  if (uuu->meta.list) {
1066  SMetaConnector* meta = connector->meta;
1067  verify(METACONN_Remove(meta, uuu->meta.list) == eIO_Success);
1068  uuu->meta.list = 0;
1069  s_Reset(meta, connector);
1070  }
1071 
1072  return status;
1073 }
1074 
1075 
1076 static const char* s_VT_GetType(CONNECTOR connector)
1077 {
1078  SServiceConnector* uuu = (SServiceConnector*) connector->handle;
1079  return uuu->type ? uuu->type : uuu->name;
1080 }
1081 
1082 
1083 static char* s_VT_Descr(CONNECTOR connector)
1084 {
1085  SServiceConnector* uuu = (SServiceConnector*) connector->handle;
1086  return uuu->descr && *uuu->descr ? strdup(uuu->descr) : 0;
1087 }
1088 
1089 
1090 static EIO_Status s_VT_Open(CONNECTOR connector, const STimeout* timeout)
1091 {
1092  SServiceConnector* uuu = (SServiceConnector*) connector->handle;
1093  SMetaConnector* meta = connector->meta;
1094  EIO_Status status = eIO_Closed;
1095 
1096  uuu->warned = 0/*false*/;
1097  for (uuu->retry = 0; uuu->retry < uuu->net_info->max_try; uuu->retry++) {
1098  SConnNetInfo* net_info;
1100  const char* type;
1101  int stateless;
1102  CONNECTOR c;
1103  char* descr;
1104 
1105  assert(!uuu->meta.list && status != eIO_Success);
1106 
1107  if (!uuu->iter && !s_OpenDispatcher(uuu))
1108  break;
1109 
1110  if (!(info = s_GetNextInfo(uuu, 0/*any*/))
1111  && (!uuu->net_info->firewall
1112  || strcmp(SERV_MapperName(uuu->iter), "LOCAL") == 0)) {
1113  break;
1114  }
1115  if (uuu->type) {
1116  free((void*) uuu->type);
1117  uuu->type = 0;
1118  }
1119  if (uuu->descr) {
1120  free((void*) uuu->descr);
1121  uuu->descr = 0;
1122  }
1123  if (!(net_info = ConnNetInfo_Clone(uuu->net_info))) {
1124  status = eIO_Unknown;
1125  break;
1126  }
1127  if (info && strcmp(SERV_MapperName(uuu->iter), "LINKERD") == 0) {
1128  /* LINKERD *is* a proxy, so just drop HTTP proxy (if any) here */
1129  net_info->http_proxy_host[0] = '\0';
1130  net_info->http_proxy_port = 0;
1131  net_info->http_proxy_user[0] = '\0';
1132  net_info->http_proxy_pass[0] = '\0';
1133  net_info->http_proxy_leak = 0;
1134  net_info->http_proxy_skip = 0;
1135  net_info->http_proxy_mask = fProxy_Http;
1136  }
1137 
1138  c = s_Open(uuu, timeout, info, net_info, &status);
1139  descr = uuu->descr ? (char*) uuu->descr : ConnNetInfo_URL(net_info);
1140  stateless = net_info->stateless;
1141 
1142  ConnNetInfo_Destroy(net_info);
1143 
1144  if (!c) {
1145  if (status == eIO_Success)
1146  status = eIO_Unknown;
1147  uuu->descr = descr;
1148  continue;
1149  }
1150  {{
1151  EIO_Status meta_status;
1152  /* Setup the new connector on a temporary meta-connector... */
1153  memset(&uuu->meta, 0, sizeof(uuu->meta));
1154  meta_status = METACONN_Insert(&uuu->meta, c);
1155  if (meta_status != eIO_Success) {
1156  x_DestroyConnector(c);
1157  status = meta_status;
1158  uuu->descr = descr;
1159  continue;
1160  }
1161  }}
1162  /* ...then link it in using the current connection's meta */
1163  assert(c->meta == &uuu->meta);
1164  c->next = meta->list;
1165  meta->list = c;
1166 
1167  if (!uuu->meta.descr)
1168  uuu->descr = descr;
1169  else if (!uuu->descr) {
1170  if (descr)
1171  free(descr);
1172  CONN_SET_METHOD(meta, descr, uuu->meta.descr, uuu->meta.c_descr);
1173  }
1174  CONN_SET_METHOD (meta, wait, uuu->meta.wait, uuu->meta.c_wait);
1175  CONN_SET_METHOD (meta, write, uuu->meta.write, uuu->meta.c_write);
1176  CONN_SET_METHOD (meta, flush, uuu->meta.flush, uuu->meta.c_flush);
1177  CONN_SET_METHOD (meta, read, uuu->meta.read, uuu->meta.c_read);
1178  CONN_SET_METHOD (meta, status, uuu->meta.status,uuu->meta.c_status);
1179 
1180  type = uuu->meta.get_type
1181  ? uuu->meta.get_type(uuu->meta.c_get_type) : 0;
1182  if (type) {
1183  size_t nlen = strlen(uuu->name);
1184  size_t tlen = strlen(type);
1185  char* temp = (char*) malloc(nlen + tlen + 2);
1186  if (temp) {
1187  memcpy(temp, uuu->name, nlen);
1188  temp[nlen++] = '/';
1189  memcpy(temp + nlen, type, tlen);
1190  temp[nlen + tlen] = '\0';
1191  uuu->type = temp;
1192  }
1193  }
1194 
1195  if (status == eIO_Success) {
1196  if (!uuu->meta.open) {
1197  s_Close(connector, timeout, 0/*retain*/);
1198  status = eIO_NotSupported;
1199  continue;
1200  }
1201 
1202  status = uuu->meta.open(uuu->meta.c_open, timeout);
1203  if (status == eIO_Success)
1204  break;
1205  }
1206  if (!stateless
1207  && (uuu->net_info->firewall || info->type == fSERV_Firewall)
1208  && type && strcmp(type, g_kNcbiSockNameAbbr) == 0) {
1209  static const char kFWDLink[] = CONN_FWD_LINK;
1211  ("[%s] %s connection failure (%s) usually"
1212  " indicates possible firewall configuration"
1213  " problem(s); please consult <%s>", uuu->name,
1214  uuu->net_info->firewall ? "Firewall":"Stateful relay",
1215  IO_StatusStr(status), kFWDLink));
1216  }
1217 
1218  s_Close(connector, timeout, 0/*retain*/);
1219  }
1220  if (status != eIO_Success && !uuu->warned
1221  && uuu->retry > 1 && uuu->retry >= uuu->net_info->max_try) {
1222  CORE_LOGF_X(10, eLOG_Error,
1223  ("[%s] Too many failed attempts (%hu), giving up",
1224  uuu->name, uuu->retry));
1225  }
1226  uuu->status = status;
1227  return status;
1228 }
1229 
1230 
1231 /*ARGSUSED*/
1233 {
1234  return ((SServiceConnector*) connector->handle)->status;
1235 }
1236 
1237 
1238 static EIO_Status s_VT_Close(CONNECTOR connector, const STimeout* timeout)
1239 {
1240  return s_Close(connector, timeout, 1/*cleanup*/);
1241 }
1242 
1243 
1244 static void s_Setup(CONNECTOR connector)
1245 {
1246  SServiceConnector* uuu = (SServiceConnector*) connector->handle;
1247  SMetaConnector* meta = connector->meta;
1248 
1249  /* initialize virtual table */
1250  CONN_SET_METHOD(meta, get_type, s_VT_GetType, connector);
1251  CONN_SET_METHOD(meta, open, s_VT_Open, connector);
1252  CONN_SET_METHOD(meta, close, s_VT_Close, connector);
1254  /* reset everything else */
1255  s_Reset(meta, connector);
1256 }
1257 
1258 
1259 static void s_Destroy(CONNECTOR connector)
1260 {
1261  SServiceConnector* uuu = (SServiceConnector*) connector->handle;
1262  connector->handle = 0;
1263 
1264  if (uuu->extra.cleanup)
1265  uuu->extra.cleanup(uuu->extra.data);
1266  s_CloseDispatcher(uuu);
1267  s_Cleanup(uuu);
1269  free(uuu);
1270  free(connector);
1271 }
1272 
1273 
1274 /***********************************************************************
1275  * EXTERNAL -- the connector's "constructor"
1276  ***********************************************************************/
1277 
1279 (const char* name,
1280  TSERV_Type types,
1281  const SConnNetInfo* net_info,
1282  const SSERVICE_Extra* extra)
1283 {
1284  SConnNetInfo* x_net_info;
1285  char* x_name;
1286  size_t len;
1287  CONNECTOR ccc;
1288  SServiceConnector* xxx;
1289 
1290  if (!(x_name = SERV_ServiceName(name)))
1291  return 0;
1292 
1293  if (!(ccc = (SConnector*) malloc(sizeof(SConnector)))) {
1294  free(x_name);
1295  return 0;
1296  }
1297  len = strlen(name);
1298  if (!(xxx = (SServiceConnector*) calloc(1, sizeof(*xxx) + len + 1))) {
1299  free(x_name);
1300  free(ccc);
1301  return 0;
1302  }
1303 
1304  /* initialize connector structures */
1305  ccc->handle = xxx;
1306  ccc->next = 0;
1307  ccc->meta = 0;
1308  ccc->setup = s_Setup;
1309  ccc->destroy = s_Destroy;
1310 
1311  x_net_info = (net_info
1312  ? ConnNetInfo_Clone(net_info)
1313  : ConnNetInfo_CreateInternal(x_name));
1314  free(x_name);
1315  if (!x_net_info) {
1316  s_Destroy(ccc);
1317  return 0;
1318  }
1319  xxx->net_info = x_net_info;
1320  xxx->types = (TSERV_TypeOnly) types;
1321  /* NB: zero'ed block, no need to copy the trailing '\0' */
1322  memcpy((char*) xxx->name, name, len);
1323 
1324  /* now get ready for first probe dispatching */
1325  if ( types & fSERV_Stateless )
1326  x_net_info->stateless = 1/*true*/;
1327  if ((types & fSERV_Firewall) && !x_net_info->firewall)
1328  x_net_info->firewall = eFWMode_Adaptive;
1329  if (x_net_info->max_try < 1
1330  || (extra && (extra->flags & fHTTP_NoAutoRetry))) {
1331  x_net_info->max_try = 1;
1332  }
1333  if (!(types & fSERV_DelayOpen)) {
1334  if (!s_OpenDispatcher(xxx)) {
1335  s_Destroy(ccc);
1336  return 0;
1337  }
1338  assert(xxx->iter);
1339  }
1340 
1341  /* finally, store all callback extras */
1342  if (extra)
1343  memcpy(&xxx->extra, extra, sizeof(xxx->extra));
1344 
1345  /* done */
1346  return ccc;
1347 }
static const char * kContentType
static uch flags
int close(int fd)
Definition: connection.cpp:45
static void cleanup(void)
Definition: ct_dynamic.c:30
static CS_CONNECTION * conn
Definition: ct_dynamic.c:25
static void DLIST_NAME() init(DLIST_LIST_TYPE *list)
Definition: dlist.tmpl.h:40
static int type
Definition: getdata.c:31
static const char * str(char *buf, int n)
Definition: stats.c:84
static const struct type types[]
Definition: type.c:22
char data[12]
Definition: iconv.c:80
CONNECTOR SERVICE_CreateConnectorEx(const char *name, TSERV_Type types, const SConnNetInfo *net_info, const SSERVICE_Extra *extra)
EIO_Status HTTP_CreateTunnel(const SConnNetInfo *net_info, THTTP_Flags flags, SOCK *sock)
Same as HTTP_CreateTunnelEx(net_info, flags, 0, 0, 0, 0, sock)
CONNECTOR c_descr
CONNECTOR c_wait
CONNECTOR c_status
FSetupVTable setup
init meta, may not be NULL
#define CONN_SET_METHOD(meta, method, function, connector)
CONNECTOR HTTP_CreateConnectorEx(const SConnNetInfo *net_info, THTTP_Flags flags, FHTTP_ParseHeader parse_header, void *user_data, FHTTP_Adjust adjust, FHTTP_Cleanup cleanup)
Create new CONNECTOR structure to hit the specified URL using HTTP with either POST / GET (or ANY) me...
CONNECTOR c_flush
FConnectorGetType get_type
unsigned int THTTP_Flags
Bitwise OR of EHTTP_Flag.
EIO_Status CONN_Flush(CONN conn)
Explicitly flush connection from any pending data written by CONN_Write().
CONNECTOR c_write
FConnectorDescr descr
#define CONN_SET_DEFAULT_TIMEOUT(meta, timeout)
CONNECTOR c_read
FConnectorFlush flush
FConnectorOpen open
CONNECTOR next
linked list
FHTTP_ParseHeader parse_header
FConnectorClose close
EIO_Status CONN_SetTimeout(CONN conn, EIO_Event event, const STimeout *timeout)
Specify timeout for the connection I/O, including "Connect" (aka "Open") and "Close".
EIO_Status CONN_Create(CONNECTOR connector, CONN *conn)
Same as CONN_CreateEx() called with 0 in the "flags" parameter.
FDestroy destroy
destroys handle, can be NULL
FSERVICE_GetNextInfo get_next_info
EIO_Status METACONN_Remove(SMetaConnector *meta, CONNECTOR connector)
Delete given "connector" all its descendants (all connectors if "connector" is NULL) from the connect...
EHTTP_HeaderParse
The extended version HTTP_CreateConnectorEx() is able to track the HTTP response chain and also chang...
EIO_Status METACONN_Insert(SMetaConnector *meta, CONNECTOR connector)
Insert a connector in the beginning of the connection's list of connectors.
void * handle
data handle of the connector
FSERVICE_Cleanup cleanup
SMetaConnector * meta
back link to original meta
EIO_Status CONN_Close(CONN conn)
Close the connection and destroy all relevant internal data.
FConnectorWrite write
CONNECTOR c_close
CONNECTOR c_get_type
CONNECTOR SOCK_CreateConnectorOnTopEx(SOCK sock, unsigned short own_sock, const char *hostport)
CONNECTOR c_open
FConnectorStatus status
FSERVICE_Reset reset
FConnectorRead read
FConnectorWait wait
@ fHTTP_AdjustOnRedirect
Call adjust routine for redirects, too.
@ fHTTP_NoAutoRetry
No auto-retries allowed.
@ fHTTP_AutoReconnect
See HTTP_CreateConnectorEx()
@ fHTTP_Flushable
Connector will really flush on Flush()
@ eHTTP_HeaderSuccess
Parse succeeded, retain server status.
@ eHTTP_HeaderError
Parse failed, treat as a server error.
#define SERV_HTTP_PATH(ui)
#define SERV_HTTP_ARGS(ui)
SSERV_InfoCPtr SERV_GetNextInfo(SERV_ITER iter)
Same as "SERV_GetNextInfoEx(., 0)" – i.e.
Definition: ncbi_service.c:936
void SERV_Close(SERV_ITER iter)
Deallocate the iterator.
Definition: ncbi_service.c:993
void SERV_Reset(SERV_ITER iter)
Reset the iterator to the state as if it has just been opened.
Definition: ncbi_service.c:981
SERV_ITER SERV_Open(const char *service, TSERV_Type types, unsigned int preferred_host, const SConnNetInfo *net_info)
Same as "SERV_OpenEx(., ., ., ., 0, 0)" – i.e.
Definition: ncbi_service.c:809
unsigned int TSERV_Type
Bitwise OR of ESERV_Type[Special].
Definition: ncbi_service.h:94
unsigned short TSERV_TypeOnly
Server type only, w/o specials.
Definition: ncbi_service.h:95
#define SERV_LOCALHOST
Special values for the "preferred_host" parameter.
Definition: ncbi_service.h:54
#define SERV_NCBID_ARGS(ui)
@ fSERV_Firewall
@ fSERV_Http
@ fSERV_HttpPost
@ fSERV_Standalone
@ fSERV_HttpGet
@ fSERV_Dns
@ fSERV_Ncbid
@ fSERV_Stateless
Stateless servers only.
Definition: ncbi_service.h:81
@ fSERV_DelayOpen
Don't open service until use.
Definition: ncbi_service.h:83
@ fSERV_Secure
@ fSERV_Stateful
unsigned int SOCK_HostToNetLong(unsigned int value)
See man for the BSDisms, htonl() and htons().
Definition: ncbi_socket.c:8736
#define SOCK_Destroy(s)
Definition: ncbi_socket.h:875
EIO_Status SOCK_Close(SOCK sock)
Close the SOCK handle, and destroy all relevant internal data.
Definition: ncbi_socket.c:6851
int SOCK_gethostname(char *name, size_t namelen)
Same as SOCK_gethostnameEx(,,<current API data logging>)
Definition: ncbi_socket.c:8774
unsigned int SOCK_gethostbyname(const char *hostname)
Same as SOCK_gethostbynameEx(,<current API data logging>)
Definition: ncbi_socket.c:8790
EIO_Status SOCK_Abort(SOCK sock)
If there is outstanding connection or output data pending, cancel it.
Definition: ncbi_socket.c:7557
int SOCK_ntoa(unsigned int addr, char *buf, size_t bufsize)
Convert IP address to a string in dotted notation.
Definition: ncbi_socket.c:8661
const char * SOCK_gethostbyaddr(unsigned int addr, char *name, size_t namelen)
Same as SOCK_gethostbyaddrEx(,,<current API data logging>)
Definition: ncbi_socket.c:8813
unsigned int TSOCK_Flags
bitwise "OR" of ESOCK_Flags
Definition: ncbi_socket.h:503
@ fSOCK_LogDefault
Definition: ncbi_socket.h:491
@ fSOCK_Secure
subsumes CloseOnExec regardless of Keep
Definition: ncbi_socket.h:497
@ fSOCK_LogOn
Definition: ncbi_socket.h:490
TReqMethod req_method
unsigned EBURLScheme
unsigned external
char http_proxy_host[255+1]
unsigned lb_disable
EBFWMode firewall
int ConnNetInfo_ExtendUserHeader(SConnNetInfo *net_info, const char *header)
unsigned TReqMethod
int ConnNetInfo_SetupStandardArgs(SConnNetInfo *net_info, const char *service)
char http_proxy_user[63+1]
unsigned short http_proxy_port
int ConnNetInfo_OverrideUserHeader(SConnNetInfo *net_info, const char *header)
const STimeout * timeout
unsigned short port
unsigned http_push_auth
char * MIME_ComposeContentTypeEx(EMIME_Type type, EMIME_SubType subtype, EMIME_Encoding encoding, char *buf, size_t bufsize)
int ConnNetInfo_SetArgs(SConnNetInfo *net_info, const char *args)
EMIME_Type
EMIME_SubType
SConnNetInfo * ConnNetInfo_Clone(const SConnNetInfo *net_info)
LOG CORE_GetLOG(void)
Get the log handle that is to be used by the core internals (CORE LOG).
Definition: ncbi_util.c:138
char user[63+1]
EIO_Status
I/O status.
Definition: ncbi_core.h:132
#define CONN_CONTENT_TYPE_LEN
char http_proxy_pass[63+1]
const char * ConnNetInfo_GetArgs(const SConnNetInfo *net_info)
EMIME_Encoding
int ConnNetInfo_PreOverrideArg(SConnNetInfo *net_info, const char *arg, const char *val)
unsigned http_proxy_leak
EReqMethod
unsigned stateless
char * ConnNetInfo_URL(const SConnNetInfo *net_info)
const char * IO_StatusStr(EIO_Status status)
Get the text form of an enum status value.
Definition: ncbi_core.c:56
int ConnNetInfo_SetUserHeader(SConnNetInfo *net_info, const char *header)
int MIME_ParseContentTypeEx(const char *str, EMIME_Type *type, EMIME_SubType *subtype, EMIME_Encoding *encoding)
void ConnNetInfo_DeleteUserHeader(SConnNetInfo *net_info, const char *header)
unsigned http_proxy_skip
void ConnNetInfo_Log(const SConnNetInfo *net_info, ELOG_Level sev, LOG log)
EBURLScheme scheme
const char * http_user_header
EBProxyType http_proxy_mask
unsigned short max_try
NCBI_CRED credentials
char pass[63+1]
unsigned http_version
EIO_Event
I/O event (or direction).
Definition: ncbi_core.h:118
char host[255+1]
char client_host[255+1]
char path[4095+1]
EBDebugPrintout debug_printout
int ConnNetInfo_SetPath(SConnNetInfo *net_info, const char *path)
const char * http_referer
void ConnNetInfo_Destroy(SConnNetInfo *net_info)
@ eLOG_Error
Definition: ncbi_core.h:297
@ eLOG_Note
Definition: ncbi_core.h:294
@ eLOG_Warning
Definition: ncbi_core.h:296
@ eURL_Unspec
@ eURL_Http
@ eURL_Https
@ eMIME_T_Undefined
@ eMIME_T_Unknown
@ eMIME_Undefined
@ eMIME_Unknown
@ eIO_NotSupported
operation is not supported or is not available
Definition: ncbi_core.h:138
@ eIO_Success
everything is fine, no error occurred
Definition: ncbi_core.h:133
@ eIO_Unknown
unknown I/O error (likely fatal but can retry)
Definition: ncbi_core.h:139
@ eENCOD_None
@ eReqMethod_Any
@ eReqMethod_Get
@ eReqMethod_Post
@ fProxy_Http
$http_proxy used
@ eFWMode_Adaptive
Regular firewall ports first, then fallback.
@ eFWMode_Fallback
Fallback ports only (w/o trying any regular)
@ eDebugPrintout_Data
@ eIO_ReadWrite
eIO_Read | eIO_Write (also, eCONN_OnFlush)
Definition: ncbi_core.h:122
@ eIO_Open
also serves as no-event indicator in SOCK_Poll
Definition: ncbi_core.h:119
@ eIO_Close
also serves as an error indicator in SOCK_Poll
Definition: ncbi_core.h:123
unsigned int
A callback function used to compare two keys in a database.
Definition: types.hpp:1210
for(len=0;yy_str[len];++len)
if(yy_accept[yy_current_state])
yy_size_t n
int len
static const CS_INT unused
Definition: long_binary.c:20
static MDB_envinfo info
Definition: mdb_load.c:37
const struct ncbi::grid::netcache::search::fields::SIZE size
int strncmp(const char *str1, const char *str2, size_t count)
Definition: odbc_utils.hpp:133
int strcmp(const char *str1, const char *str2)
Definition: odbc_utils.hpp:160
char * strncpy0(char *s1, const char *s2, size_t n)
Copy not more than "n" characters from string "s2" into "s1", and return the result,...
#define strdup
Definition: ncbi_ansi_ext.h:70
#define strlwr
#define strncasecmp
#define strcasecmp
#define verify(expr)
Definition: ncbi_assert.h:51
#define NCBI_DISP_VERSION
Definition: ncbi_comm.h:38
#define CONN_FWD_LINK
Definition: ncbi_comm.h:55
#define HTTP_CONNECTION_INFO
Definition: ncbi_comm.h:39
unsigned int ticket_t
Definition: ncbi_comm.h:66
#define NCBID_WEBPATH
Definition: ncbi_comm.h:37
int SERV_IsFirewallPort(unsigned short port)
SConnNetInfo * ConnNetInfo_CreateInternal(const char *service)
char * NcbiAddrToString(char *buf, size_t bufsize, const TNCBI_IPv6Addr *addr)
Convert an IPv6 address into either a full-quad text IPv4 (for IPv4-mapped IPv6 addresses) or a hex c...
Definition: ncbi_ipv6.c:490
int NcbiIsIPv4(const TNCBI_IPv6Addr *addr)
Return non-zero(true) if the address is a true IPv4 address (a mapped IPv4 address); return zero(fals...
Definition: ncbi_ipv6.c:89
EIPRangeType t
Definition: ncbi_localip.c:101
#define CORE_LOGF_X(subcode, level, fmt_args)
Definition: ncbi_priv.h:150
#define CORE_UNLOCK
Definition: ncbi_priv.h:273
#define CORE_LOCK_READ
Definition: ncbi_priv.h:271
const char * tag
const char * SERV_HostOfInfo(const SSERV_Info *info)
char * SERV_ServiceName(const char *service)
Definition: ncbi_service.c:186
int SERV_Update(SERV_ITER iter, const char *text, int code)
char * SERV_Print(SERV_ITER iter, const SConnNetInfo *net_info, int but_last)
const char * SERV_MapperName(SERV_ITER iter)
Definition: ncbi_service.c:943
static EIO_Status s_Close(CONNECTOR connector, const STimeout *timeout, int cleanup)
static void s_CloseDispatcher(SServiceConnector *uuu)
static const char kHttpHostTag[]
static EHTTP_HeaderParse s_ParseHeaderUCB(const char *header, void *data, int server_error)
static void s_Cleanup(SServiceConnector *uuu)
static const char * s_AdjustNetParams(const char *service, const char *svcname, SConnNetInfo *net_info, EReqMethod req_method, const char *cgi_path, const char *cgi_args, const char *args, const char *static_header, EMIME_Type mime_t, EMIME_SubType mime_s, EMIME_Encoding mime_e, const char *extend_header)
static SSERV_InfoCPtr s_GetNextInfo(SServiceConnector *uuu, int http)
static char * s_VT_Descr(CONNECTOR connector)
static EIO_Status s_VT_Status(CONNECTOR connector, EIO_Event direction)
static int s_IsContentTypeDefined(const char *service, const SConnNetInfo *net_info, EMIME_Type mime_t, EMIME_SubType mime_s, EMIME_Encoding mime_e)
static void x_SetDefaultReferer(SConnNetInfo *net_info, SERV_ITER iter)
static int s_Adjust(SConnNetInfo *net_info, void *data, unsigned int n)
static const char * s_VT_GetType(CONNECTOR connector)
static void s_Reset(SMetaConnector *meta, CONNECTOR connector)
static int x_SetHostPort(SConnNetInfo *net_info, const SSERV_Info *info)
static EIO_Status s_VT_Close(CONNECTOR connector, const STimeout *timeout)
static EIO_Status s_VT_Open(CONNECTOR connector, const STimeout *timeout)
struct SServiceConnectorTag SServiceConnector
static CONNECTOR s_SocketConnectorBuilder(SConnNetInfo *net_info, const char *hostport, EIO_Status *status, const void *data, size_t size, TSOCK_Flags flags)
static EHTTP_HeaderParse s_ParseHeader(const char *header, void *user_data, int server_error, int user_callback_enabled)
static void s_Setup(CONNECTOR connector)
static EHTTP_HeaderParse s_ParseHeaderNoUCB(const char *header, void *data, int server_error)
static char * x_HostPort(const char *host, unsigned short aport)
static CONNECTOR s_Open(SServiceConnector *uuu, const STimeout *timeout, SSERV_InfoCPtr info, SConnNetInfo *net_info, EIO_Status *status)
static int s_OpenDispatcher(SServiceConnector *uuu)
static void s_Destroy(CONNECTOR connector)
static void x_DestroyConnector(CONNECTOR c)
EIO_Status SOCK_CreateOnTopInternal(const void *handle, size_t handle_size, SOCK *sock, const SSOCK_Init *init, TSOCK_Flags flags)
Definition: ncbi_socket.c:6700
const char g_kNcbiSockNameAbbr[]
Definition: ncbi_socket.c:266
EIO_Status SOCK_CreateInternal(const char *host, unsigned short port, const STimeout *timeout, SOCK *sock, const SSOCK_Init *init, TSOCK_Flags flags)
Definition: ncbi_socket.c:6631
#define NCBI_CXX_TOOLKIT
Definition: ncbiconf_msvc.h:16
int isspace(Uchar c)
Definition: ncbictype.hpp:69
#define memmove(a, b, c)
#define assert(x)
Definition: srv_diag.hpp:58
Connector specification.
Standard set of connector methods to handle a connection (corresponding connectors are also in here),...
const char * name
Definition: ncbi_servicep.h:89
const SConnNetInfo * net_info
Timeout structure.
Definition: ncbi_types.h:76
Definition: type.c:6
void free(voidpf ptr)
voidp malloc(uInt size)
voidp calloc(uInt items, uInt size)
Modified on Wed May 01 14:21:35 2024 by modify_doxy.py rev. 669887