Blame src/win/getaddrinfo.c

Packit b5b901
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
Packit b5b901
 *
Packit b5b901
 * Permission is hereby granted, free of charge, to any person obtaining a copy
Packit b5b901
 * of this software and associated documentation files (the "Software"), to
Packit b5b901
 * deal in the Software without restriction, including without limitation the
Packit b5b901
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
Packit b5b901
 * sell copies of the Software, and to permit persons to whom the Software is
Packit b5b901
 * furnished to do so, subject to the following conditions:
Packit b5b901
 *
Packit b5b901
 * The above copyright notice and this permission notice shall be included in
Packit b5b901
 * all copies or substantial portions of the Software.
Packit b5b901
 *
Packit b5b901
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Packit b5b901
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Packit b5b901
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
Packit b5b901
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Packit b5b901
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
Packit b5b901
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
Packit b5b901
 * IN THE SOFTWARE.
Packit b5b901
 */
Packit b5b901
Packit b5b901
#include <assert.h>
Packit b5b901
Packit b5b901
#include "uv.h"
Packit b5b901
#include "internal.h"
Packit b5b901
#include "req-inl.h"
Packit Service e08953
#include "idna.h"
Packit b5b901
Packit b5b901
/* EAI_* constants. */
Packit b5b901
#include <winsock2.h>
Packit b5b901
Packit b5b901
/* Needed for ConvertInterfaceIndexToLuid and ConvertInterfaceLuidToNameA */
Packit b5b901
#include <iphlpapi.h>
Packit b5b901
Packit b5b901
int uv__getaddrinfo_translate_error(int sys_err) {
Packit b5b901
  switch (sys_err) {
Packit b5b901
    case 0:                       return 0;
Packit b5b901
    case WSATRY_AGAIN:            return UV_EAI_AGAIN;
Packit b5b901
    case WSAEINVAL:               return UV_EAI_BADFLAGS;
Packit b5b901
    case WSANO_RECOVERY:          return UV_EAI_FAIL;
Packit b5b901
    case WSAEAFNOSUPPORT:         return UV_EAI_FAMILY;
Packit b5b901
    case WSA_NOT_ENOUGH_MEMORY:   return UV_EAI_MEMORY;
Packit b5b901
    case WSAHOST_NOT_FOUND:       return UV_EAI_NONAME;
Packit b5b901
    case WSATYPE_NOT_FOUND:       return UV_EAI_SERVICE;
Packit b5b901
    case WSAESOCKTNOSUPPORT:      return UV_EAI_SOCKTYPE;
Packit b5b901
    default:                      return uv_translate_sys_error(sys_err);
Packit b5b901
  }
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
/*
Packit b5b901
 * MinGW is missing this
Packit b5b901
 */
Packit b5b901
#if !defined(_MSC_VER) && !defined(__MINGW64_VERSION_MAJOR)
Packit b5b901
  typedef struct addrinfoW {
Packit b5b901
    int ai_flags;
Packit b5b901
    int ai_family;
Packit b5b901
    int ai_socktype;
Packit b5b901
    int ai_protocol;
Packit b5b901
    size_t ai_addrlen;
Packit b5b901
    WCHAR* ai_canonname;
Packit b5b901
    struct sockaddr* ai_addr;
Packit b5b901
    struct addrinfoW* ai_next;
Packit b5b901
  } ADDRINFOW, *PADDRINFOW;
Packit b5b901
Packit b5b901
  DECLSPEC_IMPORT int WSAAPI GetAddrInfoW(const WCHAR* node,
Packit b5b901
                                          const WCHAR* service,
Packit b5b901
                                          const ADDRINFOW* hints,
Packit b5b901
                                          PADDRINFOW* result);
Packit b5b901
Packit b5b901
  DECLSPEC_IMPORT void WSAAPI FreeAddrInfoW(PADDRINFOW pAddrInfo);
Packit b5b901
#endif
Packit b5b901
Packit b5b901
Packit b5b901
/* Adjust size value to be multiple of 4. Use to keep pointer aligned.
Packit b5b901
 * Do we need different versions of this for different architectures? */
Packit b5b901
#define ALIGNED_SIZE(X)     ((((X) + 3) >> 2) << 2)
Packit b5b901
Packit b5b901
#ifndef NDIS_IF_MAX_STRING_SIZE
Packit b5b901
#define NDIS_IF_MAX_STRING_SIZE IF_MAX_STRING_SIZE
Packit b5b901
#endif
Packit b5b901
Packit b5b901
static void uv__getaddrinfo_work(struct uv__work* w) {
Packit b5b901
  uv_getaddrinfo_t* req;
Packit b5b901
  struct addrinfoW* hints;
Packit b5b901
  int err;
Packit b5b901
Packit b5b901
  req = container_of(w, uv_getaddrinfo_t, work_req);
Packit b5b901
  hints = req->addrinfow;
Packit b5b901
  req->addrinfow = NULL;
Packit b5b901
  err = GetAddrInfoW(req->node, req->service, hints, &req->addrinfow);
Packit b5b901
  req->retcode = uv__getaddrinfo_translate_error(err);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
/*
Packit b5b901
 * Called from uv_run when complete. Call user specified callback
Packit b5b901
 * then free returned addrinfo
Packit b5b901
 * Returned addrinfo strings are converted from UTF-16 to UTF-8.
Packit b5b901
 *
Packit b5b901
 * To minimize allocation we calculate total size required,
Packit b5b901
 * and copy all structs and referenced strings into the one block.
Packit b5b901
 * Each size calculation is adjusted to avoid unaligned pointers.
Packit b5b901
 */
Packit b5b901
static void uv__getaddrinfo_done(struct uv__work* w, int status) {
Packit b5b901
  uv_getaddrinfo_t* req;
Packit b5b901
  int addrinfo_len = 0;
Packit b5b901
  int name_len = 0;
Packit b5b901
  size_t addrinfo_struct_len = ALIGNED_SIZE(sizeof(struct addrinfo));
Packit b5b901
  struct addrinfoW* addrinfow_ptr;
Packit b5b901
  struct addrinfo* addrinfo_ptr;
Packit b5b901
  char* alloc_ptr = NULL;
Packit b5b901
  char* cur_ptr = NULL;
Packit b5b901
Packit b5b901
  req = container_of(w, uv_getaddrinfo_t, work_req);
Packit b5b901
Packit b5b901
  /* release input parameter memory */
Packit b5b901
  uv__free(req->alloc);
Packit b5b901
  req->alloc = NULL;
Packit b5b901
Packit b5b901
  if (status == UV_ECANCELED) {
Packit b5b901
    assert(req->retcode == 0);
Packit b5b901
    req->retcode = UV_EAI_CANCELED;
Packit b5b901
    goto complete;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (req->retcode == 0) {
Packit b5b901
    /* Convert addrinfoW to addrinfo. First calculate required length. */
Packit b5b901
    addrinfow_ptr = req->addrinfow;
Packit b5b901
    while (addrinfow_ptr != NULL) {
Packit b5b901
      addrinfo_len += addrinfo_struct_len +
Packit b5b901
          ALIGNED_SIZE(addrinfow_ptr->ai_addrlen);
Packit b5b901
      if (addrinfow_ptr->ai_canonname != NULL) {
Packit b5b901
        name_len = WideCharToMultiByte(CP_UTF8,
Packit b5b901
                                       0,
Packit b5b901
                                       addrinfow_ptr->ai_canonname,
Packit b5b901
                                       -1,
Packit b5b901
                                       NULL,
Packit b5b901
                                       0,
Packit b5b901
                                       NULL,
Packit b5b901
                                       NULL);
Packit b5b901
        if (name_len == 0) {
Packit b5b901
          req->retcode = uv_translate_sys_error(GetLastError());
Packit b5b901
          goto complete;
Packit b5b901
        }
Packit b5b901
        addrinfo_len += ALIGNED_SIZE(name_len);
Packit b5b901
      }
Packit b5b901
      addrinfow_ptr = addrinfow_ptr->ai_next;
Packit b5b901
    }
Packit b5b901
Packit b5b901
    /* allocate memory for addrinfo results */
Packit b5b901
    alloc_ptr = (char*)uv__malloc(addrinfo_len);
Packit b5b901
Packit b5b901
    /* do conversions */
Packit b5b901
    if (alloc_ptr != NULL) {
Packit b5b901
      cur_ptr = alloc_ptr;
Packit b5b901
      addrinfow_ptr = req->addrinfow;
Packit b5b901
Packit b5b901
      while (addrinfow_ptr != NULL) {
Packit b5b901
        /* copy addrinfo struct data */
Packit b5b901
        assert(cur_ptr + addrinfo_struct_len <= alloc_ptr + addrinfo_len);
Packit b5b901
        addrinfo_ptr = (struct addrinfo*)cur_ptr;
Packit b5b901
        addrinfo_ptr->ai_family = addrinfow_ptr->ai_family;
Packit b5b901
        addrinfo_ptr->ai_socktype = addrinfow_ptr->ai_socktype;
Packit b5b901
        addrinfo_ptr->ai_protocol = addrinfow_ptr->ai_protocol;
Packit b5b901
        addrinfo_ptr->ai_flags = addrinfow_ptr->ai_flags;
Packit b5b901
        addrinfo_ptr->ai_addrlen = addrinfow_ptr->ai_addrlen;
Packit b5b901
        addrinfo_ptr->ai_canonname = NULL;
Packit b5b901
        addrinfo_ptr->ai_addr = NULL;
Packit b5b901
        addrinfo_ptr->ai_next = NULL;
Packit b5b901
Packit b5b901
        cur_ptr += addrinfo_struct_len;
Packit b5b901
Packit b5b901
        /* copy sockaddr */
Packit b5b901
        if (addrinfo_ptr->ai_addrlen > 0) {
Packit b5b901
          assert(cur_ptr + addrinfo_ptr->ai_addrlen <=
Packit b5b901
                 alloc_ptr + addrinfo_len);
Packit b5b901
          memcpy(cur_ptr, addrinfow_ptr->ai_addr, addrinfo_ptr->ai_addrlen);
Packit b5b901
          addrinfo_ptr->ai_addr = (struct sockaddr*)cur_ptr;
Packit b5b901
          cur_ptr += ALIGNED_SIZE(addrinfo_ptr->ai_addrlen);
Packit b5b901
        }
Packit b5b901
Packit b5b901
        /* convert canonical name to UTF-8 */
Packit b5b901
        if (addrinfow_ptr->ai_canonname != NULL) {
Packit b5b901
          name_len = WideCharToMultiByte(CP_UTF8,
Packit b5b901
                                         0,
Packit b5b901
                                         addrinfow_ptr->ai_canonname,
Packit b5b901
                                         -1,
Packit b5b901
                                         NULL,
Packit b5b901
                                         0,
Packit b5b901
                                         NULL,
Packit b5b901
                                         NULL);
Packit b5b901
          assert(name_len > 0);
Packit b5b901
          assert(cur_ptr + name_len <= alloc_ptr + addrinfo_len);
Packit b5b901
          name_len = WideCharToMultiByte(CP_UTF8,
Packit b5b901
                                         0,
Packit b5b901
                                         addrinfow_ptr->ai_canonname,
Packit b5b901
                                         -1,
Packit b5b901
                                         cur_ptr,
Packit b5b901
                                         name_len,
Packit b5b901
                                         NULL,
Packit b5b901
                                         NULL);
Packit b5b901
          assert(name_len > 0);
Packit b5b901
          addrinfo_ptr->ai_canonname = cur_ptr;
Packit b5b901
          cur_ptr += ALIGNED_SIZE(name_len);
Packit b5b901
        }
Packit b5b901
        assert(cur_ptr <= alloc_ptr + addrinfo_len);
Packit b5b901
Packit b5b901
        /* set next ptr */
Packit b5b901
        addrinfow_ptr = addrinfow_ptr->ai_next;
Packit b5b901
        if (addrinfow_ptr != NULL) {
Packit b5b901
          addrinfo_ptr->ai_next = (struct addrinfo*)cur_ptr;
Packit b5b901
        }
Packit b5b901
      }
Packit b5b901
      req->addrinfo = (struct addrinfo*)alloc_ptr;
Packit b5b901
    } else {
Packit b5b901
      req->retcode = UV_EAI_MEMORY;
Packit b5b901
    }
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* return memory to system */
Packit b5b901
  if (req->addrinfow != NULL) {
Packit b5b901
    FreeAddrInfoW(req->addrinfow);
Packit b5b901
    req->addrinfow = NULL;
Packit b5b901
  }
Packit b5b901
Packit b5b901
complete:
Packit b5b901
  uv__req_unregister(req->loop, req);
Packit b5b901
Packit b5b901
  /* finally do callback with converted result */
Packit b5b901
  if (req->getaddrinfo_cb)
Packit b5b901
    req->getaddrinfo_cb(req, req->retcode, req->addrinfo);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
void uv_freeaddrinfo(struct addrinfo* ai) {
Packit b5b901
  char* alloc_ptr = (char*)ai;
Packit b5b901
Packit b5b901
  /* release copied result memory */
Packit b5b901
  uv__free(alloc_ptr);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
/*
Packit b5b901
 * Entry point for getaddrinfo
Packit b5b901
 * we convert the UTF-8 strings to UNICODE
Packit b5b901
 * and save the UNICODE string pointers in the req
Packit b5b901
 * We also copy hints so that caller does not need to keep memory until the
Packit b5b901
 * callback.
Packit b5b901
 * return 0 if a callback will be made
Packit b5b901
 * return error code if validation fails
Packit b5b901
 *
Packit b5b901
 * To minimize allocation we calculate total size required,
Packit b5b901
 * and copy all structs and referenced strings into the one block.
Packit b5b901
 * Each size calculation is adjusted to avoid unaligned pointers.
Packit b5b901
 */
Packit b5b901
int uv_getaddrinfo(uv_loop_t* loop,
Packit b5b901
                   uv_getaddrinfo_t* req,
Packit b5b901
                   uv_getaddrinfo_cb getaddrinfo_cb,
Packit b5b901
                   const char* node,
Packit b5b901
                   const char* service,
Packit b5b901
                   const struct addrinfo* hints) {
Packit Service e08953
  char hostname_ascii[256];
Packit b5b901
  int nodesize = 0;
Packit b5b901
  int servicesize = 0;
Packit b5b901
  int hintssize = 0;
Packit b5b901
  char* alloc_ptr = NULL;
Packit b5b901
  int err;
Packit Service e08953
  long rc;
Packit b5b901
Packit b5b901
  if (req == NULL || (node == NULL && service == NULL)) {
Packit b5b901
    return UV_EINVAL;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  UV_REQ_INIT(req, UV_GETADDRINFO);
Packit b5b901
  req->getaddrinfo_cb = getaddrinfo_cb;
Packit b5b901
  req->addrinfo = NULL;
Packit b5b901
  req->loop = loop;
Packit b5b901
  req->retcode = 0;
Packit b5b901
Packit b5b901
  /* calculate required memory size for all input values */
Packit b5b901
  if (node != NULL) {
Packit Service e08953
    rc = uv__idna_toascii(node,
Packit Service e08953
                          node + strlen(node),
Packit Service e08953
                          hostname_ascii,
Packit Service e08953
                          hostname_ascii + sizeof(hostname_ascii));
Packit Service e08953
    if (rc < 0)
Packit Service e08953
      return rc;
Packit Service e08953
    nodesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, 0, hostname_ascii,
Packit Service e08953
                                                -1, NULL, 0) * sizeof(WCHAR));
Packit b5b901
    if (nodesize == 0) {
Packit b5b901
      err = GetLastError();
Packit b5b901
      goto error;
Packit b5b901
    }
Packit Service e08953
    node = hostname_ascii;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (service != NULL) {
Packit b5b901
    servicesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8,
Packit b5b901
                                                   0,
Packit b5b901
                                                   service,
Packit b5b901
                                                   -1,
Packit b5b901
                                                   NULL,
Packit b5b901
                                                   0) *
Packit b5b901
                               sizeof(WCHAR));
Packit b5b901
    if (servicesize == 0) {
Packit b5b901
      err = GetLastError();
Packit b5b901
      goto error;
Packit b5b901
    }
Packit b5b901
  }
Packit b5b901
  if (hints != NULL) {
Packit b5b901
    hintssize = ALIGNED_SIZE(sizeof(struct addrinfoW));
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* allocate memory for inputs, and partition it as needed */
Packit b5b901
  alloc_ptr = (char*)uv__malloc(nodesize + servicesize + hintssize);
Packit b5b901
  if (!alloc_ptr) {
Packit b5b901
    err = WSAENOBUFS;
Packit b5b901
    goto error;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* save alloc_ptr now so we can free if error */
Packit b5b901
  req->alloc = (void*)alloc_ptr;
Packit b5b901
Packit b5b901
  /* Convert node string to UTF16 into allocated memory and save pointer in the
Packit b5b901
   * request. */
Packit b5b901
  if (node != NULL) {
Packit b5b901
    req->node = (WCHAR*)alloc_ptr;
Packit b5b901
    if (MultiByteToWideChar(CP_UTF8,
Packit b5b901
                            0,
Packit b5b901
                            node,
Packit b5b901
                            -1,
Packit b5b901
                            (WCHAR*) alloc_ptr,
Packit b5b901
                            nodesize / sizeof(WCHAR)) == 0) {
Packit b5b901
      err = GetLastError();
Packit b5b901
      goto error;
Packit b5b901
    }
Packit b5b901
    alloc_ptr += nodesize;
Packit b5b901
  } else {
Packit b5b901
    req->node = NULL;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* Convert service string to UTF16 into allocated memory and save pointer in
Packit b5b901
   * the req. */
Packit b5b901
  if (service != NULL) {
Packit b5b901
    req->service = (WCHAR*)alloc_ptr;
Packit b5b901
    if (MultiByteToWideChar(CP_UTF8,
Packit b5b901
                            0,
Packit b5b901
                            service,
Packit b5b901
                            -1,
Packit b5b901
                            (WCHAR*) alloc_ptr,
Packit b5b901
                            servicesize / sizeof(WCHAR)) == 0) {
Packit b5b901
      err = GetLastError();
Packit b5b901
      goto error;
Packit b5b901
    }
Packit b5b901
    alloc_ptr += servicesize;
Packit b5b901
  } else {
Packit b5b901
    req->service = NULL;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* copy hints to allocated memory and save pointer in req */
Packit b5b901
  if (hints != NULL) {
Packit b5b901
    req->addrinfow = (struct addrinfoW*)alloc_ptr;
Packit b5b901
    req->addrinfow->ai_family = hints->ai_family;
Packit b5b901
    req->addrinfow->ai_socktype = hints->ai_socktype;
Packit b5b901
    req->addrinfow->ai_protocol = hints->ai_protocol;
Packit b5b901
    req->addrinfow->ai_flags = hints->ai_flags;
Packit b5b901
    req->addrinfow->ai_addrlen = 0;
Packit b5b901
    req->addrinfow->ai_canonname = NULL;
Packit b5b901
    req->addrinfow->ai_addr = NULL;
Packit b5b901
    req->addrinfow->ai_next = NULL;
Packit b5b901
  } else {
Packit b5b901
    req->addrinfow = NULL;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  uv__req_register(loop, req);
Packit b5b901
Packit b5b901
  if (getaddrinfo_cb) {
Packit b5b901
    uv__work_submit(loop,
Packit b5b901
                    &req->work_req,
Packit b5b901
                    UV__WORK_SLOW_IO,
Packit b5b901
                    uv__getaddrinfo_work,
Packit b5b901
                    uv__getaddrinfo_done);
Packit b5b901
    return 0;
Packit b5b901
  } else {
Packit b5b901
    uv__getaddrinfo_work(&req->work_req);
Packit b5b901
    uv__getaddrinfo_done(&req->work_req, 0);
Packit b5b901
    return req->retcode;
Packit b5b901
  }
Packit b5b901
Packit b5b901
error:
Packit b5b901
  if (req != NULL) {
Packit b5b901
    uv__free(req->alloc);
Packit b5b901
    req->alloc = NULL;
Packit b5b901
  }
Packit b5b901
  return uv_translate_sys_error(err);
Packit b5b901
}
Packit b5b901
Packit b5b901
int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) {
Packit b5b901
  NET_LUID luid;
Packit b5b901
  wchar_t wname[NDIS_IF_MAX_STRING_SIZE + 1]; /* Add one for the NUL. */
Packit b5b901
  DWORD bufsize;
Packit b5b901
  int r;
Packit b5b901
Packit b5b901
  if (buffer == NULL || size == NULL || *size == 0)
Packit b5b901
    return UV_EINVAL;
Packit b5b901
Packit b5b901
  r = ConvertInterfaceIndexToLuid(ifindex, &luid);
Packit b5b901
Packit b5b901
  if (r != 0)
Packit b5b901
    return uv_translate_sys_error(r);
Packit b5b901
Packit b5b901
  r = ConvertInterfaceLuidToNameW(&luid, wname, ARRAY_SIZE(wname));
Packit b5b901
Packit b5b901
  if (r != 0)
Packit b5b901
    return uv_translate_sys_error(r);
Packit b5b901
Packit b5b901
  /* Check how much space we need */
Packit b5b901
  bufsize = WideCharToMultiByte(CP_UTF8, 0, wname, -1, NULL, 0, NULL, NULL);
Packit b5b901
Packit b5b901
  if (bufsize == 0) {
Packit b5b901
    return uv_translate_sys_error(GetLastError());
Packit b5b901
  } else if (bufsize > *size) {
Packit b5b901
    *size = bufsize;
Packit b5b901
    return UV_ENOBUFS;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* Convert to UTF-8 */
Packit b5b901
  bufsize = WideCharToMultiByte(CP_UTF8,
Packit b5b901
                                0,
Packit b5b901
                                wname,
Packit b5b901
                                -1,
Packit b5b901
                                buffer,
Packit b5b901
                                *size,
Packit b5b901
                                NULL,
Packit b5b901
                                NULL);
Packit b5b901
Packit b5b901
  if (bufsize == 0)
Packit b5b901
    return uv_translate_sys_error(GetLastError());
Packit b5b901
Packit b5b901
  *size = bufsize - 1;
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) {
Packit b5b901
  int r;
Packit b5b901
Packit b5b901
  if (buffer == NULL || size == NULL || *size == 0)
Packit b5b901
    return UV_EINVAL;
Packit b5b901
Packit b5b901
  r = snprintf(buffer, *size, "%d", ifindex);
Packit b5b901
Packit b5b901
  if (r < 0)
Packit b5b901
    return uv_translate_sys_error(r);
Packit b5b901
Packit b5b901
  if (r >= (int) *size) {
Packit b5b901
    *size = r + 1;
Packit b5b901
    return UV_ENOBUFS;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  *size = r;
Packit b5b901
  return 0;
Packit b5b901
}