/* SCTP kernel Implementation: User API extensions.
*
* addrs.c
*
* Distributed under the terms of the LGPL v2.1 as described in
* http://www.gnu.org/copyleft/lesser.txt
*
* This file is part of the user library that offers support for the
* SCTP kernel Implementation. The main purpose of this
* code is to provide the SCTP Socket API mappings for user
* application to interface with the SCTP in kernel.
*
* This implementation is based on the Socket API Extensions for SCTP
* defined in <draft-ietf-tsvwg-sctpsocket-10.txt.
*
* (C) Copyright IBM Corp. 2003
* Copyright (c) 2001-2002 Intel Corp.
*
* Written or modified by:
* Ardelle Fan <ardelle.fan@intel.com>
* Sridhar Samudrala <sri@us.ibm.com>
* Ivan Skytte Jørgensen <isj-sctp@i1.dk>
*/
#include <malloc.h>
#include <netinet/in.h>
#include <netinet/sctp.h>
#include <string.h>
#include <errno.h>
/*
* Common getsockopt() layer
* If the NEW getsockopt() API fails this function will fall back to using
* the old API
*/
static int
sctp_getaddrs(int sd, sctp_assoc_t id, int optname_new,
struct sockaddr **addrs)
{
int cnt, err;
socklen_t len;
size_t bufsize = 4096; /*enough for most cases*/
struct sctp_getaddrs *getaddrs = (struct sctp_getaddrs*)malloc(bufsize);
if(!getaddrs)
return -1;
for(;;) {
char *new_buf;
len = bufsize;
getaddrs->assoc_id = id;
err = getsockopt(sd, SOL_SCTP, optname_new, getaddrs, &len);
if (err == 0) {
/*got it*/
break;
}
if (errno != ENOMEM ) {
/*unknown error*/
free(getaddrs);
return -1;
}
/*expand buffer*/
if (bufsize > 128*1024) {
/*this is getting ridiculous*/
free(getaddrs);
errno = ENOBUFS;
return -1;
}
new_buf = realloc(getaddrs, bufsize+4096);
if (!new_buf) {
free(getaddrs);
return -1;
}
bufsize += 4096;
getaddrs = (struct sctp_getaddrs*)new_buf;
}
/* we skip traversing the list, allocating a new buffer etc. and enjoy
* a simple hack*/
cnt = getaddrs->addr_num;
memmove(getaddrs, getaddrs + 1, len);
*addrs = (struct sockaddr*)getaddrs;
return cnt;
} /* sctp_getaddrs() */
/* Get all peer address on a socket. This is a new SCTP API
* described in the section 8.3 of the Sockets API Extensions for SCTP.
* This is implemented using the getsockopt() interface.
*/
int
sctp_getpaddrs(int sd, sctp_assoc_t id, struct sockaddr **addrs)
{
return sctp_getaddrs(sd, id,
SCTP_GET_PEER_ADDRS,
addrs);
} /* sctp_getpaddrs() */
/* Frees all resources allocated by sctp_getpaddrs(). This is a new SCTP API
* described in the section 8.4 of the Sockets API Extensions for SCTP.
*/
int
sctp_freepaddrs(struct sockaddr *addrs)
{
free(addrs);
return 0;
} /* sctp_freepaddrs() */
/* Get all locally bound address on a socket. This is a new SCTP API
* described in the section 8.5 of the Sockets API Extensions for SCTP.
* This is implemented using the getsockopt() interface.
*/
int
sctp_getladdrs(int sd, sctp_assoc_t id, struct sockaddr **addrs)
{
return sctp_getaddrs(sd, id,
SCTP_GET_LOCAL_ADDRS,
addrs);
} /* sctp_getladdrs() */
/* Frees all resources allocated by sctp_getladdrs(). This is a new SCTP API
* described in the section 8.6 of the Sockets API Extensions for SCTP.
*/
int
sctp_freeladdrs(struct sockaddr *addrs)
{
free(addrs);
return 0;
} /* sctp_freeladdrs() */
int
sctp_getaddrlen(sa_family_t family)
{
/* We could call into the kernel to see what it thinks the size should
* be, but hardcoding the address families here is: (a) faster,
* (b) easier, and (c) probably good enough for forseeable future.
*/
switch(family) {
case AF_INET:
return sizeof(struct sockaddr_in);
case AF_INET6:
return sizeof(struct sockaddr_in6);
default:
/* Currently there is no defined error handling in
* draft-ietf-tsvwg-sctpsocket-13.txt.
* -1 might cause the application to overwrite buffer
* or misinterpret data. 0 is more likely to cause
* an endless loop.
*/
return 0;
}
}