Пример #1
0
/**
 * opens the server socket, which attends (accepts) the clients, that is:
 * params:
 * address:
 * 	address to which to listen
 * port:
 * 	base port to which to listen. then port+1 will be the socket
 * 	for action's delivery.
 * fds:
 * 	in fd[0] the action socket will be put.
 * 	in fd[1] the event socket will be put.
 *
 * returns 0 on exit, <0 on fail
 *
 */
static int open_server_sockets(struct ip_addr *address,unsigned short port,int *fd)
{

   /*using sockaddr_union enables ipv6..*/
   union sockaddr_union su;
   int i,optval;

   fd[0]=fd[1]=-1;

   if(address->af!=AF_INET && address->af!=AF_INET6){
      LM_ERR("Only ip and ipv6 allowed socket types\n");
      return -1;
   }

   for(i=0;i<2;i++){
      if(init_su(&su,address,port+i)<0){
	 LM_ERR("unable to init sockaddr_union\n");
	 return -1;
      }
      if((fd[i]=socket(AF2PF(su.s.sa_family), SOCK_STREAM, 0))==-1){
	 LM_ERR("trying to open server %s socket (%s)\n",i==0?"event":"action",strerror(errno));
	 goto error;
      }
      optval=1;
      if (setsockopt(fd[i], SOL_SOCKET, SO_REUSEADDR, (void*)&optval, sizeof(optval))==-1) {
	 LM_ERR("setsockopt (%s)\n",strerror(errno));
	 goto error;
      }
      if ((bind(fd[i], &su.s,sizeof(union sockaddr_union)))==-1){
	 LM_ERR( "bind (%s)\n",strerror(errno));
	 goto error;
      }
      if (listen(fd[i], 10)==-1){
	 LM_ERR( "listen (%s)\n",strerror(errno));
	 goto error;
      }
   }
   return 0;

error:
   for(i=0;i<2;i++)
      if(fd[i]!=-1){
	 close(fd[i]);
	 fd[i]=-1;
      }
   return -1;
}
Пример #2
0
int tcp_init(struct socket_info* sock_info)
{
	union sockaddr_union* addr;
	int optval;
#ifdef DISABLE_NAGLE
	int flag;
	struct protoent* pe;

	if (tcp_proto_no==-1){ /* if not already set */
		pe=getprotobyname("tcp");
		if (pe==0){
			LOG(L_ERR, "ERROR: tcp_init: could not get TCP protocol number\n");
			tcp_proto_no=-1;
		}else{
			tcp_proto_no=pe->p_proto;
		}
	}
#endif
	
	addr=&sock_info->su;
	sock_info->proto=PROTO_TCP;
	if (init_su(addr, &sock_info->address, sock_info->port_no)<0){
		LOG(L_ERR, "ERROR: tcp_init: could no init sockaddr_union\n");
		goto error;
	}
	sock_info->socket=socket(AF2PF(addr->s.sa_family), SOCK_STREAM, 0);
	if (sock_info->socket==-1){
		LOG(L_ERR, "ERROR: tcp_init: socket: %s\n", strerror(errno));
		goto error;
	}
#ifdef DISABLE_NAGLE
	flag=1;
	if ( (tcp_proto_no!=-1) &&
		 (setsockopt(sock_info->socket, tcp_proto_no , TCP_NODELAY,
					 &flag, sizeof(flag))<0) ){
		LOG(L_ERR, "ERROR: tcp_init: could not disable Nagle: %s\n",
				strerror(errno));
	}
#endif


#if  !defined(TCP_DONT_REUSEADDR) 
	/* Stevens, "Network Programming", Section 7.5, "Generic Socket
     * Options": "...server started,..a child continues..on existing
	 * connection..listening server is restarted...call to bind fails
	 * ... ALL TCP servers should specify the SO_REUSEADDRE option 
	 * to allow the server to be restarted in this situation
	 *
	 * Indeed, without this option, the server can't restart.
	 *   -jiri
	 */
	optval=1;
	if (setsockopt(sock_info->socket, SOL_SOCKET, SO_REUSEADDR,
				(void*)&optval, sizeof(optval))==-1) {
		LOG(L_ERR, "ERROR: tcp_init: setsockopt %s\n",
			strerror(errno));
		goto error;
	}
#endif
	/* tos */
	optval=IPTOS_LOWDELAY;
	if (setsockopt(sock_info->socket, IPPROTO_IP, IP_TOS, (void*)&optval, 
				sizeof(optval)) ==-1){
		LOG(L_WARN, "WARNING: tcp_init: setsockopt tos: %s\n", strerror(errno));
		/* continue since this is not critical */
	}
	if (bind(sock_info->socket, &addr->s, sockaddru_len(*addr))==-1){
		LOG(L_ERR, "ERROR: tcp_init: bind(%x, %p, %d) on %s: %s\n",
				sock_info->socket, &addr->s, 
				sockaddru_len(*addr),
				sock_info->address_str.s,
				strerror(errno));
		goto error;
	}
	if (listen(sock_info->socket, 10)==-1){
		LOG(L_ERR, "ERROR: tcp_init: listen(%x, %p, %d) on %s: %s\n",
				sock_info->socket, &addr->s, 
				sockaddru_len(*addr),
				sock_info->address_str.s,
				strerror(errno));
		goto error;
	}
	
	return 0;
error:
	if (sock_info->socket!=-1){
		close(sock_info->socket);
		sock_info->socket=-1;
	}
	return -1;
}
Пример #3
0
/**
 * Evaluate if next hop is a strict or loose router, by looking at the
 * retr. buffer of the original INVITE.
 * Assumes:
 * 	orig_inv is a parsed SIP message;
 * 	rtset is not NULL.
 * @return:
 * 	F_RB_NH_LOOSE : next hop was loose router;
 * 	F_RB_NH_STRICT: nh is strict;
 * 	0 on error.
 */
static unsigned long nhop_type(sip_msg_t *orig_inv, rte_t *rtset,
		const struct dest_info *dst_inv, str *contact)
{
	struct sip_uri puri, topr_uri, lastr_uri, inv_ruri, cont_uri;
	struct ip_addr *uri_ia;
	union sockaddr_union uri_sau;
	unsigned int uri_port, dst_port, inv_port, cont_port, lastr_port;
	rte_t *last_r;
#ifdef TM_LOC_ACK_DO_REV_DNS
	struct ip_addr ia;
	struct hostent *he;
	char **alias;
#endif

#define PARSE_URI(_str_, _uri_) \
	do { \
		/* parse_uri() 0z the puri */ \
		if (parse_uri((_str_)->s, \
				(_str_)->len, _uri_) < 0) { \
			LM_ERR("failed to parse route body '%.*s'.\n", STR_FMT(_str_)); \
			return 0; \
		} \
	} while (0)

#define HAS_LR(_rte_) \
	({ \
		PARSE_URI(&(_rte_)->ptr->nameaddr.uri, &puri); \
		puri.lr.s; \
	})

#define URI_PORT(_puri_, _port) \
	do { \
		if (! (_port = uri2port(_puri_))) \
			return 0; \
	} while (0)

	/* examine the easy/fast & positive cases foremost */

	/* [1] check if 1st route lacks ;lr */
	LM_DBG("checking lack of ';lr' in 1st route.\n");
	if (! HAS_LR(rtset))
		return F_RB_NH_STRICT;
	topr_uri = puri; /* save 1st route's URI */

	/* [2] check if last route shows ;lr */
	LM_DBG("checking presence of ';lr' in last route.\n");
	for (last_r = rtset; last_r->next; last_r = last_r->next)
		/* scroll down to last route */
		;
	if (HAS_LR(last_r))
		return F_RB_NH_LOOSE;

	/* [3] 1st route has ;lr -> check if the destination of original INV
	 * equals the address provided by this route; if does -> loose */
	LM_DBG("checking INVITE's destination against its first route.\n");
	URI_PORT(&topr_uri, uri_port);
	if (! (dst_port = su_getport(&dst_inv->to)))
		return 0; /* not really expected */
	if (dst_port != uri_port)
		return F_RB_NH_STRICT;
	/* if 1st route contains an IP address, comparing it against .dst */
	if ((uri_ia = str2ip(&topr_uri.host))
			|| (uri_ia = str2ip6(&topr_uri.host))
			) {
		/* we have an IP address in route -> comparison can go swiftly */
		if (init_su(&uri_sau, uri_ia, uri_port) < 0)
			return 0; /* not really expected */
		if (su_cmp(&uri_sau, &dst_inv->to))
			/* ;lr and sent there */
			return F_RB_NH_LOOSE;
		else
			/* ;lr and NOT sent there (probably sent to RURI address) */
			return F_RB_NH_STRICT;
	} else {
		/*if 1st route contains a name, rev resolve the .dst and compare*/
		LM_INFO("Failed to decode string '%.*s' in route set element as IP"
				" address. Trying name resolution.\n",STR_FMT(&topr_uri.host));

	/* TODO: alternatively, rev name and compare against dest. IP.  */
#ifdef TM_LOC_ACK_DO_REV_DNS
		ia.af = 0;
		su2ip_addr(&ia, (void *)&dst_inv->to);
		if (! ia.af)
			return 0; /* not really expected */
		if ((he = rev_resolvehost(&ia))) {
			if ((strlen(he->h_name) == topr_uri.host.len) &&
					(memcmp(he->h_name, topr_uri.host.s,
							topr_uri.host.len) == 0))
				return F_RB_NH_LOOSE;
			for (alias = he->h_aliases; *alias; alias ++)
				if ((strlen(*alias) == topr_uri.host.len) &&
						(memcmp(*alias, topr_uri.host.s,
								topr_uri.host.len) == 0))
					return F_RB_NH_LOOSE;
			return F_RB_NH_STRICT;
		} else {
			LM_INFO("failed to resolve address '%s' to a name.\n",
					ip_addr2a(&ia));
		}
#endif
	}

	LM_WARN("failed to establish with certainty the type of next hop;"
			" trying an educated guess.\n");

	/* [4] compare (possibly updated) remote target to original RURI; if
	 * equal, a strict router's address wasn't filled in as RURI -> loose */
	LM_DBG("checking remote target against INVITE's RURI.\n");
	PARSE_URI(contact, &cont_uri);
	PARSE_URI(GET_RURI(orig_inv), &inv_ruri);
	URI_PORT(&cont_uri, cont_port);
	URI_PORT(&inv_ruri, inv_port);
	if ((cont_port == inv_port) && (cont_uri.host.len == inv_ruri.host.len) &&
			(memcmp(cont_uri.host.s, inv_ruri.host.s, cont_uri.host.len) == 0))
		return F_RB_NH_LOOSE;

	/* [5] compare (possibly updated) remote target to last route; if equal,
	 * strict router's address might have been filled as RURI and remote
	 * target appended to route set -> strict */
	LM_DBG("checking remote target against INVITE's last route.\n");
	PARSE_URI(&last_r->ptr->nameaddr.uri, &lastr_uri);
	URI_PORT(&lastr_uri, lastr_port);
	if ((cont_port == lastr_port) &&
			(cont_uri.host.len == lastr_uri.host.len) &&
			(memcmp(cont_uri.host.s, lastr_uri.host.s,
					lastr_uri.host.len) == 0))
		return F_RB_NH_STRICT;

	LM_WARN("failed to establish the type of next hop;"
			" assuming loose router.\n");
	return F_RB_NH_LOOSE;

#undef PARSE_URI
#undef HAS_LR
#undef URI_PORT
}
Пример #4
0
/** create and return a raw socket.
 * @param proto - protocol used (e.g. IPPROTO_UDP, IPPROTO_RAW)
 * @param ip - if not null the socket will be bound on this ip.
 * @param iface - if not null the socket will be bound to this interface
 *                (SO_BINDTODEVICE). This is supported only on linux.
 * @param iphdr_incl - set to 1 if packets send on this socket include
 *                     a pre-built ip header (some fields, like the checksum
 *                     will still be filled by the kernel, OTOH packet
 *                     fragmentation has to be done in user space).
 * @return socket on success, -1 on error
 */
int raw_socket(int proto, struct ip_addr* ip, str* iface, int iphdr_incl)
{
	int sock;
	int t;
	union sockaddr_union su;
#if defined (SO_BINDTODEVICE)
	char short_ifname[sizeof(int)];
	int ifname_len;
	char* ifname;
#endif /* SO_BINDTODEVICE */

	sock = socket(PF_INET, SOCK_RAW, proto);
	if (sock==-1)
		goto error;
	/* set socket options */
	if (iphdr_incl) {
		t=1;
		if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &t, sizeof(t))<0){
			ERR("raw_socket: setsockopt(IP_HDRINCL) failed: %s [%d]\n",
					strerror(errno), errno);
			goto error;
		}
	} else {
		/* IP_PKTINFO makes no sense if the ip header is included */
		/* using IP_PKTINFO */
		t=1;
#ifdef IP_PKTINFO
		if (setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &t, sizeof(t))<0){
			ERR("raw_socket: setsockopt(IP_PKTINFO) failed: %s [%d]\n",
					strerror(errno), errno);
			goto error;
		}
#elif defined(IP_RECVDSTADDR)
		if (setsockopt(sock, IPPROTO_IP, IP_RECVDSTADDR, &t, sizeof(t))<0){
			ERR("raw_socket: setsockop(IP_RECVDSTADDR) failed: %s [%d]\n",
					strerror(errno), errno);
			goto error;
		}
#else
#error "no method of getting the destination ip address supported"
#endif /* IP_RECVDSTADDR / IP_PKTINFO */
	}
#if defined (IP_MTU_DISCOVER) && defined (IP_PMTUDISC_DONT)
	t=IP_PMTUDISC_DONT;
	if(setsockopt(sock, IPPROTO_IP, IP_MTU_DISCOVER, &t, sizeof(t)) ==-1){
		ERR("raw_socket: setsockopt(IP_MTU_DISCOVER): %s\n",
				strerror(errno));
		goto error;
	}
#endif /* IP_MTU_DISCOVER && IP_PMTUDISC_DONT */
	if (iface && iface->s){
#if defined (SO_BINDTODEVICE)
		/* workaround for linux bug: arg to setsockopt must have at least
		 * sizeof(int) size or EINVAL would be returned */
		if (iface->len<sizeof(int)){
			memcpy(short_ifname, iface->s, iface->len);
			short_ifname[iface->len]=0; /* make sure it's zero term */
			ifname_len=sizeof(short_ifname);
			ifname=short_ifname;
		}else{
			ifname_len=iface->len;
			ifname=iface->s;
		}
		if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, ifname, ifname_len)
						<0){
				ERR("raw_socket: could not bind to %.*s: %s [%d]\n",
							iface->len, ZSW(iface->s), strerror(errno), errno);
				goto error;
		}
#else /* !SO_BINDTODEVICE */
		/* SO_BINDTODEVICE is linux specific => cannot bind to a device */
		ERR("raw_socket: bind to device supported only on linux\n");
		goto error;
#endif /* SO_BINDTODEVICE */
	}
	/* FIXME: probe_max_receive_buffer(sock) missing */
	if (ip){
		init_su(&su, ip, 0);
		if (bind(sock, &su.s, sockaddru_len(su))==-1){
			ERR("raw_socket: bind(%s) failed: %s [%d]\n",
				ip_addr2a(ip), strerror(errno), errno);
			goto error;
		}
	}
	return sock;
