⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tcpio.c

📁 GNUnet是一个安全的点对点网络框架
💻 C
📖 第 1 页 / 共 2 页
字号:
/*     This file is part of GNUnet.     (C) 2001, 2002, 2006, 2008 Christian Grothoff (and other contributing authors)     GNUnet is free software; you can redistribute it and/or modify     it under the terms of the GNU General Public License as published     by the Free Software Foundation; either version 2, or (at your     option) any later version.     GNUnet is distributed in the hope that it will be useful, but     WITHOUT ANY WARRANTY; without even the implied warranty of     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     General Public License for more details.     You should have received a copy of the GNU General Public License     along with GNUnet; see the file COPYING.  If not, write to the     Free Software Foundation, Inc., 59 Temple Place - Suite 330,     Boston, MA 02111-1307, USA.*//** * @file util/network/tcpio.c * @brief code for synchronized access to TCP streams * @author Christian Grothoff * * Generic TCP code for reliable, mostly blocking, record-oriented TCP * connections. GNUnet uses the "tcpio" code for trusted client-server * (e.g. gnunet-gtk to gnunetd via loopback) communications.  Note * that an unblocking write is also provided since if both client and * server use blocking IO, both may block on a write and cause a * mutual inter-process deadlock. * * Since we do not want other peers (!) to be able to block a peer by * not reading from the TCP stream, the peer-to-peer TCP transport * uses unreliable, buffered, non-blocking, record-oriented TCP code * with a select call to reduce the number of threads which is * provided in transports/tcp.c. */#include "gnunet_util_network.h"#include "gnunet_util_os.h"#include "gnunet_util_config.h"#include "gnunet_protocols.h"#include "platform.h"#define DEBUG_TCPIO GNUNET_NO/** * Struct to refer to a GNUnet TCP connection. * This is more than just a socket because if the server * drops the connection, the client automatically tries * to reconnect (and for that needs connection information). */typedef struct GNUNET_ClientServerConnection{  /**   * the socket handle, NULL if not live   */  struct GNUNET_SocketHandle *sock;  struct GNUNET_Mutex *readlock;  struct GNUNET_Mutex *writelock;  struct GNUNET_Mutex *destroylock;  struct GNUNET_GE_Context *ectx;  struct GNUNET_GC_Configuration *cfg;  int dead;} ClientServerConnection;/** * Return the port-number (in host byte order) * @return 0 on error */static unsigned shortgetGNUnetPort (struct GNUNET_GE_Context *ectx,               struct GNUNET_GC_Configuration *cfg){  char *res;  char *pos;  unsigned int port;  res = NULL;  if (-1 == GNUNET_GC_get_configuration_value_string (cfg,                                                      "NETWORK",                                                      "HOST",                                                      "localhost:2087", &res))    {      GNUNET_GE_LOG (ectx,                     GNUNET_GE_ERROR | GNUNET_GE_USER | GNUNET_GE_BULK,                     _                     ("Could not find valid value for HOST in section NETWORK."));      return 2087;    }  pos = strstr (res, ":");  if (pos == NULL)    {      GNUNET_free (res);      return 2087;    }  pos++;  if (1 != SSCANF (pos, "%u", &port))    {      GNUNET_GE_LOG (ectx,                     GNUNET_GE_ERROR | GNUNET_GE_USER | GNUNET_GE_BULK,                     _                     ("Syntax error in configuration entry HOST in section NETWORK: `%s'"),                     pos);      GNUNET_free (res);      return 2087;    }  GNUNET_free (res);  return (unsigned short) port;}/** * Configuration: get the GNUnetd host where the client * should connect to (via TCP) * * @return the name of the host, NULL on error */static char *getGNUnetdHost (struct GNUNET_GE_Context *ectx,                struct GNUNET_GC_Configuration *cfg){  char *res;  char *pos;  res = NULL;  if (-1 == GNUNET_GC_get_configuration_value_string (cfg,                                                      "NETWORK",                                                      "HOST",                                                      "localhost:2087", &res))    {      GNUNET_GE_LOG (ectx,                     GNUNET_GE_ERROR | GNUNET_GE_USER | GNUNET_GE_BULK,                     _                     ("Could not find valid value for HOST in section NETWORK."));      return NULL;    }  pos = strstr (res, ":");  if (pos != NULL)    *pos = '\0';  return res;}struct GNUNET_ClientServerConnection *GNUNET_client_connection_create (struct GNUNET_GE_Context *ectx,                                 struct GNUNET_GC_Configuration *cfg){  ClientServerConnection *result;  result = GNUNET_malloc (sizeof (ClientServerConnection));  result->sock = NULL;  result->readlock = GNUNET_mutex_create (GNUNET_NO);  result->writelock = GNUNET_mutex_create (GNUNET_NO);  result->destroylock = GNUNET_mutex_create (GNUNET_YES);  result->ectx = ectx;  result->cfg = cfg;  return result;}voidGNUNET_client_connection_close_temporarily (struct                                            GNUNET_ClientServerConnection                                            *sock){  GNUNET_GE_ASSERT (NULL, sock != NULL);  GNUNET_mutex_lock (sock->destroylock);  if (sock->sock != NULL)    {      GNUNET_socket_close (sock->sock);      GNUNET_mutex_lock (sock->readlock);      GNUNET_mutex_lock (sock->writelock);      GNUNET_socket_destroy (sock->sock);      sock->sock = NULL;      GNUNET_mutex_unlock (sock->writelock);      GNUNET_mutex_unlock (sock->readlock);    }  GNUNET_mutex_unlock (sock->destroylock);}voidGNUNET_client_connection_close_forever (struct GNUNET_ClientServerConnection                                        *sock){  GNUNET_GE_ASSERT (NULL, sock != NULL);  GNUNET_mutex_lock (sock->destroylock);  if (sock->sock != NULL)    {      GNUNET_socket_close (sock->sock);      GNUNET_mutex_lock (sock->readlock);      GNUNET_mutex_lock (sock->writelock);      GNUNET_socket_destroy (sock->sock);      sock->sock = NULL;      sock->dead = GNUNET_YES;      GNUNET_mutex_unlock (sock->writelock);      GNUNET_mutex_unlock (sock->readlock);    }  else    {      sock->dead = GNUNET_YES;    }  GNUNET_mutex_unlock (sock->destroylock);}voidGNUNET_client_connection_destroy (struct GNUNET_ClientServerConnection *sock){  GNUNET_GE_ASSERT (NULL, sock != NULL);  GNUNET_client_connection_close_forever (sock);  GNUNET_mutex_destroy (sock->readlock);  GNUNET_mutex_destroy (sock->writelock);  GNUNET_mutex_destroy (sock->destroylock);  GNUNET_free (sock);}intGNUNET_client_connection_test_connected (struct GNUNET_ClientServerConnection                                         *sock){  return (sock->sock != NULL);}/** * Check a socket, open and connect if it is closed.  This code * supports IPv4 and IPv6 (and may try both).  It also waits a bounded * amount of time for the connection to succeed and may even retry the * same IP version a few times since gnunetd may just be starting or * out of sockets; hence this code could fail on first attempt, will * then wait a few milliseconds, retry and conceivably succeed.  Since * this is then done for multiple address families, the whole thing is * slightly more complicated then your ordinary connect call.  Not to * mention that the code also supports another thread coming in in the * middle and closing the socket for good -- or even opening it! */intGNUNET_client_connection_ensure_connected (struct                                           GNUNET_ClientServerConnection                                           *sock){  /* list of address families to try for connecting,     in order of preference */  static int addr_families[] = {#ifdef AF_UNSPEC    AF_UNSPEC,#endif#ifdef AF_INET6    AF_INET6,#endif    AF_INET,    -1  };  GNUNET_CronTime select_start;  struct sockaddr *soaddr;  socklen_t socklen;  fd_set rset;  fd_set wset;  fd_set eset;  struct timeval timeout;  int ret;  int osock;  unsigned short port;  char *host;  int af_index;  int soerr;  socklen_t soerrlen;  int tries;  GNUNET_GE_ASSERT (NULL, sock != NULL);  if (sock->sock != NULL)    return GNUNET_OK;  if (sock->dead == GNUNET_YES)    return GNUNET_SYSERR;  port = getGNUnetPort (sock->ectx, sock->cfg);  if (port == 0)    return GNUNET_SYSERR;  host = getGNUnetdHost (sock->ectx, sock->cfg);  if (host == NULL)    return GNUNET_SYSERR;  af_index = 0;  /* we immediately advance if there is a DNS lookup error   * (which would likely persist) or a socket API error   * (which would equally likely persist).  We retry a   * few times with a small delay if we may just be having   * a connection issue.   */#define TRIES_PER_AF 2#ifdef WINDOWS  #define DELAY_PER_RETRY (5000 * GNUNET_CRON_MILLISECONDS)#else  #define DELAY_PER_RETRY (50 * GNUNET_CRON_MILLISECONDS)#endif#define ADVANCE() do { af_index++; tries = TRIES_PER_AF; } while(0)#define RETRY() do { tries--; if (tries == 0) { ADVANCE(); } else { GNUNET_thread_sleep(DELAY_PER_RETRY); } } while (0)  tries = TRIES_PER_AF;  /* loop over all possible address families */  while (1)    {      if (addr_families[af_index] == -1)        {          GNUNET_GE_LOG (sock->ectx,                         GNUNET_GE_WARNING | GNUNET_GE_USER | GNUNET_GE_BULK,                         _("Error connecting to %s:%u. Is the daemon running?\n"), host, port);          return GNUNET_SYSERR;        }      soaddr = NULL;      socklen = 0;      if (GNUNET_SYSERR ==          GNUNET_get_ip_from_hostname (sock->ectx, host,                                       addr_families[af_index], &soaddr,                                       &socklen))        {          ADVANCE ();

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -