📄 ncbi_service_connector.c
字号:
/* * =========================================================================== * PRODUCTION $Log: ncbi_service_connector.c,v $ * PRODUCTION Revision 1000.0 2003/10/29 16:39:51 gouriano * PRODUCTION PRODUCTION: IMPORTED [ORIGINAL] Dev-tree R6.60 * PRODUCTION * =========================================================================== *//* $Id: ncbi_service_connector.c,v 1000.0 2003/10/29 16:39:51 gouriano Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE * National Center for Biotechnology Information * * This software/database is a "United States Government Work" under the * terms of the United States Copyright Act. It was written as part of * the author's official duties as a United States Government employee and * thus cannot be copyrighted. This software/database is freely available * to the public for use. The National Library of Medicine and the U.S. * Government have not placed any restriction on its use or reproduction. * * Although all reasonable efforts have been taken to ensure the accuracy * and reliability of the software and data, the NLM and the U.S. * Government do not and cannot warrant the performance or results that * may be obtained by using this software or data. The NLM and the U.S. * Government disclaim all warranties, express or implied, including * warranties of performance, merchantability or fitness for any particular * purpose. * * Please cite the author in any work or product based on this material. * * =========================================================================== * * Author: Anton Lavrentiev * * File Description: * Implementation of CONNECTOR to a named service * */#include "ncbi_ansi_ext.h"#include "ncbi_comm.h"#include "ncbi_priv.h"#include "ncbi_servicep.h"#include <connect/ncbi_http_connector.h>#include <connect/ncbi_service_connector.h>#include <connect/ncbi_socket_connector.h>#include <ctype.h>#include <stdio.h>#include <stdlib.h>typedef struct SServiceConnectorTag { const char* name; /* Verbal connector type */ const char* service; /* Service name (final) to use */ TSERV_Type types; /* Server types, record keeping only */ SConnNetInfo* net_info; /* Connection information */ const char* user_header; /* User header currently set */ SERV_ITER iter; /* Dispatcher information */ SMetaConnector meta; /* Low level comm.conn and its VT */ EIO_Status status; /* Status of last op */ unsigned int host; /* Parsed connection info... */ unsigned short port; ticket_t ticket; SSERVICE_Extra params; char args[1]; /* Additional CGI parameters */} SServiceConnector;/*********************************************************************** * INTERNAL -- "s_VT_*" functions for the "virt. table" of connector methods ***********************************************************************/#ifdef __cplusplusextern "C" {#endif /* __cplusplus */ static const char* s_VT_GetType (CONNECTOR connector); static EIO_Status s_VT_Open (CONNECTOR connector, const STimeout* timeout); static EIO_Status s_VT_Status (CONNECTOR connector, EIO_Event dir); static EIO_Status s_VT_Close (CONNECTOR connector, const STimeout* timeout); static void s_Setup (SMetaConnector* meta, CONNECTOR connector); static void s_Destroy (CONNECTOR connector);#ifdef __cplusplus} /* extern "C" */#endif /* __cplusplus */static char* s_GetArgs(const char* client_host){ static const char platform[] = "&platform="; static const char address[] = "address="; size_t nodelen, archlen, buflen; const char* arch; unsigned int ip; char addr[80]; char* p; buflen = 0; if (*client_host) { nodelen = strlen(client_host); buflen += sizeof(address) - 1 + nodelen; if (!strchr(client_host, '.') && (ip = SOCK_gethostbyname(client_host)) != 0 && SOCK_ntoa(ip, addr, sizeof(addr)) == 0) { buflen += strlen(addr) + 2; } else *addr = 0; } else nodelen = 0; if ((arch = CORE_GetPlatform()) != 0 && *arch) { archlen = strlen(arch); buflen += sizeof(platform) - 1 + archlen; } else archlen = 0; if (!buflen || !(p = (char*) malloc(buflen + 1))) return 0; buflen = 0; if (nodelen) { strcpy(&p[buflen], address); buflen += sizeof(address) - 1; strcpy(&p[buflen], client_host); buflen += nodelen; if (*addr) buflen += sprintf(&p[buflen], "(%s)", addr); } if (archlen) { strcpy(&p[buflen], nodelen ? platform : platform + 1); buflen += nodelen ? sizeof(platform) - 1 : sizeof(platform) - 2; strcpy(&p[buflen], arch); buflen += archlen; } return p;}static int/*bool*/ s_OpenDispatcher(SServiceConnector* uuu){ uuu->user_header = 0; if (!(uuu->iter = SERV_OpenEx(uuu->service, uuu->types, SERV_LOCALHOST, uuu->net_info, 0, 0))) return 0/*false*/; return 1/*true*/;}static void s_CloseDispatcher(SServiceConnector* uuu){ if (uuu->user_header) { free((void*) uuu->user_header); uuu->user_header = 0; } SERV_Close(uuu->iter); uuu->iter = 0;}/* Reset functions, which are implemented only in transport * connectors, but not in this connector. */static void s_Reset(SMetaConnector *meta){ CONN_SET_METHOD(meta, descr, 0, 0); CONN_SET_METHOD(meta, wait, 0, 0); CONN_SET_METHOD(meta, write, 0, 0); CONN_SET_METHOD(meta, flush, 0, 0); CONN_SET_METHOD(meta, read, 0, 0); CONN_SET_METHOD(meta, status, s_VT_Status, 0);#ifdef IMPLEMENTED__CONN_WaitAsync CONN_SET_METHOD(meta, wait_async, 0, 0);#endif}#ifdef __cplusplusextern "C" { static int s_ParseHeader(const char*, void*, int);}#endif /* __cplusplus */static int/*bool*/ s_ParseHeader(const char* header, void* data, int/*bool*/ server_error){ static const char kStateless[] = "TRY_STATELESS"; SServiceConnector* uuu = (SServiceConnector*) data; SERV_Update(uuu->iter, header); if (server_error) return 1/*parsed okay*/; while (header && *header) { if (strncasecmp(header, HTTP_CONNECTION_INFO, sizeof(HTTP_CONNECTION_INFO) - 1) == 0) { unsigned int i1, i2, i3, i4, ticket; unsigned char o1, o2, o3, o4; char ipaddr[32]; header += sizeof(HTTP_CONNECTION_INFO) - 1; while (*header && isspace((unsigned char)(*header))) header++; if (strncasecmp(header, kStateless, sizeof(kStateless) - 1) == 0) { /* Special keyword for switching into stateless mode */ uuu->host = (unsigned int)(-1);#if defined(_DEBUG) && !defined(NDEBUG) if (uuu->net_info->debug_printout) CORE_LOG(eLOG_Warning, "[SERVICE] Fallback to stateless requested");#endif break; } if (sscanf(header, "%u.%u.%u.%u %hu %x", &i1, &i2, &i3, &i4, &uuu->port, &ticket) < 6) return 0/*failed*/; o1 = i1; o2 = i2; o3 = i3; o4 = i4; sprintf(ipaddr, "%u.%u.%u.%u", o1, o2, o3, o4); uuu->host = SOCK_gethostbyname(ipaddr); uuu->ticket = SOCK_htonl(ticket); break; } if ((header = strchr(header, '\n')) != 0) header++; } return 1/*success*/;}static char* s_AdjustNetParams(SConnNetInfo* net_info, EReqMethod req_method, const char* cgi_name, const char* service, const char* args, const char* cgi_args, const char* static_header, EMIME_Type mime_t, EMIME_SubType mime_s, EMIME_Encoding mime_e, char* dynamic_header/*will be freed*/){ char content_type[MAX_CONTENT_TYPE_LEN], *retval; net_info->req_method = req_method; if (cgi_name) strncpy0(net_info->path, cgi_name, sizeof(net_info->path) - 1); if (cgi_args) strncpy0(net_info->args, cgi_args, sizeof(net_info->args) - 1); if (service) { ConnNetInfo_PrependArg(net_info, args, 0); if (!ConnNetInfo_PreOverrideArg(net_info, "service", service)) { const char* a = args ? strrchr(args, '&') : 0; if (!a) a = args; while (a) { ConnNetInfo_DeleteArg(net_info, a + (*a == '&' ? 1 : 0)); if (ConnNetInfo_PreOverrideArg(net_info, "service", service)) break; if (a != args) { while (a > args) { if (*--a == '&') break; } } else a = 0; } if (!a) { if (dynamic_header) free(dynamic_header); return 0/*failed*/; } } } if (mime_t == SERV_MIME_TYPE_UNDEFINED || mime_s == SERV_MIME_SUBTYPE_UNDEFINED || !MIME_ComposeContentTypeEx(mime_t, mime_s, mime_e, content_type, sizeof(content_type))) { *content_type = 0; } if ((retval = (char*) malloc((static_header ? strlen(static_header) : 0) + strlen(content_type) + 1/*EOL*/ + (dynamic_header? strlen(dynamic_header) : 0) )) != 0) { strcpy(retval, static_header ? static_header : ""); strcat(retval, content_type); strcat(retval, dynamic_header ? dynamic_header : ""); } if (dynamic_header) free(dynamic_header); return retval;}static const SSERV_Info* s_GetNextInfo(SServiceConnector* uuu){ if (uuu->params.get_next_info) return uuu->params.get_next_info(uuu->iter, uuu->params.data); else return SERV_GetNextInfo(uuu->iter);}/* Although all additional HTTP tags, which comprise dispatching, have * default values, which in most cases are fine with us, we will use * these tags explicitly to distinguish calls originated from within the * service connector from the calls from a Web browser, for example. * This technique allows the dispatcher to decide whether to use more * expensive dispatching (inlovling loopback connections) in case of browser. */#ifdef __cplusplusextern "C" { static int s_AdjustNetInfo(SConnNetInfo*, void*, unsigned int);}#endif /* __cplusplus *//* This callback is only for services called via direct HTTP */static int/*bool*/ s_AdjustNetInfo(SConnNetInfo* net_info, void* data, unsigned int n){ SServiceConnector* uuu = (SServiceConnector*) data; const char* user_header = 0; const SSERV_Info* info; assert(n != 0); /* paranoid assertion :-) */ if (net_info->firewall && !net_info->stateless) return 0; /*cannot adjust firewall stateful client*/ for (;;) { if (!(info = s_GetNextInfo(uuu))) return 0/*false - not adjusted*/; /* Skip any 'stateful_capable' entries here, which might * have left behind a failed stateful dispatching with a * fallback to stateless HTTP mode */ if (!info->sful) break; } {{ char* iter_header = SERV_Print(uuu->iter); switch (info->type) { case fSERV_Ncbid:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -