Commit 6c2502aa authored by Pekka Pessi's avatar Pekka Pessi
Browse files

Updated (for testing stun).

darcs-hash:20060328115354-88462-ee6a744f7bf1d6e48f36c4306a160b15b2184ffd.gz
parent 65a50ca9
......@@ -23,7 +23,7 @@
*/
/**@CFILE test_nat.c
* @brief Simulated NAT for testing nua
* @brief Simulated NAT for testing
*
* NAT thing works so that we set the outgoing proxy URI to point
* towards its "private" address and give the real address of the proxy
......@@ -38,14 +38,14 @@
#include "config.h"
#include <string.h>
struct nat;
struct binding;
#define SU_ROOT_MAGIC_T struct nat
#define SU_WAKEUP_ARG_T struct binding
#include <sofia-sip/su.h>
#include <sofia-sip/su_errno.h>
#include <sofia-sip/su_wait.h>
#include <sofia-sip/su_tagarg.h>
#include <sofia-sip/su_localinfo.h>
......@@ -53,11 +53,7 @@ struct binding;
#include <stdlib.h>
#include <assert.h>
#if !defined(EADDRNOTAVAIL) && defined(_WIN32)
#define EADDRNOTAVAIL WSAEADDRNOTAVAIL
#endif
#include <string.h>
#define LIST_PROTOS(STORAGE, PREFIX, T) \
STORAGE void PREFIX ##_insert(T **list, T *node), \
......@@ -119,16 +115,29 @@ struct binding
{
struct binding *next, **prev;
struct nat *nat; /* backpointer */
int socktype;
int socktype, protocol;
int in_socket, out_socket;
int in_register, out_register;
int in_closed, out_closed;
char in_name[64], out_name[64];
};
static struct binding *nat_binding_new(struct nat *, int, int, int);
static struct binding *nat_binding_new(struct nat *nat,
char const *protoname,
int socktype, int protocol,
int connected,
int in_socket,
su_sockaddr_t *from,
socklen_t fromlen);
static void nat_binding_destroy(struct binding *);
static int binding_init(struct binding *b,
char const *protoname,
int connected,
su_localinfo_t *li,
su_sockaddr_t *from,
socklen_t fromlen);
static void flush_bindings(struct nat *nat);
static void invalidate_bindings(struct nat *nat);
......@@ -156,6 +165,8 @@ test_nat_init(su_root_t *root, struct nat *nat)
nat->root = root;
nat->udp_socket = -1, nat->tcp_socket = -1;
hints->li_scope = LI_SCOPE_HOST | LI_SCOPE_SITE | LI_SCOPE_GLOBAL;
error = su_getlocalinfo(hints, &nat->localinfo);
if (error) {
fprintf(stderr, "test_nat: su_getlocalinfo: %s\n", su_gli_strerror(error));
......@@ -208,7 +219,7 @@ test_nat_init(su_root_t *root, struct nat *nat)
}
if (getsockname(nat->udp_socket, (void *)su, &sulen) < 0) {
su_perror("nat: bind(udp_socket)");
su_perror("nat: getsockname(udp_socket)");
return -1;
}
......@@ -402,39 +413,145 @@ int test_nat_flush(struct nat *nat)
/* ====================================================================== */
static struct binding *nat_binding_new(struct nat *nat,
int socktype,
int in_socket,
int out_socket)
struct binding *nat_binding_new(struct nat *nat,
char const *protoname,
int socktype,
int protocol,
int connected,
int in_socket,
su_sockaddr_t *from,
socklen_t fromlen)
{
struct binding *b = su_zalloc(nat->home, sizeof *b);
su_sockaddr_t addr[1];
socklen_t addrlen = (sizeof addr);
char name[64];
struct binding *b;
if (b == NULL)
if (nat->fake == NULL) { /* Xyzzy */
fprintf(stderr, "test_nat: fake address missing\n");
su_close(in_socket);
return NULL;
}
nat_binding_insert(&nat->bindings, b);
b = su_zalloc(nat->home, sizeof *b);
if (b == NULL) {
su_perror("nat_binding_new: su_zalloc");
su_close(in_socket);
return 0;
}
b->nat = nat;
b->socktype = socktype;
b->in_socket = in_socket, b->out_socket = out_socket;
b->protocol = protocol;
b->in_socket = in_socket, b->out_socket = -1;
b->in_register = -1, b->out_register = -1;
getpeername(in_socket, (void *)addr, &addrlen);
inet_ntop(addr->su_family, SU_ADDR(addr), name, sizeof name);
if (binding_init(b, protoname, connected, nat->fake, from, fromlen) < 0)
nat_binding_destroy(b), b = NULL;
else
nat_binding_insert(&nat->bindings, b);
return b;
}
static int binding_init(struct binding *b,
char const *protoname,
int connected,
su_localinfo_t *li,
su_sockaddr_t *from,
socklen_t fromlen)
{
struct nat *nat = b->nat;
int out_socket;
su_sockaddr_t addr[1];
socklen_t addrlen = (sizeof addr);
char ipname[64];
su_wait_t wait[1];
su_wakeup_f in_to_out, out_to_in;
if (b->socktype == SOCK_STREAM)
in_to_out = tcp_in_to_out, out_to_in = tcp_out_to_in;
else
in_to_out = udp_in_to_out, out_to_in = udp_out_to_in;
if (b->in_socket == -1) {
int in_socket;
in_socket = su_socket(from->su_family, b->socktype, b->protocol);
if (in_socket < 0) {
su_perror("nat_binding_new: socket");
return -1;
}
b->in_socket = in_socket;
if (su_setreuseaddr(in_socket, 1) < 0) {
su_perror("nat_binding_new: su_setreuseaddr(in_socket)");
return -1;
}
if (bind(in_socket, (void *)nat->in_address, nat->in_addrlen) < 0) {
su_perror("nat_binding_new: bind(in_socket)");
return -1;
}
if (connect(in_socket, (void *)from, fromlen) < 0) {
su_perror("nat_binding_new: connect(in_socket)");
return -1;
}
}
out_socket = su_socket(li->li_family, b->socktype, b->protocol);
if (out_socket < 0) {
su_perror("nat_binding_new: socket");
return -1;
}
b->out_socket = out_socket;
if (bind(out_socket, (void *)li->li_addr, li->li_addrlen) < 0) {
su_perror("nat_binding_new: bind(to)");
return -1;
}
if (connected)
if (connect(out_socket, (void *)nat->out_address, nat->out_addrlen) < 0) {
su_perror("nat_binding_new: connect(to)");
return -1;
}
getpeername(b->in_socket, (void *)addr, &addrlen);
inet_ntop(addr->su_family, SU_ADDR(addr), ipname, sizeof ipname);
snprintf(b->in_name, sizeof b->in_name,
addr->su_family == AF_INET6 ? "[%s]:%u" : "%s:%u",
name, ntohs(addr->su_port));
ipname, ntohs(addr->su_port));
getsockname(out_socket, (void *)addr, &addrlen);
inet_ntop(addr->su_family, SU_ADDR(addr), name, sizeof name);
inet_ntop(addr->su_family, SU_ADDR(addr), ipname, sizeof ipname);
snprintf(b->out_name, sizeof b->out_name,
addr->su_family == AF_INET6 ? "[%s]:%u" : "%s:%u",
name, ntohs(addr->su_port));
ipname, ntohs(addr->su_port));
return b;
nat_binding_insert(&nat->bindings, b);
if (su_wait_create(wait, b->in_socket, SU_WAIT_IN) < 0) {
su_perror("nat_binding_new: su_wait_create");
return -1;
}
b->in_register = su_root_register(nat->root, wait, in_to_out, b, 0);
if (b->in_register < 0) {
su_perror("nat_binding_new: su_root_register");
su_wait_destroy(wait);
return -1;
}
if (su_wait_create(wait, out_socket, SU_WAIT_IN) < 0) {
su_perror("nat_binding_new: su_wait_create");
return -1;
}
b->out_register = su_root_register(nat->root, wait, out_to_in, b, 0);
if (b->out_register < 0) {
su_perror("nat_binding_new: su_root_register");
su_wait_destroy(wait);
return -1;
}
printf("nat: new %s binding %s <=> %s\n",
protoname, b->in_name, b->out_name);
return 0;
}
static void nat_binding_destroy(struct binding *b)
......@@ -470,6 +587,34 @@ static void invalidate_bindings(struct nat *nat)
}
}
#if 0
static struct binding *nat_binding_find(struct nat *nat,
su_sockaddr_t *from,
int fromlen)
{
char name[64], ipname[64];
size_t namelen;
struct binding *b;
inet_ntop(from->su_family, SU_ADDR(from), ipname, sizeof ipname);
snprintf(name, sizeof name,
from->su_family == AF_INET6 ? "[%s]:%u" : "%s:%u",
ipname, ntohs(from->su_port));
namelen = strlen(name) + 1;
for (b = nat->bindings; b; b = b->next) {
if (memcmp(name, b->in_name, namelen) == 0)
return b;
}
if (b == NULL)
b = nat_binding_new(nat, "UDP", SOCK_DGRAM, IPPROTO_UDP, nat->symmetric,
-1, from, fromlen);
return b;
}
#endif
/* ====================================================================== */
LIST_BODIES(static, nat_binding, struct binding, next, prev);
......@@ -483,8 +628,6 @@ static int new_udp(struct nat *nat, su_wait_t *wait, struct binding *dummy)
socklen_t fromlen = (sizeof from);
struct binding *b;
ssize_t n, m;
int in, out;
su_wait_t win[1], wout[1];
events = su_wait_events(wait, nat->udp_socket);
......@@ -495,88 +638,10 @@ static int new_udp(struct nat *nat, su_wait_t *wait, struct binding *dummy)
return 0;
}
if (nat->fake == NULL) { /* Xyzzy */
fprintf(stderr, "test_nat: fake address missing\n");
return -1;
}
in = su_socket(from->su_family, SOCK_DGRAM, IPPROTO_UDP);
if (in < 0) {
su_perror("new_udp: socket");
return 0;
}
if (su_setreuseaddr(in, 1) < 0) {
su_perror("nat: su_setreuseaddr(in)");
su_close(in);
return -1;
}
if (bind(in, (void *)nat->in_address, nat->in_addrlen) < 0) {
su_perror("new_udp: bind(in)");
su_close(in);
return 0;
}
if (connect(in, (void *)from, fromlen) < 0) {
su_perror("new_udp: connect(in)");
su_close(in);
return 0;
}
out = su_socket(nat->fake->li_family, SOCK_DGRAM, IPPROTO_UDP);
if (out < 0) {
su_perror("new_udp: socket");
su_close(in);
return 0;
}
if (bind(out, (void *)nat->fake->li_addr, nat->fake->li_addrlen) < 0) {
su_perror("new_udp: bind(to)");
su_close(in); su_close(out);
return 0;
}
if (nat->symmetric)
if (connect(out, (void *)nat->out_address, nat->out_addrlen) < 0) {
su_perror("new_udp: connect(to)");
su_close(in); su_close(out);
return 0;
}
if (su_wait_create(win, in, SU_WAIT_IN) < 0) {
su_perror("new_udp: su_wait_create");
su_close(in); su_close(out);
return 0;
}
if (su_wait_create(wout, out, SU_WAIT_IN) < 0) {
su_perror("new_udp: su_wait_create");
su_wait_destroy(win);
su_close(in); su_close(out);
return 0;
}
b = nat_binding_new(nat, SOCK_DGRAM, in, out);
if (b == NULL) {
su_perror("new_udp: nat_binding_new");
su_close(in); su_close(out);
return 0;
}
b->in_register = su_root_register(nat->root, win, udp_in_to_out, b, 0);
if (b->in_register < 0) {
su_perror("new_udp: su_root_register");
su_wait_destroy(win); su_wait_destroy(wout);
nat_binding_destroy(b);
return 0;
}
b->out_register = su_root_register(nat->root, wout, udp_out_to_in, b, 0);
if (b->out_register < 0) {
su_perror("new_udp: su_root_register");
su_wait_destroy(wout);
nat_binding_destroy(b);
b = nat_binding_new(nat, "UDP", SOCK_DGRAM, IPPROTO_UDP, nat->symmetric,
-1, from, fromlen);
if (b == NULL)
return 0;
}
printf("nat: new UDP binding %s <=> %s\n", b->in_name, b->out_name);
if (nat->symmetric)
m = send(b->out_socket, nat->buffer, n, 0);
......@@ -641,80 +706,23 @@ static int udp_out_to_in(struct nat *nat, su_wait_t *wait, struct binding *b)
static int new_tcp(struct nat *nat, su_wait_t *wait, struct binding *dummy)
{
int events;
int in_socket;
su_sockaddr_t from[1];
socklen_t fromlen = (sizeof from);
struct binding *b;
int in, out;
su_wait_t win[1], wout[1];
events = su_wait_events(wait, nat->tcp_socket);
in = accept(nat->tcp_socket, (void *)from, &fromlen);
if (in < 0) {
su_perror("new_udp: accept");
in_socket = accept(nat->tcp_socket, (void *)from, &fromlen);
if (in_socket < 0) {
su_perror("new_tcp: accept");
return 0;
}
if (nat->fake == NULL) { /* Xyzzy */
fprintf(stderr, "test_nat: fake address missing\n");
su_close(in);
return -1;
}
out = su_socket(nat->fake->li_family, SOCK_STREAM, IPPROTO_TCP);
if (out < 0) {
su_perror("new_tcp: socket");
su_close(in);
return 0;
}
if (bind(out, (void *)nat->fake->li_addr, nat->fake->li_addrlen) < 0) {
su_perror("new_tcp: bind");
su_close(in); su_close(out);
return 0;
}
if (connect(out, (void *)nat->out_address, nat->out_addrlen) < 0) {
su_perror("new_tcp: connect");
su_close(in); su_close(out);
return 0;
}
if (su_wait_create(win, in, SU_WAIT_IN) < 0) {
su_perror("new_tcp: su_wait_create");
su_close(in); su_close(out);
return 0;
}
if (su_wait_create(wout, out, SU_WAIT_IN) < 0) {
su_perror("new_tcp: su_wait_create");
su_wait_destroy(win);
su_close(in); su_close(out);
return 0;
}
b = nat_binding_new(nat, SOCK_STREAM, in, out);
if (b == NULL) {
su_perror("new_tcp: nat_binding_new");
su_close(in); su_close(out);
return 0;
}
b->in_register = su_root_register(nat->root, win, tcp_in_to_out, b, 0);
if (b->in_register < 0) {
su_perror("new_tcp: su_root_register");
su_wait_destroy(win); su_wait_destroy(wout);
nat_binding_destroy(b);
return 0;
}
b->out_register = su_root_register(nat->root, wout, tcp_out_to_in, b, 0);
if (b->out_register < 0) {
su_perror("new_tcp: su_root_register");
su_wait_destroy(wout);
nat_binding_destroy(b);
b = nat_binding_new(nat, "TCP", SOCK_STREAM, IPPROTO_TCP, 1,
in_socket, from, fromlen);
if (b == NULL)
return 0;
}
printf("nat: new TCP binding %s <=> %s\n", b->in_name, b->out_name);
return 0;
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment