示例#1
0
/**
 * Resolves an IP address to a hostname per DNS.
 *
 * @param ha	The host address to resolve.
 * @return		On success, the hostname is returned. Otherwise, NULL is
 *				returned. The resulting string points to a static buffer.
 */
const char *
host_addr_to_name(host_addr_t addr)
{
	socket_addr_t sa;

	if (host_addr_can_convert(addr, NET_TYPE_IPV4)) {
		(void) host_addr_convert(addr, &addr, NET_TYPE_IPV4);
	}
	if (0 == socket_addr_set(&sa, addr, 0)) {
		return NULL;
	}

#ifdef HAS_GETNAMEINFO
	{
		static char host[1025];
		int error;

		error = getnameinfo(socket_addr_get_const_sockaddr(&sa),
					socket_addr_get_len(&sa), host, sizeof host, NULL, 0, 0);
		if (error) {
			char buf[HOST_ADDR_BUFLEN];

			host_addr_to_string_buf(addr, buf, sizeof buf);
			g_message("getnameinfo() failed for \"%s\": %s",
				buf, gai_strerror(error));
			return NULL;
		}
		return host;
	}
#else	/* !HAS_GETNAMEINFO */
	{
		const struct hostent *he;
		socklen_t len = 0;
		const char *ptr = NULL;

		switch (host_addr_net(addr)) {
		case NET_TYPE_IPV4:
			ptr = cast_to_gchar_ptr(&sa.inet4.sin_addr);
			len = sizeof sa.inet4.sin_addr;
			break;
		case NET_TYPE_IPV6:
#ifdef HAS_IPV6
			ptr = cast_to_gchar_ptr(&sa.inet6.sin6_addr);
			len = sizeof sa.inet6.sin6_addr;
			break;
#endif /* HAS_IPV6 */
		case NET_TYPE_LOCAL:
		case NET_TYPE_NONE:
			return NULL;
		}
		g_return_val_if_fail(ptr, NULL);
		g_return_val_if_fail(0 != len, NULL);

		he = gethostbyaddr(ptr, len, socket_addr_get_family(&sa));
		if (!he) {
			char buf[HOST_ADDR_BUFLEN];

			host_addr_to_string_buf(addr, buf, sizeof buf);
			gethostbyname_error(buf);
			return NULL;
		}
		return he->h_name;
	}
#endif	/* HAS_GETNAMEINFO */
}
示例#2
0
/**
 * Writes the browse host data of the context ``ctx'' to the buffer
 * ``dest''. This must be called multiple times to retrieve the complete
 * data until zero is returned i.e., the end of file is reached.
 *
 * This routine deals with HTML data generation.
 *
 * @param ctx an initialized browse host context.
 * @param dest the destination buffer.
 * @param size the amount of bytes ``dest'' can hold.
 *
 * @return -1 on failure, zero at the end-of-file condition or if size
 *         was zero. On success, the amount of bytes copied to ``dest''
 *         is returned.
 */
