inetaddr.c
来自「GNet是一个简单的网络库。它是目标定向的」· C语言 代码 · 共 2,578 行 · 第 1/4 页
C
2,578 行
else { g_warning ("fork error: %s (%d)\n", g_strerror(errno), errno); return NULL; } }#endif /* Create a new InetAddr */ 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); /* Finish setting up state for callback */ g_assert (state); state->ia = ia; state->func = func; state->data = data;# ifdef HAVE_LIBPTHREAD { pthread_mutex_unlock (&state->mutex); }# endif return state;}#ifdef HAVE_LIBPTHREAD /* ********** UNIX Pthread ********** */static gboolean inetaddr_new_async_pthread_dispatch (gpointer data);/** * gnet_inetaddr_new_async_cancel: * @id: ID of the lookup * * Cancel an asynchronous GInetAddr creation that was started with * gnet_inetaddr_new_async(). * */voidgnet_inetaddr_new_async_cancel (GInetAddrNewAsyncID id){ GInetAddrAsyncState* state = (GInetAddrAsyncState*) id; g_return_if_fail (state); /* We don't use in_callback because we'd have to get the mutex to access it and if we're in the callback we'd already have the mutex and deadlock. in_callback was mostly meant to prevent programmer error. */ pthread_mutex_lock (&state->mutex); /* Check if the thread has finished and a reply is pending. If a reply is pending, cancel it and delete state. */ if (state->source) { g_source_remove (state->source); gnet_inetaddr_delete (state->ia); pthread_mutex_unlock (&state->mutex); pthread_mutex_destroy (&state->mutex); g_free (state); } /* Otherwise, the thread is still running. Set the cancelled flag and allow the thread to complete. When the thread completes, it will delete state. We can't kill the thread because we'd loose the resources allocated in gethostbyname_r. */ else { state->is_cancelled = TRUE; pthread_mutex_unlock (&state->mutex); }}static gbooleaninetaddr_new_async_pthread_dispatch (gpointer data){ GInetAddrAsyncState* state = (GInetAddrAsyncState*) data; pthread_mutex_lock (&state->mutex); /* Upcall */ if (!state->lookup_failed) (*state->func)(state->ia, GINETADDR_ASYNC_STATUS_OK, state->data); else (*state->func)(NULL, GINETADDR_ASYNC_STATUS_ERROR, state->data); /* Delete state */ g_source_remove (state->source); gnet_inetaddr_delete (state->ia); pthread_mutex_unlock (&state->mutex); pthread_mutex_destroy (&state->mutex); memset (state, 0, sizeof(*state)); g_free (state); return FALSE;}static void*inetaddr_new_async_pthread (void* arg){ void** args = (void**) arg; gchar* name = (gchar*) args[0]; GInetAddrAsyncState* state = (GInetAddrAsyncState*) args[1]; struct sockaddr_in sa; int rv; g_free (args); /* Do lookup */ rv = gnet_gethostbyname (name, &sa, NULL); g_free (name); /* Lock */ pthread_mutex_lock (&state->mutex); /* If cancelled, destroy state and exit. The main thread is no longer using state. */ if (state->is_cancelled) { gnet_inetaddr_delete (state->ia); pthread_mutex_unlock (&state->mutex); pthread_mutex_destroy (&state->mutex); g_free (state); return NULL; } /* Copy result */ if (rv) { struct sockaddr_in* sa_in; /* Copy address */ sa_in = (struct sockaddr_in*) &state->ia->sa; memcpy(&sa_in->sin_addr, &sa.sin_addr, 4); } else { /* Flag failure */ state->lookup_failed = TRUE; } /* Add a source for reply */ state->source = g_idle_add_full (G_PRIORITY_DEFAULT, inetaddr_new_async_pthread_dispatch, state, NULL); /* Unlock */ pthread_mutex_unlock (&state->mutex); /* Thread exits... */ return NULL;}#else /* ********** UNIX process ********** */gboolean gnet_inetaddr_new_async_cb (GIOChannel* iochannel, GIOCondition condition, gpointer data){ GInetAddrAsyncState* state = (GInetAddrAsyncState*) data; g_assert (!state->in_callback); /* Read from the pipe */ if (condition & G_IO_IN) { int rv; char* buf; int length; buf = &state->buffer[state->len]; length = sizeof(state->buffer) - state->len; if ((rv = read(state->fd, buf, length)) >= 0) { state->len += rv; /* Return true if there's more to read */ if ((state->len - 1) != state->buffer[0]) return TRUE; /* We're done reading. Copy into the addr if we were successful. */ if (state->len > 1) { struct sockaddr_in* sa_in; sa_in = (struct sockaddr_in*) &state->ia->sa; memcpy(&sa_in->sin_addr, &state->buffer[1], (state->len - 1)); } /* Otherwise, we got a 0 because there was an error */ else goto error; /* Call back */ state->in_callback = TRUE; (*state->func)(state->ia, GINETADDR_ASYNC_STATUS_OK, state->data); state->in_callback = FALSE; gnet_inetaddr_new_async_cancel (state); return FALSE; } /* otherwise, there was an error */ } /* otherwise, there was an error */ error: state->in_callback = TRUE; (*state->func)(NULL, GINETADDR_ASYNC_STATUS_ERROR, state->data); state->in_callback = FALSE; gnet_inetaddr_new_async_cancel(state); return FALSE;}voidgnet_inetaddr_new_async_cancel (GInetAddrNewAsyncID id){ GInetAddrAsyncState* state = (GInetAddrAsyncState*) id; g_return_if_fail (state); /* Ignore if in callback */ if (state->in_callback) return; gnet_inetaddr_delete (state->ia); g_source_remove (state->watch); g_io_channel_unref (state->iochannel); close (state->fd); kill (state->pid, SIGKILL); waitpid (state->pid, NULL, 0); memset (state, 0, sizeof(*state)); g_free (state);}#endif /* UNIX */#else /*********** Windows code ***********/GInetAddrNewAsyncIDgnet_inetaddr_new_async (const gchar* name, gint port, GInetAddrNewAsyncFunc func, gpointer data){ GInetAddr* ia; struct sockaddr_in* sa_in; GInetAddrAsyncState* state; g_return_val_if_fail(name != NULL, NULL); g_return_val_if_fail(func != NULL, NULL); /* Create a new InetAddr */ 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); /* Create a structure for the call back */ state = g_new0(GInetAddrAsyncState, 1); state->ia = ia; state->func = func; state->data = data; state->WSAhandle = (int) WSAAsyncGetHostByName(gnet_hWnd, IA_NEW_MSG, name, state->hostentBuffer, sizeof(state->hostentBuffer)); if (!state->WSAhandle) { g_free(state); return NULL; } /*get a lock and insert the state into the hash */ WaitForSingleObject(gnet_Mutex, INFINITE); g_hash_table_insert(gnet_hash, (gpointer)state->WSAhandle, (gpointer)state); ReleaseMutex(gnet_Mutex); return state;}gbooleangnet_inetaddr_new_async_cb (GIOChannel* iochannel, GIOCondition condition, gpointer data){ GInetAddrAsyncState* state = (GInetAddrAsyncState*) data; struct hostent *result; struct sockaddr_in *sa_in; if (state->errorcode) { state->in_callback = TRUE; (*state->func)(state->ia, GINETADDR_ASYNC_STATUS_ERROR, state->data); state->in_callback = FALSE; g_free(state); return FALSE; } result = (struct hostent*)state->hostentBuffer; sa_in = (struct sockaddr_in*) &state->ia->sa; memcpy(&sa_in->sin_addr, result->h_addr_list[0], result->h_length); state->ia->name = g_strdup(result->h_name); state->in_callback = TRUE; (*state->func)(state->ia, GINETADDR_ASYNC_STATUS_OK, state->data); state->in_callback = FALSE; g_free(state); return FALSE;}voidgnet_inetaddr_new_async_cancel(GInetAddrNewAsyncID id){ GInetAddrAsyncState* state = (GInetAddrAsyncState*) id; g_return_if_fail(state != NULL); if (state->in_callback) return; gnet_inetaddr_delete (state->ia); WSACancelAsyncRequest((HANDLE)state->WSAhandle); /*get a lock and remove the hash entry */ WaitForSingleObject(gnet_Mutex, INFINITE); g_hash_table_remove(gnet_hash, (gpointer)state->WSAhandle); ReleaseMutex(gnet_Mutex); g_free(state);}#endif /*********** End Windows code ***********//** * gnet_inetaddr_new_nonblock: * @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, but don't block * and fail if it would require blocking. This is, if the name is a * canonical name or "localhost", it returns the address. Otherwise, * it returns NULL. * * Returns: a new #GInetAddr, or NULL if there was a failure or it * would require blocking. * **/GInetAddr* gnet_inetaddr_new_nonblock (const gchar* name, gint port){ struct sockaddr_in* sa_in; struct in_addr inaddr; GInetAddr* ia = NULL; g_return_val_if_fail (name, NULL); /* Try to read the name as if were dotted decimal */ try_again: 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)); } /* If the name is localhost, change it to 127.0.0.1 and try again */ /* FIX: I don't think this is legal... */ else if (!strcmp (name, "localhost")) { name = "127.0.0.1"; goto try_again; } return ia;}/** * gnet_inetaddr_clone: * @ia: Address to clone * * Create an internet address from another one. * * Returns: a new InetAddr, or NULL if there was a failure. * **/GInetAddr* gnet_inetaddr_clone(const GInetAddr* ia){ GInetAddr* cia; g_return_val_if_fail (ia != NULL, NULL); cia = g_new0(GInetAddr, 1); cia->ref_count = 1; cia->sa = ia->sa; if (ia->name != NULL) cia->name = g_strdup(ia->name); return cia;}/** * gnet_inetaddr_delete: * @ia: GInetAddr to delete * * Delete a GInetAddr. * **/voidgnet_inetaddr_delete (GInetAddr* ia){ if (ia != NULL) gnet_inetaddr_unref(ia);}/** * gnet_inetaddr_ref * @ia: GInetAddr to reference * * Increment the reference counter of the GInetAddr. * **/voidgnet_inetaddr_ref (GInetAddr* ia){ g_return_if_fail(ia != NULL); ++ia->ref_count;}/** * gnet_inetaddr_unref * @ia: GInetAddr to unreference * * Remove a reference from the GInetAddr. When reference count * reaches 0, the address is deleted. * **/voidgnet_inetaddr_unref (GInetAddr* ia){ g_return_if_fail(ia != NULL); --ia->ref_count; if (ia->ref_count == 0) { if (ia->name != NULL) g_free (ia->name); g_free (ia); }}/** * gnet_inetaddr_get_name: * @ia: Address to get the name of. * * Get the nice name of the address (eg, "mofo.eecs.umich.edu"). The * "nice name" is the domain name if it has one or the canonical name * if it does not. Be warned that this call may block since it may * need to do a reverse DNS lookup. * * Returns: the nice name of the host, or NULL if there was an error. * The caller is responsible for deleting the returned string. * **/gchar* gnet_inetaddr_get_name (/* const */ GInetAddr* ia){ g_return_val_if_fail (ia != NULL, NULL); if (ia->name == NULL) { gchar* name; if ((name = gnet_gethostbyaddr((char*) &((struct sockaddr_in*)&ia->sa)->sin_addr, sizeof(struct in_addr), AF_INET)) != NULL) ia->name = name; else ia->name = gnet_inetaddr_get_canonical_name(ia); } g_assert (ia->name != NULL); return g_strdup(ia->name);}/** * gnet_inetaddr_get_name_nonblock: * @ia: Address to get the name of. * * Get the nice name of the address, but don't block and fail if it * would require blocking. * * Returns: the nice name of the host, or NULL if there was an error * or it would require blocking. The caller is responsible for * deleting the returned string. * **/gchar* gnet_inetaddr_get_name_nonblock (GInetAddr* ia){ if (ia->name) return g_strdup(ia->name); return NULL;}#ifndef GNET_WIN32 /*********** Unix code ***********/#ifdef HAVE_LIBPTHREADstatic void* inetaddr_get_name_async_pthread (void* arg);#endif/** * gnet_inetaddr_get_name_async: * @ia: Address to get the name of. * @func: Callback function. * @data: User data passed when callback function is called. * * Get the nice name of the address (eg, "mofo.eecs.umich.edu"). * This function will use the callback once it knows the nice name. * The callback will not be called during the call to * gnet_inetaddr_new_async(). * * The Unix uses either pthreads or fork(). See the notes for * gnet_inetaddr_new_async(). * * FIX: In the next big version, this should copy ia. * * Returns: ID of the lookup which can be used with * gnet_inetaddrr_get_name_async_cancel() to cancel it; NULL on * failure. * **/GInetAddrGetNameAsyncIDgnet_inetaddr_get_name_async (GInetAddr* ia, GInetAddrGetNameAsyncFunc func, gpointer data){ GInetAddrReverseAsyncState* state = NULL; g_return_val_if_fail(ia != 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(GInetAddrReverseAsyncState, 1); args = g_new (void*, 2); args[0] = (void*) gnet_inetaddr_clone(ia); 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_get_name_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); gnet_inetaddr_delete ((GInetAddr*) args[0]); g_free (state); return NULL; } pthread_attr_destroy (&attr); }# else /* Fork */ { int pipes[2]; pid_t pid = -1; /* Open a pipe */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?