conn.c
来自「GNet是一个简单的网络库。它是目标定向的」· C语言 代码 · 共 628 行
C
628 行
/* GNet - Networking library * Copyright (C) 2000 David Helder * * 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 "conn.h"#include <stdio.h>#include <memory.h> /* required for windows */typedef struct _QueuedWrite{ gchar* buffer; gint length; gint timeout;} QueuedWrite;static void conn_check_queued_writes (GConn* conn);static void conn_connect_cb (GTcpSocket* socket, GInetAddr* ia, GTcpSocketConnectAsyncStatus status, gpointer user_data);static void conn_new_cb (GTcpSocket* socket, GTcpSocketNewAsyncStatus status, gpointer user_data);static void conn_write_cb (GIOChannel* iochannel, gchar* buffer, guint length, guint bytes_writen, GNetIOChannelWriteAsyncStatus status, gpointer user_data);static gboolean conn_read_cb (GIOChannel* iochannel, GNetIOChannelReadAsyncStatus status, gchar* buffer, guint length, gpointer user_data);static gboolean conn_timeout_cb (gpointer data);/** * gnet_conn_new * @hostname: Hostname of host * @port: Port of host * @func: Function to call on connection, I/O, or error * @user_data: Data to pass to func * * Create a connection object representing a connection to a host. * The actual connection is not made until gnet_conn_connect() is * called. The callback is called when events occur. The events are * connect, read, write, error, and timeout. These only occur if the * appropriate function is called first. For example, use * gnet_conn_read() to have the callback called when data is read. * * Returns: A #GConn. * **/GConn*gnet_conn_new (const gchar* hostname, gint port, GConnFunc func, gpointer user_data){ GConn* conn; g_return_val_if_fail (hostname, NULL); conn = g_new0 (GConn, 1); conn->ref_count = 1; conn->hostname = g_strdup(hostname); conn->port = port; conn->inetaddr = gnet_inetaddr_new_nonblock (hostname, port); conn->func = func; conn->user_data = user_data; return conn;}/** * gnet_conn_new_inetaddr * @inetaddr: address of host * @func: Function to call on connection, I/O, or error * @user_data: Data to pass to func * * Create a connection object representing a connection to a host. * This function is similar to gnet_conn_new() but has different * arguments. * * Returns: A #GConn. * **/GConn* gnet_conn_new_inetaddr (const GInetAddr* inetaddr, GConnFunc func, gpointer user_data){ GConn* conn; g_return_val_if_fail (inetaddr, NULL); conn = g_new0 (GConn, 1); conn->ref_count = 1; conn->hostname = gnet_inetaddr_get_canonical_name (inetaddr); conn->port = gnet_inetaddr_get_port (inetaddr); conn->inetaddr = gnet_inetaddr_clone (inetaddr); conn->func = func; conn->user_data = user_data; return conn;}/** * gnet_conn_delete * @conn: Connection to delete * @delete_buffers: True if write buffers should be deleted. * * Delete the connection. If delete_buffers is set, any write * buffers are deleted. * **/voidgnet_conn_delete (GConn* conn, gboolean delete_buffers){ if (conn) { gnet_conn_disconnect (conn, delete_buffers); if (conn->inetaddr) gnet_inetaddr_delete (conn->inetaddr); g_free (conn->hostname); if (conn->timer) g_source_remove (conn->timer); memset (conn, 0, sizeof(*conn)); g_free (conn); }}/** * gnet_conn_ref * @conn: #GConn to reference * * Increment the reference counter of the GConn. * **/voidgnet_conn_ref (GConn* conn){ g_return_if_fail (conn); ++conn->ref_count;}/** * gnet_conn_unref * @conn: #GConn to unreference * * Remove a reference from the #GConn. When reference count reaches * 0, the connection is deleted. * **/voidgnet_conn_unref (GConn* conn, gboolean delete_buffers){ g_return_if_fail (conn); --conn->ref_count; if (conn->ref_count == 0) gnet_conn_delete (conn, delete_buffers);}/** * gnet_conn_connect * @conn: Conn to connect to * @timeout: Timeout for connection. * * Establish the connection. If the connection is pending or already * established, this function does nothing. The callback is called * when the connection is established or an error occurs. THE * TIMEOUT IS NOT CURRENTLY USED (FIX). * **/voidgnet_conn_connect (GConn* conn, guint timeout){ g_return_if_fail (conn); g_return_if_fail (conn->func); if (conn->connect_id || conn->new_id || conn->socket) return; if (conn->inetaddr) conn->new_id = gnet_tcp_socket_new_async (conn->inetaddr, conn_new_cb, conn); else if (conn->hostname) conn->connect_id = gnet_tcp_socket_connect_async (conn->hostname, conn->port, conn_connect_cb, conn); else g_return_if_fail (FALSE); /* FIX: Use the timeout! */}static voidconn_connect_cb (GTcpSocket* socket, GInetAddr* ia, GTcpSocketConnectAsyncStatus status, gpointer user_data){ GConn* conn = (GConn*) user_data; GConnStatus st = GNET_CONN_STATUS_ERROR; g_return_if_fail (conn); conn->connect_id = NULL; if (status == GTCP_SOCKET_CONNECT_ASYNC_STATUS_OK) { conn->socket = socket; conn->inetaddr = ia; conn->iochannel = gnet_tcp_socket_get_iochannel (socket); st = GNET_CONN_STATUS_CONNECT; conn_check_queued_writes (conn); } (conn->func)(conn, st, NULL, 0, conn->user_data);}static voidconn_new_cb (GTcpSocket* socket, GTcpSocketNewAsyncStatus status, gpointer user_data){ GConn* conn = (GConn*) user_data; GConnStatus st = GNET_CONN_STATUS_ERROR; g_return_if_fail (conn); conn->new_id = NULL; if (status == GTCP_SOCKET_NEW_ASYNC_STATUS_OK) { conn->socket = socket; conn->iochannel = gnet_tcp_socket_get_iochannel (socket); st = GNET_CONN_STATUS_CONNECT; conn_check_queued_writes (conn); } (conn->func)(conn, st, NULL, 0, conn->user_data);}/** * gnet_conn_disconnect * @conn: Conn to disconnect * @delete_buffers: True if write buffers should be deleted. * * End the connection. The connection can later be reestablished by * calling gnet_conn_connect() again. If there the connection was * not establish, this function does nothing. If delete_buffers is * set, any write buffers are deleted. * **/voidgnet_conn_disconnect (GConn* conn, gboolean delete_buffers){ GList* i; g_return_if_fail (conn); if (conn->connect_id) { gnet_tcp_socket_connect_async_cancel (conn->connect_id); conn->connect_id = NULL; } if (conn->new_id) { gnet_tcp_socket_new_async_cancel (conn->new_id); conn->new_id = NULL; } for (i = conn->queued_writes; i != NULL; i = i->next) { QueuedWrite* queued_write = i->data; if (delete_buffers) g_free (queued_write->buffer); g_free (queued_write); } g_list_free (conn->queued_writes); conn->queued_writes = NULL; if (conn->write_id) { gnet_io_channel_write_async_cancel (conn->write_id, delete_buffers); conn->write_id = NULL; } if (conn->read_id) { gnet_io_channel_read_async_cancel (conn->read_id); conn->read_id = NULL; } if (conn->iochannel) { g_io_channel_unref (conn->iochannel); conn->iochannel = NULL; } if (conn->socket) { gnet_tcp_socket_delete (conn->socket); conn->socket = NULL; }}/** * gnet_conn_is_connected * @conn: Connection to check * * Check if the connection is established. * * Returns: TRUE if the connection is established, FALSE otherwise. * **/gbooleangnet_conn_is_connected (const GConn* conn){ g_return_val_if_fail (conn, FALSE); return (conn->socket != NULL);}/** * gnet_conn_read: * @conn: Connection to read from * @buffer: Buffer to read to (NULL if to be allocated) * @length: Length of the buffer (maximum size if buffer is to be allocated) * @read_one_byte_at_a_time: TRUE if bytes should be read one-at-a-time * @timeout: Timeout for read (0 if no timeout) * @check_func: Function to check if read is complete * @check_user_data: User data for check_func * * Set up an asynchronous read from the connection to the buffer. * This is a wrapper around gnet_io_channel_read_async(), which reads * data until the check function stops it. The callback for this * #GConn is called when the read is complete or there is an error. * **/voidgnet_conn_read (GConn* conn, gchar* buffer, guint length, guint timeout, gboolean read_one_byte_at_a_time, GNetIOChannelReadAsyncCheckFunc check_func, gpointer check_user_data){ g_return_if_fail (conn); g_return_if_fail (conn->iochannel); g_return_if_fail (conn->func); g_return_if_fail (!conn->read_id); conn->read_id = gnet_io_channel_read_async (conn->iochannel, buffer, length, timeout, read_one_byte_at_a_time, check_func, check_user_data, conn_read_cb, conn);}/** * gnet_conn_readany: * @conn: Connection to read from * @buffer: Buffer to read to (NULL if to be allocated) * @length: Length of the buffer (maximum size if buffer is to be allocated) * @timeout: Timeout for read (0 if not timeout) * * Set up an asynchronous read from the connection to the buffer. * This is a wrapper around gnet_io_channel_readany(), which will * read any amount of data. * **/voidgnet_conn_readany (GConn* conn, gchar* buffer, guint length, guint timeout){ g_return_if_fail (conn); g_return_if_fail (buffer); g_return_if_fail (conn->func); g_return_if_fail (conn->iochannel); g_return_if_fail (!conn->read_id); conn->read_id = gnet_io_channel_readany_async(conn->iochannel, buffer, length, timeout, conn_read_cb, conn);}/** * gnet_conn_readline: * @conn: Connection to read from * @buffer: Buffer to read to (NULL if to be allocated) * @length: Length of the buffer (maximum size if buffer is to be allocated) * @timeout: Timeout for read (0 if not timeout) * * Set up an asynchronous read from the connection to the buffer. * This is a wrapper around gnet_io_channel_readline(), which will * read data until a newline. * **/voidgnet_conn_readline (GConn* conn, gchar* buffer, guint length, guint timeout){ g_return_if_fail (conn); g_return_if_fail (conn->func); g_return_if_fail (conn->iochannel); g_return_if_fail (!conn->read_id); conn->read_id = gnet_io_channel_readline_async(conn->iochannel, buffer, length, timeout, conn_read_cb, conn);}static gbooleanconn_read_cb (GIOChannel* iochannel, GNetIOChannelReadAsyncStatus status, gchar* buffer, guint length, gpointer user_data){ GConn* conn = (GConn*) user_data; gpointer read_id; g_return_val_if_fail (conn, FALSE); g_return_val_if_fail (conn->func, FALSE); /* If the upper level calls disconnect, we don't want it to delete the read_id. */ read_id = conn->read_id; conn->read_id = NULL; if (status == GNET_IOCHANNEL_READ_ASYNC_STATUS_OK) { if (length) { gboolean rv; rv = (conn->func)(conn, GNET_CONN_STATUS_READ, buffer, length, conn->user_data); if (rv) conn->read_id = read_id; return rv; } else { /* read_id is invalid */ (conn->func)(conn, GNET_CONN_STATUS_CLOSE, NULL, 0, conn->user_data); } } else { /* read_id is invalid */ (conn->func)(conn, GNET_CONN_STATUS_ERROR, NULL, 0, conn->user_data); } return FALSE;}/** * gnet_conn_write * @conn: Connection to write to * @buffer: Buffer to write * @length: Length of buffer * @timeout: Timeout for write (0 if no timeout) * * Set up an asynchronous write to the connection from the buffer. * This is a wrapper around gnet_io_channel_write_async(). This * function may be called again before another asynchronous write * completes. * **/voidgnet_conn_write (GConn* conn, gchar* buffer, gint length, guint timeout){ g_return_if_fail (conn); g_return_if_fail (conn->func); if (conn->iochannel && !conn->write_id) { conn->write_id = gnet_io_channel_write_async (conn->iochannel, buffer, length, timeout, conn_write_cb, conn); } else { QueuedWrite* queued_write; queued_write = g_new0 (QueuedWrite, 1); queued_write->buffer = buffer; queued_write->length = length; queued_write->timeout = timeout; conn->queued_writes = g_list_append (conn->queued_writes, queued_write); }}static voidconn_write_cb (GIOChannel* iochannel, gchar* buffer, guint length, guint bytes_writen, GNetIOChannelWriteAsyncStatus status, gpointer user_data){ GConn* conn = (GConn*) user_data; g_return_if_fail (conn); conn->write_id = NULL; /* write id is invalid */ if (status == GNET_IOCHANNEL_WRITE_ASYNC_STATUS_OK) { conn_check_queued_writes (conn); (conn->func)(conn, GNET_CONN_STATUS_WRITE, buffer, length, conn->user_data); } else { (conn->func)(conn, GNET_CONN_STATUS_ERROR, NULL, 0, conn->user_data); }}/** * gnet_conn_timeout * @conn: Connection to set timeout on * @timeout: Timeout (in milliseconds) * * Set a timeout on the connection. When the time expires, the * #GConn's callback is called. If there already is a timeout, the * old timeout is canceled. * **/voidgnet_conn_timeout (GConn* conn, guint timeout){ g_return_if_fail (conn); g_return_if_fail (conn->func); if (conn->timer) { g_source_remove (conn->timer); conn->timer = 0; } if (timeout) { conn->timer = g_timeout_add (timeout, conn_timeout_cb, conn); }}static gboolean conn_timeout_cb (gpointer data){ GConn* conn = (GConn*) data; g_return_val_if_fail (conn, FALSE); conn->timer = 0; (conn->func)(conn, GNET_CONN_STATUS_TIMEOUT, NULL, 0, conn->user_data); return FALSE;}static voidconn_check_queued_writes (GConn* conn){ g_return_if_fail (conn); g_return_if_fail (conn->iochannel); if (conn->write_id) g_return_if_fail (FALSE); if (conn->queued_writes) { QueuedWrite* queued_write = conn->queued_writes->data; conn->queued_writes = g_list_remove (conn->queued_writes, queued_write); conn->write_id = gnet_io_channel_write_async (conn->iochannel, queued_write->buffer, queued_write->length, queued_write->timeout, conn_write_cb, conn); g_free (queued_write); }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?