static ssize_t
browse_host_read_html(struct special_upload *ctx,
                      gpointer const dest, size_t size)
{
    static const char header[] =
        "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\">\r\n"
        "<html>\r\n"
        "<head>\r\n"
        "<title>Browse Host</title>\r\n"
        "</head>\r\n"
        "<body>\r\n";
    static const char trailer[] = "</ul>\r\n</body>\r\n</html>\r\n";
    struct browse_host_upload *bh = cast_to_browse_host_upload(ctx);
    char *p = dest;

    g_assert(NULL != bh);
    g_assert(NULL != dest);
    g_assert(size <= INT_MAX);

    g_assert(UNSIGNED(bh->state) < NUM_BH_STATES);
    g_assert(bh->b_size <= INT_MAX);
    g_assert(bh->b_offset <= bh->b_size);

    do {
        switch (bh->state) {
        case BH_STATE_HEADER:
            if (!bh->b_data) {
                bh->b_data = header;
                bh->b_size = CONST_STRLEN(header);
            }
            p += browse_host_read_data(bh, p, &size);
            if (bh->b_size == bh->b_offset)
                browse_host_next_state(bh, BH_STATE_LIBRARY_INFO);
            break;

        case BH_STATE_LIBRARY_INFO:
            if (!bh->b_data) {
                bh->w_buf_size = w_concat_strings(&bh->w_buf,
                                                  "<h1>" GTA_PRODUCT_NAME "</h1>\r\n"
                                                  "<h3>", version_get_string(),
                                                  " sharing ",
                                                  uint64_to_string(shared_files_scanned()),
                                                  " file",
                                                  shared_files_scanned() == 1 ? "" : "s",
                                                  " ",
                                                  short_kb_size(shared_kbytes_scanned(),
                                                          GNET_PROPERTY(display_metric_units)),
                                                  " total</h3>\r\n"
                                                  "<ul>\r\n", (void *) 0);
                bh->b_data = bh->w_buf;
                bh->b_size = bh->w_buf_size - 1; /* minus trailing NUL */
                bh->b_offset = 0;
            }
            p += browse_host_read_data(bh, p, &size);
            if (bh->b_size == bh->b_offset)
                browse_host_next_state(bh, BH_STATE_FILES);
            break;

        case BH_STATE_TRAILER:
            if (!bh->b_data) {
                bh->b_data = trailer;
                bh->b_size = CONST_STRLEN(trailer);
            }
            p += browse_host_read_data(bh, p, &size);
            if (bh->b_size == bh->b_offset)
                browse_host_next_state(bh, BH_STATE_EOF);
            break;

        case BH_STATE_FILES:
            if (bh->b_data && bh->b_size == bh->b_offset) {
                g_assert(bh->w_buf == bh->b_data);
                wfree(bh->w_buf, bh->w_buf_size);
                bh->w_buf = NULL;
                bh->w_buf_size = 0;
                bh->b_data = NULL;
            }

            if (!bh->b_data) {
                const shared_file_t *sf;

                bh->file_index++;
                sf = shared_file_sorted(bh->file_index);
                if (!sf) {
                    if (bh->file_index > shared_files_scanned())
                        browse_host_next_state(bh, BH_STATE_TRAILER);
                    /* Skip holes in the file_index table */
                } else if (SHARE_REBUILDING == sf) {
                    browse_host_next_state(bh, BH_STATE_REBUILDING);
                } else {
                    const char * const name_nfc = shared_file_name_nfc(sf);
                    const filesize_t file_size = shared_file_size(sf);
                    size_t html_size;
                    char *html_name;

                    {
                        const char *dir;
                        char *name;

                        dir = shared_file_relative_path(sf);
                        if (dir) {
                            name = h_strconcat(dir, "/", name_nfc, (void *) 0);
                        } else {
                            name = deconstify_gchar(name_nfc);
                        }

                        html_size = 1 + html_escape(name, NULL, 0);
                        html_name = walloc(html_size);
                        html_escape(name, html_name, html_size);
                        if (name != name_nfc) {
                            HFREE_NULL(name);
                        }
                    }

                    if (sha1_hash_available(sf)) {
                        const struct sha1 *sha1 = shared_file_sha1(sf);

                        bh->w_buf_size = w_concat_strings(&bh->w_buf,
                                                          "<li><a href=\"/uri-res/N2R?urn:sha1:",
                                                          sha1_base32(sha1),
                                                          "\">", html_name, "</a>&nbsp;[",
                                                          short_html_size(file_size,
                                                                  GNET_PROPERTY(display_metric_units)),
                                                          "]</li>\r\n",
                                                          (void *) 0);
                    } else {
                        char *escaped;

                        escaped = url_escape(name_nfc);
                        bh->w_buf_size = w_concat_strings(&bh->w_buf,
                                                          "<li><a href=\"/get/",
                                                          uint32_to_string(shared_file_index(sf)),
                                                          "/", escaped, "\">", html_name, "</a>"
                                                          "&nbsp;[",
                                                          short_html_size(file_size,
                                                                  GNET_PROPERTY(display_metric_units)),
                                                          "]</li>\r\n", (void *) 0);

                        if (escaped != name_nfc) {
                            HFREE_NULL(escaped);
                        }
                    }

                    wfree(html_name, html_size);
                    bh->b_data = bh->w_buf;
                    bh->b_size = bh->w_buf_size - 1; /* minus trailing NUL */
                    bh->b_offset = 0;
                }
            }

            if (bh->b_data)
                p += browse_host_read_data(bh, p, &size);

            break;

        case BH_STATE_REBUILDING:
            if (!bh->b_data) {
                static const char msg[] =
                    "<li>"
                    "<b>"
                    "The library is currently being rebuild. Please, "
                    "try again in a moment."
                    "</b>"
                    "</li>";

                bh->b_data = msg;
                bh->b_size = CONST_STRLEN(msg);
            }
            p += browse_host_read_data(bh, p, &size);
            if (bh->b_size == bh->b_offset)
                browse_host_next_state(bh, BH_STATE_TRAILER);
            break;

        case BH_STATE_EOF:
            return p - cast_to_gchar_ptr(dest);

        case NUM_BH_STATES:
            g_assert_not_reached();
        }
    } while (size > 0);

    return p - cast_to_gchar_ptr(dest);
}
示例#3
0
文件: adns.c 项目: MrJoe/gtk-gnutella
/**
 * Callback function for inputevt_add(). This function invokes the callback
 * function given in DNS query on the client-side i.e., gtk-gnutella itself.
 * It handles partial reads if necessary. In case of an unrecoverable error
 * the reply pipe will be closed and the callback will be lost.
 */
static void
adns_reply_callback(void *data, int source, inputevt_cond_t condition)
{
	static struct adns_response ans;
	static void *buf;
	static size_t size, pos;

	g_assert(NULL == data);
	g_assert(condition & INPUT_EVENT_RX);

	/*
	 * Consume all the data available in the pipe, potentially handling
	 * several pending replies.
	 */

	for (;;) {
		ssize_t ret;
		size_t n;

		if (pos == size) {

			pos = 0;
			if (cast_to_pointer(&ans.common) == buf) {
				/*
				 * Finished reading the generic reply header, now read
				 * the specific part.
				 */

				g_assert(ADNS_COMMON_MAGIC == ans.common.magic);

				if (ans.common.reverse) {
					buf = &ans.reply.reverse;
					size = sizeof ans.reply.reverse;
				} else {
					buf = &ans.reply.by_addr;
					size = sizeof ans.reply.by_addr;
				}
			} else {
				if (buf) {
					/*
					 * Completed reading the specific part of the reply.
					 * Inform issuer of request by invoking the user callback.
					 */

					adns_reply_ready(&ans);
				}

				/*
				 * Continue reading the next reply, if any, which will start
				 * by the generic header.
				 */

				buf = &ans.common;
				size = sizeof ans.common;
				ans.common.magic = 0;
			}
		}

		g_assert(buf);
		g_assert(size > 0);
		g_assert(pos < size);

		n = size - pos;
		ret = read(source, cast_to_gchar_ptr(buf) + pos, n);
		if ((ssize_t) -1 == ret) {
		   	if (!is_temporary_error(errno)) {
				g_warning("%s: read() failed: %m", G_STRFUNC);
				goto error;
			}
			break;
		} else if (0 == ret) {
			g_warning("%s: read() failed: EOF", G_STRFUNC);
			goto error;
		} else {
			g_assert(ret > 0);
			g_assert(UNSIGNED(ret) <= n);
			pos += (size_t) ret;
		}
	}
	return;
	
error:
	inputevt_remove(&adns_reply_event_id);
	g_warning("%s: removed myself", G_STRFUNC);
	fd_close(&source);
}