error:
	if (sock!=-1) close(sock);
	return -1;
}
Пример #5
0
/* initializes an already defined TCP listener */
int tcp_init_listener(struct socket_info *si)
{
	union sockaddr_union* addr;
	int optval;
#ifdef DISABLE_NAGLE
	int flag;
	struct protoent* pe;

	if (tcp_proto_no==-1){ /* if not already set */
		pe=getprotobyname("tcp");
		if (pe==0){
			LM_ERR("could not get TCP protocol number\n");
			tcp_proto_no=-1;
		}else{
			tcp_proto_no=pe->p_proto;
		}
	}
#endif

	addr = &si->su;
	if (init_su(addr, &si->address, si->port_no)<0){
		LM_ERR("could no init sockaddr_union\n");
		goto error;
	}
	si->socket = socket(AF2PF(addr->s.sa_family), SOCK_STREAM, 0);
	if (si->socket==-1){
		LM_ERR("socket failed with [%s]\n", strerror(errno));
		goto error;
	}
#ifdef DISABLE_NAGLE
	flag=1;
	if ( (tcp_proto_no!=-1) &&
		 (setsockopt(si->socket, tcp_proto_no , TCP_NODELAY,
					 &flag, sizeof(flag))<0) ){
		LM_ERR("could not disable Nagle: %s\n",strerror(errno));
	}
#endif

#if  !defined(TCP_DONT_REUSEADDR)
	/* Stevens, "Network Programming", Section 7.5, "Generic Socket
	 * Options": "...server started,..a child continues..on existing
	 * connection..listening server is restarted...call to bind fails
	 * ... ALL TCP servers should specify the SO_REUSEADDRE option
	 * to allow the server to be restarted in this situation
	 */
	optval=1;
	if (setsockopt(si->socket, SOL_SOCKET, SO_REUSEADDR,
	(void*)&optval, sizeof(optval))==-1) {
		LM_ERR("setsockopt failed with [%s]\n", strerror(errno));
		goto error;
	}
#endif
	/* tos */
	optval = tos;
	if (setsockopt(si->socket, IPPROTO_IP, IP_TOS, (void*)&optval,
	sizeof(optval)) ==-1){
		LM_WARN("setsockopt tos: %s\n", strerror(errno));
		/* continue since this is not critical */
	}

	if (probe_max_sock_buff(si->socket,1,MAX_SEND_BUFFER_SIZE,
	BUFFER_INCREMENT)) {
		LM_WARN("setsockopt tcp snd buff: %s\n",strerror(errno));
		/* continue since this is not critical */
	}

	init_sock_keepalive(si->socket);
	if (bind(si->socket, &addr->s, sockaddru_len(*addr))==-1){
		LM_ERR("bind(%x, %p, %d) on %s:%d : %s\n",
 				si->socket, &addr->s,
 				(unsigned)sockaddru_len(*addr),
 				si->address_str.s,
				si->port_no,
 				strerror(errno));
		goto error;
	}
	if (listen(si->socket, tcp_listen_backlog)==-1){
		LM_ERR("listen(%x, %p, %d) on %s: %s\n",
				si->socket, &addr->s,
				(unsigned)sockaddru_len(*addr),
				si->address_str.s,
				strerror(errno));
		goto error;
	}

	return 0;
error:
	if (si->socket!=-1){
		close(si->socket);
		si->socket=-1;
	}
	return -1;
}
Пример #6
0
int sctp_server_init(struct socket_info* sock_info)
{
	union sockaddr_union* addr;
	int optval;

	addr=&sock_info->su;
	sock_info->proto=PROTO_SCTP;
	if (init_su(addr, &sock_info->address, sock_info->port_no)<0){
		LM_ERR("could not init sockaddr_union\n");
		goto error;
	}
	
	sock_info->socket = socket(AF2PF(addr->s.sa_family), SOCK_SEQPACKET, 0);
	if (sock_info->socket==-1){
		LM_ERR("socket: %s [%d]\n", strerror(errno), errno);
		goto error;
	}
	
	optval=1;
	if (setsockopt(sock_info->socket, SOL_SOCKET, SO_REUSEADDR ,
					(void*)&optval, sizeof(optval)) ==-1){
		LM_ERR("setsockopt: %s\n", strerror(errno));
		goto error;
	}

#ifdef DISABLE_NAGLE
	/* turns of Nagle-like algorithm/chunk-bundling.*/
	optval=1;
	if (setsockopt(sock_info->socket, IPPROTO_SCTP, SCTP_NODELAY, 
				(void*)&optval, sizeof(optval))==-1){
		LM_WARN("setsockopt %s\n", strerror(errno));
	/* continues since this is not critical */
	}
#endif

	/* tos */
	
	/* this sockopt causes a kernel panic in some sctp implementations.
	 * commenting it out. -gmarmon */
	
	/*
	optval=tos;
	if (setsockopt(sock_info->socket, IPPROTO_IP, IP_TOS, (void*)&optval, 
			sizeof(optval)) ==-1){
		LM_WARN("setsockopt tos: %s\n", strerror(errno));
	}
    */

#if defined (__linux__) && defined(SCTP_ERRORS)
	/* will SCTP_ERRORS ever be defined? -gmarmon */
	optval=1;
	/* enable error receiving on unconnected sockets */
	if(setsockopt(sock_info->socket, SOL_IP, IP_RECVERR,
		      (void*)&optval, sizeof(optval)) ==-1){
		LM_ERR("setsockopt: %s\n", strerror(errno));
		goto error;
	}
#endif

	/*if ( probe_max_receive_buffer(sock_info->socket)==-1) goto error;
	 */
	
	if (bind(sock_info->socket, &addr->s, sockaddru_len(*addr))==-1){
		LM_ERR("bind(%x, %p, %d) on %s: %s\n",
				sock_info->socket, &addr->s, 
				(unsigned)sockaddru_len(*addr),
				sock_info->address_str.s,
				strerror(errno));
	#ifdef USE_IPV6
		if (addr->s.sa_family==AF_INET6)
			LM_ERR("might be caused by using a link "
					" local address, try site local or global\n");
	#endif
		goto error;
	}
	if(listen(sock_info->socket, LISTEN_BACKLOG)<0){
		LM_ERR("listen(%x, %d) on %s: %s\n",
				sock_info->socket,
				LISTEN_BACKLOG, 
				sock_info->address_str.s, 
				strerror(errno));
		goto error;
	}
/*	pkg_free(addr);*/
	return 0;

error:
/*	if (addr) pkg_free(addr);*/
	return -1;
}