context.c revision 0c27b3fe77ac1d5094ba3521e8142d9e7973133f
/*
* Copyright (C) 2000, 2001, 2003-2005, 2007-2009, 2012-2014, 2016 Internet Systems Consortium, Inc. ("ISC")
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
/* $Id: context.c,v 1.55 2009/09/02 23:48:03 tbox Exp $ */
/*! \file context.c
lwres_context_create() creates a #lwres_context_t structure for use in
lightweight resolver operations. It holds a socket and other data
needed for communicating with a resolver daemon. The new
lwres_context_t is returned through contextp, a pointer to a
lwres_context_t pointer. This lwres_context_t pointer must initially
be NULL, and is modified to point to the newly created
lwres_context_t.
When the lightweight resolver needs to perform dynamic memory
allocation, it will call malloc_function to allocate memory and
free_function to free it. If malloc_function and free_function are
NULL, memory is allocated using malloc and free. It is not
permitted to have a NULL malloc_function and a non-NULL free_function
or vice versa. arg is passed as the first parameter to the memory
allocation functions. If malloc_function and free_function are NULL,
arg is unused and should be passed as NULL.
Once memory for the structure has been allocated, it is initialized
using lwres_conf_init() and returned via *contextp.
lwres_context_destroy() destroys a #lwres_context_t, closing its
socket. contextp is a pointer to a pointer to the context that is to
be destroyed. The pointer will be set to NULL when the context has
been destroyed.
The context holds a serial number that is used to identify resolver
request packets and associate responses with the corresponding
requests. This serial number is controlled using
lwres_context_initserial() and lwres_context_nextserial().
lwres_context_initserial() sets the serial number for context *ctx to
serial. lwres_context_nextserial() increments the serial number and
returns the previous value.
Memory for a lightweight resolver context is allocated and freed using
lwres_context_allocmem() and lwres_context_freemem(). These use
whatever allocations were defined when the context was created with
lwres_context_create(). lwres_context_allocmem() allocates len bytes
of memory and if successful returns a pointer to the allocated
storage. lwres_context_freemem() frees len bytes of space starting at
location mem.
lwres_context_sendrecv() performs I/O for the context ctx. Data are
read and written from the context's socket. It writes data from
sendbase -- typically a lightweight resolver query packet -- and waits
for a reply which is copied to the receive buffer at recvbase. The
number of bytes that were written to this receive buffer is returned
in *recvd_len.
\section context_return Return Values
lwres_context_create() returns #LWRES_R_NOMEMORY if memory for the
struct lwres_context could not be allocated, #LWRES_R_SUCCESS
otherwise.
Successful calls to the memory allocator lwres_context_allocmem()
return a pointer to the start of the allocated space. It returns NULL
if memory could not be allocated.
#LWRES_R_SUCCESS is returned when lwres_context_sendrecv() completes
successfully. #LWRES_R_IOERROR is returned if an I/O error occurs and
#LWRES_R_TIMEOUT is returned if lwres_context_sendrecv() times out
waiting for a response.
\section context_see See Also
lwres_conf_init(), malloc, free.
*/
#include <config.h>
#include <fcntl.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <lwres/platform.h>
#endif
#include "context_p.h"
#include "assert_p.h"
/*!
* Some systems define the socket length argument as an int, some as size_t,
* some as socklen_t. The last is what the current POSIX standard mandates.
* This definition is here so it can be portable but easily changed if needed.
*/
#ifndef LWRES_SOCKADDR_LEN_T
#define LWRES_SOCKADDR_LEN_T unsigned int
#endif
/*!
* Make a socket nonblocking.
*/
#ifndef MAKE_NONBLOCKING
do { \
if (retval != -1) { \
retval |= O_NONBLOCK; \
} \
} while (0)
#endif
static void *
lwres_malloc(void *, size_t);
static void
lwres_free(void *, void *, size_t);
/*!
* lwres_result_t
*/
static lwres_result_t
/*%
* Creates a #lwres_context_t structure for use in
* lightweight resolver operations.
*/
unsigned int flags)
{
/*
* If we were not given anything special to use, use our own
* functions. These are just wrappers around malloc() and free().
*/
}
return (LWRES_R_NOMEMORY);
/*
* Set up the context.
*/
#ifndef WIN32
#else
#endif
}
}
/*
* Init resolv.conf bits.
*/
return (LWRES_R_SUCCESS);
}
/*%
Destroys a #lwres_context_t, closing its socket.
contextp is a pointer to a pointer to the context that is
to be destroyed. The pointer will be set to NULL
when the context has been destroyed.
*/
void
#ifdef WIN32
#endif
}
}
/*% Increments the serial number and returns the previous value. */
}
/*% Sets the serial number for context *ctx to serial. */
void
}
/*% Frees len bytes of space starting at location mem. */
void
}
/*% Allocates len bytes of memory and if successful returns a pointer to the allocated storage. */
void *
}
static void *
void *mem;
return (NULL);
return (mem);
}
static void
}
static lwres_result_t
#ifndef WIN32
int s;
#else
SOCKET s;
#endif
int ret;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
int domain;
sizeof(lwres_addr_t));
} else {
/* The default is the IPv4 loopback address 127.0.0.1. */
}
} else
return (LWRES_R_IOERROR);
#ifdef WIN32
InitSockets();
#endif
#ifndef WIN32
if (s < 0) {
return (LWRES_R_IOERROR);
}
#else
if (s == INVALID_SOCKET) {
return (LWRES_R_IOERROR);
}
#endif
if (ret != 0) {
#ifdef WIN32
#endif
(void)close(s);
return (LWRES_R_IOERROR);
}
MAKE_NONBLOCKING(s, ret);
if (ret < 0) {
#ifdef WIN32
#endif
(void)close(s);
return (LWRES_R_IOERROR);
}
return (LWRES_R_SUCCESS);
}
int
}
int ret;
if (lwresult != LWRES_R_SUCCESS)
return (lwresult);
}
if (ret < 0)
return (LWRES_R_IOERROR);
return (LWRES_R_IOERROR);
return (LWRES_R_SUCCESS);
}
int *recvd_len)
{
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
int ret;
} else {
}
/*
* The address of fromlen is cast to void * to shut up compiler
* warnings, namely on systems that have the sixth parameter
* prototyped as a signed int when LWRES_SOCKADDR_LEN_T is
* defined as unsigned.
*/
if (ret < 0)
return (LWRES_R_IOERROR);
return (LWRES_R_TOOLARGE);
/*
* If we got something other than what we expect, have the caller
* wait for another packet. This can happen if an old result
* comes in, or if someone is sending us random stuff.
*/
return (LWRES_R_RETRY);
} else {
return (LWRES_R_RETRY);
}
return (LWRES_R_SUCCESS);
}
/*% performs I/O for the context ctx. */
int *recvd_len)
{
int ret2;
/*
* Type of tv_sec is 32 bits long.
*/
else
if (result != LWRES_R_SUCCESS)
return (result);
/*
* If this is not checked, select() can overflow,
* causing corruption elsewhere.
*/
return (LWRES_R_IOERROR);
}
/*
* What happened with select?
*/
if (ret2 < 0)
return (LWRES_R_IOERROR);
if (ret2 == 0)
return (LWRES_R_TIMEOUT);
if (result == LWRES_R_RETRY)
goto again;
return (result);
}