1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /* gnome-vfs-inet-connection.c - Functions for creating and destroying Internet
5 Copyright (C) 1999 Free Software Foundation
7 The Gnome Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public License as
9 published by the Free Software Foundation; either version 2 of the
10 License, or (at your option) any later version.
12 The Gnome Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
17 You should have received a copy of the GNU Library General Public
18 License along with the Gnome Library; see the file COPYING.LIB. If not,
19 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.
22 Author: Ettore Perazzoli <ettore@gnu.org> */
25 #include "gnome-vfs-inet-connection.h"
26 #include "gnome-vfs-private-utils.h"
29 #include <glib/gmem.h>
30 #include <glib/gmessages.h>
32 /* Keep <sys/types.h> above the network includes for FreeBSD. */
33 #include <sys/types.h>
35 #include <netinet/in.h>
36 #include <sys/socket.h>
37 #include <sys/types.h>
42 struct GnomeVFSInetConnection {
44 struct sockaddr_in6 addr6;
46 struct sockaddr_in addr;
52 * gnome_vfs_inet_connection_create:
53 * @connection_return: pointer to a GnomeVFSInetConnection, which will
54 * contain an allocated GnomeVFSInetConnection object on return.
55 * @host_name: string indicating the host to establish an internet connection with
56 * @host_port: the port number to connect to
57 * @cancellation: handle allowing cancellation of the operation
59 * Creates a connection at @handle_return to @host_name using
62 * Return value: GnomeVFSResult indicating the success of the operation
65 gnome_vfs_inet_connection_create (GnomeVFSInetConnection **connection_return,
66 const gchar *host_name,
68 GnomeVFSCancellation *cancellation)
70 GnomeVFSInetConnection *new;
72 struct addrinfo hints, *result, *res;
75 struct hostent *host_info;
76 struct sockaddr_in addr;
79 g_return_val_if_fail (connection_return != NULL, GNOME_VFS_ERROR_BAD_PARAMETERS);
80 g_return_val_if_fail (host_name != NULL, GNOME_VFS_ERROR_BAD_PARAMETERS);
81 g_return_val_if_fail (host_port != 0, GNOME_VFS_ERROR_BAD_PARAMETERS);
84 if (_gnome_vfs_have_ipv6 ()) {
89 memset (&hints, 0, sizeof (hints));
90 hints.ai_socktype = SOCK_STREAM;
92 if (getaddrinfo (host_name, NULL, &hints, &result) != 0) {
93 return GNOME_VFS_ERROR_HOST_NOT_FOUND;
96 if (gnome_vfs_cancellation_check (cancellation)) {
97 return GNOME_VFS_ERROR_CANCELLED;
100 /*For selecting a valid IP of the List*/
101 for (res = result; res; res = res->ai_next) {
103 if (res->ai_family != AF_INET && res->ai_family != AF_INET6) {
107 sock = socket (res->ai_family, SOCK_STREAM, 0);
112 if (res->ai_family == AF_INET) {
113 ((struct sockaddr_in *)res->ai_addr)->sin_port = htons (host_port);
116 if (res->ai_family == AF_INET6) {
117 ((struct sockaddr_in6 *)res->ai_addr)->sin6_port = htons (host_port);
120 ret = connect (sock, res->ai_addr, res->ai_addrlen);
129 freeaddrinfo (result);
131 if (sock < 0 || ret < 0) {
132 /*Error in connection or socket creation.*/
133 return gnome_vfs_result_from_errno ();
135 /*Error: No IPv4 or IPv6 address.*/
136 return GNOME_VFS_ERROR_HOST_NOT_FOUND;
140 new = g_new (GnomeVFSInetConnection, 1);
142 if (res->ai_family == AF_INET) {
143 memcpy (&new->addr, res->ai_addr, res->ai_addrlen);
146 if (res->ai_family == AF_INET6) {
147 memcpy (&new->addr6, res->ai_addr, res->ai_addrlen);
150 new->socklen = res->ai_addrlen;
152 freeaddrinfo (result);
157 sock = socket (PF_INET, SOCK_STREAM, 0);
159 return gnome_vfs_result_from_errno ();
162 host_info = gethostbyname (host_name);
163 if (gnome_vfs_cancellation_check (cancellation)) {
164 return GNOME_VFS_ERROR_CANCELLED;
167 if (host_info == NULL) {
168 return gnome_vfs_result_from_h_errno ();
171 addr.sin_family = host_info->h_addrtype;
172 addr.sin_addr = * (struct in_addr *) host_info->h_addr;
173 addr.sin_port = htons (host_port);
175 if (connect (sock, (struct sockaddr *) &addr, sizeof (addr)) < 0) {
176 return gnome_vfs_result_from_errno ();
179 new = g_new (GnomeVFSInetConnection, 1);
180 memcpy (&new->addr, &addr, sizeof (addr));
181 new->socklen = sizeof(addr);
185 *connection_return = new;
191 * gnome_vfs_inet_connection_destroy:
192 * @connection: connection to destroy
193 * @cancellation: handle for cancelling the operation
195 * Closes/Destroys @connection.
198 gnome_vfs_inet_connection_destroy (GnomeVFSInetConnection *connection,
199 GnomeVFSCancellation *cancellation)
201 g_return_if_fail (connection != NULL);
203 close (connection->sock);
208 * gnome_vfs_inet_connection_close:
209 * @connection: connection to close
211 * Closes @connection, freeing all used resources.
214 gnome_vfs_inet_connection_close (GnomeVFSInetConnection *connection)
216 gnome_vfs_inet_connection_destroy (connection, NULL);
220 * gnome_vfs_inet_connection_get_fd:
221 * @connection: connection to get the file descriptor from
223 * Retrieve the UNIX file descriptor corresponding to @connection.
225 * Return value: file descriptor
228 gnome_vfs_inet_connection_get_fd (GnomeVFSInetConnection *connection)
230 g_return_val_if_fail (connection != NULL, -1);
231 return connection->sock;
234 /* SocketImpl for InetConnections */
237 * gnome_vfs_inet_connection_read:
238 * @connection: connection to read data from
239 * @buffer: allocated buffer of at least @bytes bytes to be read into
240 * @bytes: number of bytes to read from @socket into @buffer
241 * @bytes_read: pointer to a GnomeVFSFileSize, will contain
242 * the number of bytes actually read from the socket on return.
244 * Read @bytes bytes of data from @connection into @buffer.
246 * Return value: GnomeVFSResult indicating the success of the operation
248 static GnomeVFSResult
249 gnome_vfs_inet_connection_read (GnomeVFSInetConnection *connection,
251 GnomeVFSFileSize bytes,
252 GnomeVFSFileSize *bytes_read)
257 read_val = read (connection->sock, buffer, bytes);
258 } while (read_val == -1 && errno == EINTR);
260 if (read_val == -1) {
262 return gnome_vfs_result_from_errno ();
264 *bytes_read = read_val;
267 return bytes_read == 0 ? GNOME_VFS_ERROR_EOF : GNOME_VFS_OK;
271 * gnome_vfs_inet_connection_write:
272 * @connection: connection to write data to
273 * @buffer: data to write to the connection
274 * @bytes: number of bytes from @buffer to write to @socket
275 * @bytes_written: pointer to a GnomeVFSFileSize, will contain
276 * the number of bytes actually written to the connection on return.
278 * Write @bytes bytes of data from @buffer to @connection.
280 * Return value: GnomeVFSResult indicating the success of the operation
282 static GnomeVFSResult
283 gnome_vfs_inet_connection_write (GnomeVFSInetConnection *connection,
284 gconstpointer buffer,
285 GnomeVFSFileSize bytes,
286 GnomeVFSFileSize *bytes_written)
291 write_val = write (connection->sock, buffer, bytes);
292 } while (write_val == -1 && errno == EINTR);
294 if (write_val == -1) {
296 return gnome_vfs_result_from_errno ();
298 *bytes_written = write_val;
303 static GnomeVFSSocketImpl inet_connection_socket_impl = {
304 (GnomeVFSSocketReadFunc)gnome_vfs_inet_connection_read,
305 (GnomeVFSSocketWriteFunc)gnome_vfs_inet_connection_write,
306 (GnomeVFSSocketCloseFunc)gnome_vfs_inet_connection_close
310 * gnome_vfs_inet_connection_to_socket:
311 * @connection: connection to convert to wrapper in a GnomeVFSSocket
313 * Wrapper @connection inside a standard GnomeVFSSocket for convenience.
315 * Return value: a newly created GnomeVFSSocket around @connection.
318 gnome_vfs_inet_connection_to_socket (GnomeVFSInetConnection *connection)
320 return gnome_vfs_socket_new (&inet_connection_socket_impl, connection);
324 * gnome_vfs_inet_connection_to_socket_buffer:
325 * @connection: connection to convert to wrapper in a GnomeVFSSocketBuffer
327 * Wrapper @connection inside a standard GnomeVFSSocketBuffer for convenience.
329 * Return value: a newly created GnomeVFSSocketBuffer around @connection.
331 GnomeVFSSocketBuffer *
332 gnome_vfs_inet_connection_to_socket_buffer (GnomeVFSInetConnection *connection)
334 GnomeVFSSocket *socket;
335 socket = gnome_vfs_inet_connection_to_socket (connection);
336 return gnome_vfs_socket_buffer_new (socket);