⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 test_nat.c

📁 Internet Phone, Chat, Conferencing
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * This file is part of the Sofia-SIP package * * Copyright (C) 2005 Nokia Corporation. * * Contact: Pekka Pessi <pekka.pessi@nokia.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * *//**@CFILE test_nat.c * @brief Simulated NAT for testing nua * * 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 * as its "public" address. If we use different IP families here, we may * even manage to test real connectivity problems as proxy and endpoint * can not talk to each other. * * @author Pekka Pessi <Pekka.Pessi@nokia.com> * * @date Created: Wed Mar  8 19:54:28 EET 2006 */#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_wait.h>#include <sofia-sip/su_tagarg.h>#include <sofia-sip/su_localinfo.h>#include <sofia-sip/su_log.h>#include <stdlib.h>#include <assert.h>#if !defined(EADDRNOTAVAIL) && defined(_WIN32)#define EADDRNOTAVAIL WSAEADDRNOTAVAIL#endif#define LIST_PROTOS(STORAGE, PREFIX, T)			 \STORAGE void PREFIX ##_insert(T **list, T *node),	 \        PREFIX ##_remove(T *node)#define LIST_BODIES(STORAGE, PREFIX, T, NEXT, PREV)	  \STORAGE void PREFIX ##_insert(T **list, T *node)   \{							 \  if ((node->NEXT = *list)) {				 \    node->PREV = node->NEXT->PREV;			 \    node->NEXT->PREV = &node->NEXT;			 \  }							 \  else							 \    node->PREV = list;					 \  *list = node;						 \}							 \STORAGE void PREFIX ##_remove(T *node)			 \{							 \  if (node->PREV)					 \    if ((*node->PREV = node->NEXT))			 \      node->NEXT->PREV = node->PREV;			 \  node->PREV = NULL;					 \}							 \extern int LIST_DUMMY_VARIABLE#include <test_nat.h>struct nat {  su_home_t    home[1];  su_root_t   *parent;  su_clone_r   clone;  tagi_t      *tags;  su_root_t   *root;  struct binding *bindings;  /* True if we act in symmetric way */  int symmetric;  /* Everything sent to in_address will be forwarded to out_address */  su_sockaddr_t in_address[1], out_address[1];  socklen_t in_addrlen, out_addrlen;  int family;			/* Preferred private family */  /* ...but source address will be "fake" */  su_localinfo_t *localinfo, *private, *fake;  int udp_socket, tcp_socket;  int udp_register, tcp_register;  char buffer[65536];};LIST_PROTOS(static, nat_binding, struct binding);struct binding{  struct binding *next, **prev;  struct nat *nat;		/* backpointer */  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);static void nat_binding_destroy(struct binding *);static int new_udp(struct nat *, su_wait_t *wait, struct binding *dummy);static int udp_in_to_out(struct nat *, su_wait_t *wait, struct binding *);static int udp_out_to_in(struct nat *, su_wait_t *wait, struct binding *);static int new_tcp(struct nat *, su_wait_t *wait, struct binding *dummy);static int tcp_in_to_out(struct nat *, su_wait_t *wait, struct binding *);static int tcp_out_to_in(struct nat *, su_wait_t *wait, struct binding *);/* nat entry point */static inttest_nat_init(su_root_t *root, struct nat *nat){  su_localinfo_t *li, hints[1] = {{ 0 }};  int error;  unsigned port = 0, port0 = 0;  su_sockaddr_t *su;  socklen_t sulen;  su_wait_t wait[1];  nat->root = root;  nat->udp_socket = -1, nat->tcp_socket = -1;  error = su_getlocalinfo(hints, &nat->localinfo);  if (error) {    fprintf(stderr, "test_nat: su_getlocalinfo: %s\n", su_gli_strerror(error));    return -1;  }  /* We must have two different IP addresses. */  if (!nat->localinfo || !nat->localinfo->li_next) {    fprintf(stderr, "test_nat: only one IP address available\n");    return -1;  }  for (li = nat->localinfo; li; li = li->li_next) {    if (nat->family == 0 || nat->family == li->li_family)      break;  }  if (li == NULL)    li = nat->localinfo;  su = memcpy(nat->in_address, li->li_addr, sulen = li->li_addrlen);  nat->private = li;  /* Bind TCP and UDP to same port */  for (;;) {    nat->udp_socket = su_socket(li->li_family, SOCK_DGRAM, IPPROTO_UDP);    if (nat->udp_socket == -1)      return -1;    if (bind(nat->udp_socket, (void *)su, sulen) < 0) {      if (port0 == 0) {	su_perror("nat: bind(udp_socket)");	return -1;      }      fprintf(stderr, "test_nat: port %u: %s\n",	      port, su_strerror(su_errno()));      su_close(nat->udp_socket);      nat->udp_socket = -1;      if (++port > 65535)	port = 1024;      if (port == port0) {	fprintf(stderr, "test_nat: could not find free port pairt\n");	return -1;      }      continue;    }    if (getsockname(nat->udp_socket, (void *)su, &sulen) < 0) {      su_perror("nat: bind(udp_socket)");      return -1;    }    if (port0 == 0) {      port = port0 = ntohs(su->su_port);      if (port0 == 0) {	fprintf(stderr, "test_nat: bind did not return port\n");	return -1;      }    }    nat->tcp_socket = su_socket(li->li_family, SOCK_STREAM, IPPROTO_TCP);    if (nat->tcp_socket == -1)      return -1;    if (bind(nat->tcp_socket, (void *)su, sulen) < 0) {      su_close(nat->tcp_socket);      nat->tcp_socket = -1;      fprintf(stderr, "test_nat: port %u: %s\n",	      port, su_strerror(su_errno()));      if (++port > 65535)	port = 1024;      if (port == port0) {	fprintf(stderr, "test_nat: could not find free port pair\n");	return -1;      }      continue;    }    break;  }  nat->in_addrlen = sulen;  if (su_setreuseaddr(nat->udp_socket, 1) < 0) {    su_perror("nat: su_setreuseaddr(udp_socket)");    return -1;  }  if (listen(nat->tcp_socket, 5) < 0) {    su_perror("nat: listen(tcp_socket)");    return -1;  }  if (su_wait_create(wait, nat->udp_socket, SU_WAIT_IN) < 0) {    su_perror("nat: su_wait_create");    return -1;  }  nat->udp_register = su_root_register(root, wait, new_udp, NULL, 0);  if (nat->udp_register < 0) {    su_perror("nat: su_root_register");    return -1;  }  if (su_wait_create(wait, nat->tcp_socket, SU_WAIT_IN) < 0) {    su_perror("nat: su_wait_create");    return -1;  }  nat->tcp_register = su_root_register(root, wait, new_tcp, NULL, 0);  if (nat->tcp_register < 0) {    su_perror("nat: su_root_register");    return -1;  }  return 0;}static voidtest_nat_deinit(su_root_t *root, struct nat *nat){  struct binding *b;  for (b = nat->bindings; b; b = b->next) {    if (b->in_register)      su_root_deregister(root, b->in_register);    su_close(b->in_socket);    if (b->out_register)      su_root_deregister(root, b->in_register);    su_close(b->out_socket);  }  if (nat->udp_socket != -1)    su_close(nat->udp_socket);  if (nat->tcp_socket != -1)    su_close(nat->tcp_socket);  su_freelocalinfo(nat->localinfo);  free(nat->tags);}struct nat *test_nat_create(su_root_t *root,			    int family,			    tag_type_t tag, tag_value_t value, ...){  struct nat *nat = su_home_new(sizeof *nat);  if (nat) {    ta_list ta;    nat->parent = root;    nat->family = family;    ta_start(ta, tag, value);    nat->tags = tl_llist(ta_tags(ta));    ta_end(ta);    if (su_clone_start(root,		       nat->clone,		       nat,		       test_nat_init,		       test_nat_deinit) == -1)      su_home_unref(nat->home), nat = NULL;  }  return nat;}void test_nat_destroy(struct nat *nat){  if (nat) {    su_clone_wait(nat->parent, nat->clone);    su_home_unref(nat->home);  }}/** Get "private" address. */int test_nat_private(struct nat *nat, void *address, int *return_addrlen){  if (nat == NULL || address == NULL || return_addrlen == NULL)    return su_seterrno(EFAULT);  if (*return_addrlen < nat->in_addrlen)    return su_seterrno(EINVAL);  memcpy(address, nat->in_address, *return_addrlen = nat->in_addrlen);  return 0;}/** Set "public" address. */int test_nat_public(struct nat *nat, void const *address, int addrlen){  su_sockaddr_t const *su = address;  su_localinfo_t *li;  if (nat == NULL)    return su_seterrno(EFAULT);  if (address == NULL) {    nat->fake = NULL;    return 0;  }  if (addrlen > sizeof nat->out_address)    return su_seterrno(EINVAL);  for (li = nat->localinfo; li; li = li->li_next) {    if (li != nat->private &&	li->li_scope == LI_SCOPE_HOST &&	li->li_family == su->su_family)      break;  }  if (li == NULL)    for (li = nat->localinfo; li; li = li->li_next) {      if (li != nat->private && li->li_family == su->su_family)	break;    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -