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 + -
显示快捷键?