inetaddr.c

来自「GNet是一个简单的网络库。它是目标定向的」· C语言 代码 · 共 2,578 行 · 第 1/4 页

C
2,578
字号
/* GNet - Networking library * Copyright (C) 2000  David Helder * Copyright (C) 2000  Andrew Lanoix * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA  02111-1307, USA. */#include "gnet-private.h"#include "inetaddr.h"#ifdef HAVE_LIBPTHREAD#include <pthread.h>#endif/* **************************************** */static gboolean gnet_gethostbyname(const char* hostname, struct sockaddr_in* sa, gchar** nicename);static gchar* gnet_gethostbyaddr(const char* addr, size_t length, int type);/* Testing stuff *//*  #undef   HAVE_GETHOSTBYNAME_R_GLIBC *//*  #define  HAVE_GETHOSTBYNAME_R_GLIB_MUTEX *//* TODO: Move this to an init function */#ifdef HAVE_GETHOSTBYNAME_R_GLIB_MUTEX#  ifndef G_THREADS_ENABLED#    error Using GLib Mutex but thread are not enabled.#  endifG_LOCK_DEFINE (gethostbyname);#endif/* Thread safe gethostbyname.  The only valid fields are sin_len,   sin_family, and sin_addr.  Nice name */gbooleangnet_gethostbyname(const char* hostname, struct sockaddr_in* sa, gchar** nicename){  gboolean rv = FALSE;#ifndef GNET_WIN32  struct in_addr inaddr;  /* Attempt non-blocking lookup */  if (inet_aton(hostname, &inaddr) != 0)    {      sa->sin_family = AF_INET;      memcpy(&sa->sin_addr, (char*) &inaddr, sizeof(struct in_addr));      if (nicename)	*nicename = g_strdup (hostname);      return TRUE;    }#endif#ifdef HAVE_GETHOSTBYNAME_THREADSAFE  {    struct hostent* he;    he = gethostbyname(hostname);    if (he != NULL && he->h_addr_list[0] != NULL)      {	if (sa)	  {	    sa->sin_family = he->h_addrtype;	    memcpy(&sa->sin_addr, he->h_addr_list[0], he->h_length);	  }	if (nicename && he->h_name)	  *nicename = g_strdup(he->h_name);	rv = TRUE;      }  }#else#ifdef HAVE_GETHOSTBYNAME_R_GLIBC  {    struct hostent result_buf, *result;    size_t len;    char* buf;    int herr;    int res;    len = 1024;    buf = g_new(gchar, len);    while ((res = gethostbyname_r (hostname, &result_buf, buf, len, &result, &herr)) 	   == ERANGE)      {	len *= 2;	buf = g_renew (gchar, buf, len);      }    if (res || result == NULL || result->h_addr_list[0] == NULL)      goto done;    if (sa)      {	sa->sin_family = result->h_addrtype;	memcpy(&sa->sin_addr, result->h_addr_list[0], result->h_length);      }    if (nicename && result->h_name)      *nicename = g_strdup(result->h_name);    rv = TRUE;  done:    g_free(buf);  }#else#ifdef HAVE_GET_HOSTBYNAME_R_SOLARIS  {    struct hostent result;    size_t len;    char* buf;    int herr;    int res;    len = 1024;    buf = g_new(gchar, len);    while ((res = gethostbyname_r (hostname, &result, buf, len, &herr)) == ERANGE)      {	len *= 2;	buf = g_renew (gchar, buf, len);      }    if (res || hp == NULL || hp->h_addr_list[0] == NULL)      goto done;    if (sa)      {	sa->sin_family = result->h_addrtype;	memcpy(&sa->sin_addr, result->h_addr_list[0], result->h_length);      }    if (nicename && result->h_name)      *nicename = g_strdup(result->h_name);    rv = TRUE;  done:    g_free(buf);  }#else#ifdef HAVE_GETHOSTBYNAME_R_HPUX  {    struct hostent result;    struct hostent_data buf;    int res;    res = gethostbyname_r (hostname, &result, &buf);    if (res == 0)      {	if (sa)	  {	    sa->sin_family = result.h_addrtype;	    memcpy(&sa->sin_addr, result.h_addr_list[0], result.h_length);	  }		if (nicename && result.h_name)	  *nicename = g_strdup(result.h_name);	rv = TRUE;      }  }#else #ifdef HAVE_GETHOSTBYNAME_R_GLIB_MUTEX  {    struct hostent* he;    if (!g_threads_got_initialized)      g_thread_init (NULL);    G_LOCK (gethostbyname);    he = gethostbyname(hostname);    if (he != NULL && he->h_addr_list[0] != NULL)      {	if (sa)	  {	    sa->sin_family = he->h_addrtype;	    memcpy(&sa->sin_addr, he->h_addr_list[0], he->h_length);	  }	if (nicename && he->h_name)	  *nicename = g_strdup(he->h_name);	rv = TRUE;      }    G_UNLOCK (gethostbyname);  }#else#ifdef GNET_WIN32  {    struct hostent *result;    WaitForSingleObject(gnet_hostent_Mutex, INFINITE);    result = gethostbyname(hostname);    if (result != NULL)      {	if (sa)	  {	    sa->sin_family = result->h_addrtype;	    memcpy(&sa->sin_addr, result->h_addr_list[0], result->h_length);	  }		if (nicename && result->h_name)	  *nicename = g_strdup(result->h_name);	ReleaseMutex(gnet_hostent_Mutex);	rv = TRUE;         }  }#else  {    struct hostent* he;    he = gethostbyname(hostname);    if (he != NULL && he->h_addr_list[0] != NULL)      {	if (sa)	  {	    sa->sin_family = he->h_addrtype;	    memcpy(&sa->sin_addr, he->h_addr_list[0], he->h_length);	  }	if (nicename && he->h_name)	  *nicename = g_strdup(he->h_name);	rv = TRUE;      }  }#endif#endif#endif#endif#endif#endif  return rv;}/*    Thread safe gethostbyaddr (we assume that gethostbyaddr_r follows   the same pattern as gethostbyname_r, so we don't have special   checks for it in configure.in.   Returns: the hostname, NULL if there was an error.*/gchar*gnet_gethostbyaddr(const char* addr, size_t length, int type){  gchar* rv = NULL;#ifdef HAVE_GETHOSTBYNAME_THREADSAFE  {    struct hostent* he;    he = gethostbyaddr(addr, length, type);    if (he != NULL && he->h_name != NULL)      rv = g_strdup(he->h_name);  }#else#ifdef HAVE_GETHOSTBYNAME_R_GLIBC  {    struct hostent result_buf, *result;    size_t len;    char* buf;    int herr;    int res;    len = 1024;    buf = g_new(gchar, len);    while ((res = gethostbyaddr_r (addr, length, type, &result_buf, buf, len, &result, &herr)) 	   == ERANGE)      {	len *= 2;	buf = g_renew (gchar, buf, len);      }    if (res || result == NULL || result->h_name == NULL)      goto done;    rv = g_strdup(result->h_name);  done:    g_free(buf);  }#else#ifdef HAVE_GET_HOSTBYNAME_R_SOLARIS  {    struct hostent result;    size_t len;    char* buf;    int herr;    int res;    len = 1024;    buf = g_new(gchar, len);    while ((res = gethostbyaddr_r (addr, lenght, type, &result, buf, len, &herr)) == ERANGE)      {	len *= 2;	buf = g_renew (gchar, buf, len);      }    if (res || hp == NULL || hp->h_name == NULL)      goto done;    rv = g_strdup(result->h_name);  done:    g_free(buf);  }#else#ifdef HAVE_GETHOSTBYNAME_R_HPUX  {    struct hostent result;    struct hostent_data buf;    int res;    res = gethostbyaddr_r (addr, length, type, &result, &buf);    if (res == 0)      rv = g_strdup (result.h_name);  }#else #ifdef HAVE_GETHOSTBYNAME_R_GLIB_MUTEX  {    struct hostent* he;    if (!g_threads_got_initialized)      g_thread_init (NULL);    G_LOCK (gethostbyname);    he = gethostbyaddr(addr, length, type);    if (he != NULL && he->h_name != NULL)      rv = g_strdup(he->h_name);    G_UNLOCK (gethostbyname);  }#else#ifdef GNET_WIN32  {    struct hostent* he;    WaitForSingleObject(gnet_hostent_Mutex, INFINITE);    he = gethostbyaddr(addr, length, type);    if (he != NULL && he->h_name != NULL)      rv = g_strdup(he->h_name);    ReleaseMutex(gnet_hostent_Mutex);  }#else  {    struct hostent* he;    he = gethostbyaddr(addr, length, type);    if (he != NULL && he->h_name != NULL)      rv = g_strdup(he->h_name);  }#endif#endif#endif#endif#endif#endif  return rv;}#ifdef GNET_WIN32/* TODO: Use Window's inet_aton if they ever implement it. */static intinet_aton(const char *cp, struct in_addr *inp){  inp->s_addr = inet_addr(cp);  if (inp->s_addr == INADDR_NONE && strcmp (cp, "255.255.255.255"))    return 0;  return 1;}#endif /* GNET_WIN32 *//* **************************************** *//* TO IMPLEMENT?:			    *//*** * * Create an internet address from raw bytes. * **//*  InetAddr* inetaddr_bytes_new(const guint8* addr, const gint length); *//* **************************************** *//** *  gnet_inetaddr_new: *  @name: a nice name (eg, mofo.eecs.umich.edu) or a dotted decimal name *    (eg, 141.213.8.59).  You can delete the after the function is called. *  @port: port number (0 if the port doesn't matter) *  *  Create an internet address from a name and port.  This function *  may block. * *  Returns: a new #GInetAddr, or NULL if there was a failure. * **/GInetAddr* gnet_inetaddr_new (const gchar* name, gint port){  struct sockaddr_in* sa_in;  struct in_addr inaddr;  GInetAddr* ia = NULL;  g_return_val_if_fail(name != NULL, NULL);  /* Try to read the name as if were dotted decimal */  if (inet_aton(name, &inaddr) != 0)    {      ia = g_new0(GInetAddr, 1);      ia->ref_count = 1;      sa_in = (struct sockaddr_in*) &ia->sa;      sa_in->sin_family = AF_INET;      sa_in->sin_port = g_htons(port);      memcpy(&sa_in->sin_addr, (char*) &inaddr, sizeof(struct in_addr));    }  else    {      struct sockaddr_in sa;      /* Try to get the host by name (ie, DNS) */      if (gnet_gethostbyname(name, &sa, NULL))	{	  ia = g_new0(GInetAddr, 1);	  ia->name = g_strdup(name);	  ia->ref_count = 1;	  	  sa_in = (struct sockaddr_in*) &ia->sa;	  sa_in->sin_family = AF_INET;	  sa_in->sin_port = g_htons(port);	  memcpy(&sa_in->sin_addr, &sa.sin_addr, 4);	}    }  return ia;}#ifndef GNET_WIN32  /*********** Unix code ***********/#ifdef HAVE_LIBPTHREADstatic void* inetaddr_new_async_pthread (void* arg);#endif/** *  gnet_inetaddr_new_async: *  @name: a nice name (eg, mofo.eecs.umich.edu) or a dotted decimal name *    (eg, 141.213.8.59).  You can delete the after the function is called. *  @port: port number (0 if the port doesn't matter) *  @func: Callback function. *  @data: User data passed when callback function is called. *  *  Create a GInetAddr from a name and port asynchronously.  The *  callback is called once the structure is created or an error *  occurs during lookup.  The callback will not be called during the *  call to gnet_inetaddr_new_async(). * *  The Unix version creates a pthread thread which does the lookup. *  If pthreads aren't available, it forks and does the lookup. *  Forking will be slow or even fail when using operating systems *  that copy the entire process when forking.   * *  If you need to lookup hundreds of addresses, we recommend calling *  g_main_iteration(FALSE) between calls.  This will help prevent an *  explosion of threads or processes. * *  If you need a more robust library for Unix, look at <ulink *  url="http://www.gnu.org/software/adns/adns.html">GNU ADNS</ulink>. *  GNU ADNS is under the GNU GPL.  This library does not use threads *  or processes. * *  The Windows version should work fine.  Windows has an asynchronous *  DNS lookup function. * *  Returns: ID of the lookup which can be used with *  gnet_inetaddr_new_async_cancel() to cancel it; NULL on failure. * **/GInetAddrNewAsyncIDgnet_inetaddr_new_async (const gchar* name, gint port, 			 GInetAddrNewAsyncFunc func, gpointer data){  GInetAddr* ia;  struct sockaddr_in* sa_in;  GInetAddrAsyncState* state = NULL;  g_return_val_if_fail(name != NULL, NULL);  g_return_val_if_fail(func != NULL, NULL);# ifdef HAVE_LIBPTHREAD			/* Pthread */  {    void** args;    pthread_attr_t attr;    pthread_t pthread;    int rv;    state = g_new0(GInetAddrAsyncState, 1);    args = g_new (void*, 2);    args[0] = (void*) g_strdup(name);    args[1] = state;    pthread_mutex_init (&state->mutex, NULL);    pthread_mutex_lock (&state->mutex);    pthread_attr_init (&attr);    pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);  create_again:    rv = pthread_create (&pthread, &attr, inetaddr_new_async_pthread, args);    if (rv == EAGAIN)      {	sleep(0);	/* Yield the processor */	goto create_again;      }    else if (rv)      {	g_warning ("pthread_create error: %s (%d)\n", g_strerror(rv), rv);	pthread_mutex_unlock (&state->mutex);	pthread_mutex_destroy (&state->mutex);	pthread_attr_destroy (&attr);	g_free (args[0]);	g_free (state);	return NULL;      }    pthread_attr_destroy (&attr);  }# else 					/* Fork */  {    int pipes[2];    pid_t pid = -1;    /* Open a pipe */    if (pipe(pipes) == -1)      return NULL;    /* Fork to do the look up. */  fork_again:    errno = 0;    /* Child: Do lookup, write result to pipe */    if ((pid = fork()) == 0)      {	int outfd = pipes[1];	struct sockaddr_in sa;	close (pipes[0]);	/* Try to get the host by name (ie, DNS) */	if (gnet_gethostbyname(name, &sa, NULL))	  {	    guchar size = 4;	/* FIX for IPv6 */      	    if ( (write(outfd, &size, sizeof(guchar)) != sizeof(guchar)) ||		 (write(outfd, &sa.sin_addr, size) != size) )	      g_warning ("Error writing to pipe: %s\n", g_strerror(errno));	  }	else	  {	    /* Write a zero */	    guchar zero = 0;	    	    if (write(outfd, &zero, sizeof(zero)) != sizeof(zero))	      g_warning ("Error writing to pipe: %s\n", g_strerror(errno));	  }	/* Exit (we don't want atexit called, so do _exit instead) */	_exit(EXIT_SUCCESS);      }    /* Parent: Set up state */    else if (pid > 0)      {	close (pipes[1]);	state = g_new0(GInetAddrAsyncState, 1);	state->pid = pid;	state->fd = pipes[0];	state->iochannel = gnet_private_iochannel_new(pipes[0]);	state->watch = g_io_add_watch(state->iochannel,				      (G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL),				      gnet_inetaddr_new_async_cb, 				      state);      }    /* Try again */    else if (errno == EAGAIN)      {	sleep(0);	/* Yield the processor */	goto fork_again;      }    /* Else fork failed completely */

⌨️ 快捷键说明

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