Esempio n. 1
0
/** receives an ipv4 packet using a raw socket.
 * An ipv4 packet is received in buf, using IP_PKTINFO or IP_RECVDSTADDR.
 * from and to are filled (only the ip part the ports are 0 since this
 * function doesn't try to look beyond the IP level).
 * @param sock - raw socket
 * @param buf - detination buffer.
 * @param len - buffer len (should be enough for receiving a packet +
 *               IP header).
 * @param from - result parameter, the IP address part of it will be filled
 *                with the source address and the port with 0.
 * @param to - result parameter, the IP address part of it will be filled
 *                with the destination (local) address and the port with 0.
 * @return packet len or <0 on error: -1 (check errno),
 *        -2 no IP_PKTINFO/IP_RECVDSTADDR found or AF mismatch
 */
int recvpkt4(int sock, char* buf, int len, union sockaddr_union* from,
					union sockaddr_union* to)
{
	struct iovec iov[1];
	struct msghdr rcv_msg;
	struct cmsghdr* cmsg;
#ifdef IP_PKTINFO
	struct in_pktinfo* rcv_pktinfo;
#endif /* IP_PKTINFO */
	int n, ret;
	char msg_ctrl_buf[1024];

	iov[0].iov_base=buf;
	iov[0].iov_len=len;
	rcv_msg.msg_name=from;
	rcv_msg.msg_namelen=sockaddru_len(*from);
	rcv_msg.msg_control=msg_ctrl_buf;
	rcv_msg.msg_controllen=sizeof(msg_ctrl_buf);
	rcv_msg.msg_iov=&iov[0];
	rcv_msg.msg_iovlen=1;
	ret=-2; /* no PKT_INFO or AF mismatch */
retry:
	n=recvmsg(sock, &rcv_msg, MSG_WAITALL);
	if (unlikely(n==-1)){
		if (errno==EINTR)
			goto retry;
		ret=n;
		goto end;
	}
	/* find the pkt info */
	for (cmsg=CMSG_FIRSTHDR(&rcv_msg); cmsg; cmsg=CMSG_NXTHDR(&rcv_msg, cmsg)){
#ifdef IP_PKTINFO
		if (likely((cmsg->cmsg_level==IPPROTO_IP) &&
					(cmsg->cmsg_type==IP_PKTINFO))) {
			rcv_pktinfo=(struct in_pktinfo*)CMSG_DATA(cmsg);
			to->sin.sin_family=AF_INET;
			memcpy(&to->sin.sin_addr, &rcv_pktinfo->ipi_spec_dst.s_addr, 
									sizeof(to->sin.sin_addr));
			to->sin.sin_port=0; /* not known */
			/* interface no. in ipi_ifindex */
			ret=n; /* success */
			break;
		}
#elif defined (IP_RECVDSTADDR)
		if (likely((cmsg->cmsg_level==IPPROTO_IP) &&
					(cmsg->cmsg_type==IP_RECVDSTADDR))) {
			to->sin.sin_family=AF_INET;
			memcpy(&to->sin.sin_addr, CMSG_DATA(cmsg),
									sizeof(to->sin.sin_addr));
			to->sin.sin_port=0; /* not known */
			ret=n; /* success */
			break;
		}
#else
#error "no method of getting the destination ip address supported"
#endif /* IP_PKTINFO / IP_RECVDSTADDR */
	}
end:
	return ret;
}
Esempio n. 2
0
static int jsonrpc_get_fd(union sockaddr_union *addr)
{
	int fd;
	int flags;

	/* writing the iov on the network */
	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
		LM_ERR("cannot create socket\n");
		return -1;
	}

	/* mark the socket as non-blocking after connect :) */
	flags = fcntl(fd, F_GETFL);
	if (flags == -1) {
		LM_ERR("fcntl failed: %s\n", strerror(errno));
		goto close;
	}
	if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
		LM_ERR("fcntl: set non-blocking failed: %s\n", strerror(errno));
		goto close;
	}

	if (tcp_connect_blocking_timeout(fd, &addr->s,
			sockaddru_len(*addr), jrpc_connect_timeout) < 0) {
		LM_ERR("cannot connect to %s[%d:%s]\n",
				inet_ntoa(addr->sin.sin_addr),
				errno, strerror(errno));
		goto close;
	}
	return fd;
close:
	shutdown(fd, SHUT_RDWR);
	close(fd);
	return -1;
}
Esempio n. 3
0
/*! \brief which socket to use? main socket or new one? */
int sctp_server_send(struct socket_info *source, char *buf, unsigned len,
										union sockaddr_union*  to)
{
	int n;
	int tolen;

	tolen=sockaddru_len(*to);
again:
	n=sctp_sendmsg(source->socket, buf, len, &to->s, tolen, 0, 0, 0, 0, 0);
#ifdef XL_DEBUG
	LM_INFO("send status: %d\n", n);
#endif
	if (n==-1){
		LM_ERR("sctp_sendmsg(sock,%p,%d,%p,%d,0,0,0,0,0): %s(%d)\n",
				buf,len,&to->s,tolen, strerror(errno),errno);

		if (errno==EINTR) goto again;
		if (errno==EINVAL) {
			LM_CRIT("invalid sendtoparameters\n"
			"one possible reason is the server is bound to localhost and\n"
			"attempts to send to the net\n");
		}
	}
	return n;
}
Esempio n. 4
0
/**
 * bin_send - computes the checksum of the current packet and then
 * sends the packet over UDP to the @dest destination
 *
 * @return: number of bytes sent, or -1 on error
 */
int bin_send(union sockaddr_union *dest)
{
	int rc, destlen;
	str st;

	if (!dest)
		return 0;

	st.s = send_buffer + HEADER_SIZE;
	st.len = bin_send_size - HEADER_SIZE;

	/* compute a checksum of the binary packet content */
	crc32_uint(&st, (unsigned int *)(send_buffer + BIN_PACKET_MARKER_SIZE));

	LM_DBG("sending packet {'%.*s', %d}: %.*s [%d B] from socket %d\n",
	        *(int *)(send_buffer + HEADER_SIZE), send_buffer + HEADER_SIZE +
	        LEN_FIELD_SIZE, bin_send_type, bin_send_size, send_buffer, bin_send_size,
	        bin->socket);

	destlen=sockaddru_len(*dest);
again:
	rc=sendto(bin->socket, send_buffer, bin_send_size, 0, &dest->s, destlen);
	if (rc==-1){
		if (errno==EINTR) goto again;
		LM_ERR("sendto() failed with %s(%d)\n", strerror(errno),errno);
	}

	return rc;
}
Esempio n. 5
0
int proto_sctp_read(struct socket_info *si, int* bytes_read)
{
    struct receive_info ri;
    int len;
#ifdef DYN_BUF
    char* buf;
#else
    static char buf [BUF_SIZE+1];
#endif
    char *tmp;
    unsigned int fromlen;
    struct sctp_sndrcvinfo sinfo;

#ifdef DYN_BUF
    buf=pkg_malloc(BUF_SIZE+1);
    if (buf==0) {
        LM_ERR(" could not allocate receive buffer in pkg memory\n");
        goto error;
    }
#endif
    fromlen=sockaddru_len(si->su);
    len = sctp_recvmsg(si->socket, buf, BUF_SIZE, &ri.src_su.s, &fromlen,
                       &sinfo, 0);
    if (len==-1) {
        if (errno==EAGAIN) {
            LM_DBG("packet with bad checksum received\n");
            return 0;
        }
        if ((errno==EINTR)||(errno==EWOULDBLOCK)|| (errno==ECONNREFUSED))
            return -1;
        LM_ERR("sctp_recvmsg:[%d] %s\n", errno, strerror(errno));
        return -2;
    }

    /* we must 0-term the messages, receive_msg expects it */
    buf[len]=0; /* no need to save the previous char */

    ri.bind_address = si;
    ri.dst_port = si->port_no;
    ri.dst_ip = si->address;
    ri.proto = si->proto;
    ri.proto_reserved1 = ri.proto_reserved2 = 0;

    su2ip_addr(&ri.src_ip, &ri.src_su);
    ri.src_port=su_getport(&ri.src_su);

    if (ri.src_port==0) {
        tmp=ip_addr2a(&ri.src_ip);
        LM_INFO("dropping 0 port packet from %s\n", tmp);
        return 0;
    }

    /* receive_msg must free buf too!*/
    receive_msg(buf, len, &ri);

    return 0;
}
Esempio n. 6
0
struct tcp_connection* tcpconn_connect(union sockaddr_union* server, int type)
{
	int s;
	struct socket_info* si;
	union sockaddr_union my_name;
	socklen_t my_name_len;
	struct tcp_connection* con;
	struct ip_addr ip;

	s=socket(AF2PF(server->s.sa_family), SOCK_STREAM, 0);
	if (s==-1){
		LOG(L_ERR, "ERROR: tcpconn_connect: socket: (%d) %s\n",
				errno, strerror(errno));
		goto error;
	}
	if (init_sock_opt(s)<0){
		LOG(L_ERR, "ERROR: tcpconn_connect: init_sock_opt failed\n");
		goto error;
	}
	if (tcp_blocking_connect(s, &server->s, sockaddru_len(*server))<0){
		LOG(L_ERR, "ERROR: tcpconn_connect: tcp_blocking_connect failed\n");
		goto error;
	}
	my_name_len=sizeof(my_name);
	if (getsockname(s, &my_name.s, &my_name_len)!=0){
		LOG(L_ERR, "ERROR: tcp_connect: getsockname failed: %s(%d)\n",
				strerror(errno), errno);
		si=0; /* try to go on */
	}
	su2ip_addr(&ip, &my_name);
#ifdef USE_TLS
	if (type==PROTO_TLS)
		si=find_si(&ip, 0, PROTO_TLS);
	else
#endif
		si=find_si(&ip, 0, PROTO_TCP);

	if (si==0){
		LOG(L_ERR, "ERROR: tcp_connect: could not find corresponding"
				" listening socket, using default...\n");
		if (server->s.sa_family==AF_INET) si=sendipv4_tcp;
#ifdef USE_IPV6
		else si=sendipv6_tcp;
#endif
	}
	con=tcpconn_new(s, server, si, type, S_CONN_CONNECT);
	if (con==0){
		LOG(L_ERR, "ERROR: tcp_connect: tcpconn_new failed, closing the "
				 " socket\n");
		goto error;
	}
	return con;
	/*FIXME: set sock idx! */
error:
	if (s!=-1) close(s); /* close the opened socket */
	return 0;
}
Esempio n. 7
0
static struct tcp_connection* ws_sync_connect(struct socket_info* send_sock,
		union sockaddr_union* server)
{
	int s;
	union sockaddr_union my_name;
	socklen_t my_name_len;
	struct tcp_connection* con;

	s=socket(AF2PF(server->s.sa_family), SOCK_STREAM, 0);
	if (s==-1){
		LM_ERR("socket: (%d) %s\n", errno, strerror(errno));
		goto error;
	}
	if (tcp_init_sock_opt(s)<0){
		LM_ERR("tcp_init_sock_opt failed\n");
		goto error;
	}
	my_name_len = sockaddru_len(send_sock->su);
	memcpy( &my_name, &send_sock->su, my_name_len);
	su_setport( &my_name, 0);
	if (bind(s, &my_name.s, my_name_len )!=0) {
		LM_ERR("bind failed (%d) %s\n", errno,strerror(errno));
		goto error;
	}

	if (tcp_connect_blocking(s, &server->s, sockaddru_len(*server))<0){
		LM_ERR("tcp_blocking_connect failed\n");
		goto error;
	}
	con=tcp_conn_new(s, server, send_sock, S_CONN_OK);
	if (con==NULL){
		LM_ERR("tcp_conn_create failed, closing the socket\n");
		goto error;
	}
	/* it is safe to move this here and clear it after we complete the
	 * handshake, just before sending the fd to main */
	con->fd = s;
	return con;
error:
	/* close the opened socket */
	if (s!=-1) close(s);
	return 0;
}
Esempio n. 8
0
static struct tcp_connection* hep_sync_connect(struct socket_info* send_sock,
		union sockaddr_union* server, int *fd)
{
	int s;
	union sockaddr_union my_name;
	socklen_t my_name_len;
	struct tcp_connection* con;

	s=socket(AF2PF(server->s.sa_family), SOCK_STREAM, 0);
	if (s==-1){
		LM_ERR("socket: (%d) %s\n", errno, strerror(errno));
		goto error;
	}
	if (tcp_init_sock_opt(s)<0){
		LM_ERR("tcp_init_sock_opt failed\n");
		goto error;
	}
	my_name_len = sockaddru_len(send_sock->su);
	memcpy( &my_name, &send_sock->su, my_name_len);
	su_setport( &my_name, 0);
	if (bind(s, &my_name.s, my_name_len )!=0) {
		LM_ERR("bind failed (%d) %s\n", errno,strerror(errno));
		goto error;
	}

	if (tcp_connect_blocking(s, &server->s, sockaddru_len(*server))<0){
		LM_ERR("tcp_blocking_connect failed\n");
		goto error;
	}
	con = tcp_conn_create(s, server, send_sock, S_CONN_OK);
	if (con==NULL){
		LM_ERR("tcp_conn_create failed, closing the socket\n");
		goto error;
	}
	*fd = s;
	return con;
	/*FIXME: set sock idx! */
error:
	/* close the opened socket */
	if (s!=-1) close(s);
	return 0;
}
Esempio n. 9
0
/** send an udp packet over a non-ip_hdrincl raw socket.
 * @param rsock - raw socket
 * @param buf - data
 * @param len - data len
 * @param from - source address:port (_must_ be non-null, but the ip address
 *                can be 0, in which case it will be filled by the kernel).
 * @param to - destination address:port
 * @return  <0 on error (errno set too), number of bytes sent on success
 *          (including the udp header => on success len + udpheader size).
 */
int raw_udp4_send(int rsock, char* buf, unsigned int len,
					union sockaddr_union* from,
					union sockaddr_union* to)
{
	struct msghdr snd_msg;
	struct cmsghdr* cmsg;
#ifdef IP_PKTINFO
	struct in_pktinfo* snd_pktinfo;
#endif /* IP_PKTINFO */
	struct iovec iov[2];
	struct udphdr udp_hdr;
	char msg_ctrl_snd_buf[1024];
	int ret;

	memset(&snd_msg, 0, sizeof(snd_msg));
	snd_msg.msg_name=&to->sin;
	snd_msg.msg_namelen=sockaddru_len(*to);
	snd_msg.msg_iov=&iov[0];
	/* prepare udp header */
	mk_udp_hdr(&udp_hdr, &from->sin, &to->sin, (unsigned char*)buf, len, 1);
	iov[0].iov_base=(char*)&udp_hdr;
	iov[0].iov_len=sizeof(udp_hdr);
	iov[1].iov_base=buf;
	iov[1].iov_len=len;
	snd_msg.msg_iovlen=2;
	snd_msg.msg_control=msg_ctrl_snd_buf;
	snd_msg.msg_controllen=sizeof(msg_ctrl_snd_buf);
	/* init pktinfo cmsg */
	cmsg=CMSG_FIRSTHDR(&snd_msg);
	cmsg->cmsg_level=IPPROTO_IP;
#ifdef IP_PKTINFO
	cmsg->cmsg_type=IP_PKTINFO;
	cmsg->cmsg_len=CMSG_LEN(sizeof(struct in_pktinfo));
	snd_pktinfo=(struct in_pktinfo*)CMSG_DATA(cmsg);
	snd_pktinfo->ipi_ifindex=0;
	snd_pktinfo->ipi_spec_dst.s_addr=from->sin.sin_addr.s_addr;
#elif defined (IP_SENDSRCADDR)
	cmsg->cmsg_type=IP_SENDSRCADDR;
	cmsg->cmsg_len=CMSG_LEN(sizeof(struct in_addr));
	memcpy(CMSG_DATA(cmsg), &from->sin.sin_addr.s_addr,
							sizeof(struct in_addr));
#else
#error "no method of setting the source ip supported"
#endif /* IP_PKTINFO / IP_SENDSRCADDR */
	snd_msg.msg_controllen=cmsg->cmsg_len;
	snd_msg.msg_flags=0;
	ret=sendmsg(rsock, &snd_msg, 0);
	return ret;
}
Esempio n. 10
0
/**
 * Main UDP send function, called from msg_send.
 * \see msg_send
 * \param source send socket
 * \param buf sent data
 * \param len data length in bytes
 * \param to destination address
 * \return -1 on error, the return value from sento on success
 */
static int proto_udp_send(struct socket_info* source,
		char* buf, unsigned int len, union sockaddr_union* to, int id)
{
	int n, tolen;

	tolen=sockaddru_len(*to);
again:
	n=sendto(source->socket, buf, len, 0, &to->s, tolen);
	if (n==-1){
		LM_ERR("sendto(sock,%p,%d,0,%p,%d): %s(%d)\n", buf,len,to,tolen,
				strerror(errno),errno);
		if (errno==EINTR || errno==EAGAIN) goto again;
		if (errno==EINVAL) {
			LM_CRIT("invalid sendtoparameters\n"
			"one possible reason is the server is bound to localhost and\n"
			"attempts to send to the net\n");
		}
	}
	return n;
}
Esempio n. 11
0
/*! \brief return a socket_info_pointer to the sending socket
 * \note As opposed to
 * get_send_socket(), which returns process's default socket, get_out_socket
 * attempts to determine the outbound interface which will be used;
 * it creates a temporary connected socket to determine it; it will
 * be very likely noticeably slower, but it can deal better with
 * multihomed hosts
 */
struct socket_info* get_out_socket(union sockaddr_union* to, int proto)
{
	int temp_sock;
	socklen_t len;
	union sockaddr_union from; 
	struct socket_info* si;
	struct ip_addr ip;

	if (proto!=PROTO_UDP) {
		LM_CRIT("can only be called for UDP\n");
		return 0;
	}
	
	temp_sock=socket(to->s.sa_family, SOCK_DGRAM, 0 );
	if (temp_sock==-1) {
		LM_ERR("socket() failed: %s\n", strerror(errno));
		return 0;
	}
	if (connect(temp_sock, &to->s, sockaddru_len(*to))==-1) {
		LM_ERR("connect failed: %s\n", strerror(errno));
		goto error;
	}
	len=sizeof(from);
	if (getsockname(temp_sock, &from.s, &len)==-1) {
		LM_ERR("getsockname failed: %s\n", strerror(errno));
		goto error;
	}
	su2ip_addr(&ip, &from);
	si=find_si(&ip, 0, proto);
	if (si==0) goto error;
	close(temp_sock);
	LM_DBG("socket determined: %p\n", si );
	return si;
error:
	LM_ERR("no socket found\n");
	close(temp_sock);
	return 0;
}
Esempio n. 12
0
static int hep_udp_read_req(struct socket_info *si, int* bytes_read)
{
	struct receive_info ri;
	int len;
#ifdef DYN_BUF
	char* buf;
#else
	static char buf [BUF_SIZE+1];
#endif
	char *tmp;
	unsigned int fromlen;
	str msg;

	struct hep_desc h;

	int ret = 0;

#ifdef DYN_BUF
	buf=pkg_malloc(BUF_SIZE+1);
	if (buf==0){
		LM_ERR("could not allocate receive buffer\n");
		goto error;
	}
#endif

	fromlen=sockaddru_len(si->su);
	len=recvfrom(bind_address->socket, buf, BUF_SIZE,0,&ri.src_su.s,&fromlen);
	if (len==-1){
		if (errno==EAGAIN)
			return 0;
		if ((errno==EINTR)||(errno==EWOULDBLOCK)|| (errno==ECONNREFUSED))
			return -1;
		LM_ERR("recvfrom:[%d] %s\n", errno, strerror(errno));
		return -2;
	}


	if (len<MIN_UDP_PACKET) {
		LM_DBG("probing packet received len = %d\n", len);
		return 0;
	}

	/* we must 0-term the messages, receive_msg expects it */
	buf[len]=0; /* no need to save the previous char */

	ri.bind_address = si;
	ri.dst_port = si->port_no;
	ri.dst_ip = si->address;
	ri.proto = si->proto;
	ri.proto_reserved1 = ri.proto_reserved2 = 0;

	su2ip_addr(&ri.src_ip, &ri.src_su);
	ri.src_port=su_getport(&ri.src_su);

	msg.s = buf;
	msg.len = len;

	/* if udp we are sure that version 1 or 2 of the
	 * protocol is used */
	if (unpack_hepv2(buf, len, &h)) {
		LM_ERR("hep unpacking failed\n");
		return -1;
	}

	/* run hep callbacks if looks like non-SIP message*/
	if( !isalpha(msg.s[0]) ) {    /* not-SIP related */
		ret=run_hep_cbs(&h, &ri);
		if (ret < 0) {
			LM_ERR("failed to run hep callbacks\n");
			return -1;
		}

		/* remove the hep header; leave only the payload */
		memmove(buf, h.u.hepv12.payload,
							/* also copy '\0' character */
							strlen(h.u.hepv12.payload)+1);
		msg.s   = buf;
		msg.len = strlen(buf);
	}

	if (ri.src_port==0){
		tmp=ip_addr2a(&ri.src_ip);
		LM_INFO("dropping 0 port packet for %s\n", tmp);
		return 0;
	}

	if (ret != HEP_SCRIPT_SKIP) {
		/* receive_msg must free buf too!*/
		receive_msg( msg.s, msg.len, &ri);
	}

	return 0;
}
Esempio n. 13
0
int  mi_init_datagram_server(sockaddr_dtgram *addr, unsigned int socket_domain,
						rx_tx_sockets * socks, int mode, int uid, int gid )
{
	char * socket_name;

	/* create sockets rx and tx ... */
	/***********************************/
	mi_socket_domain = socket_domain;
	/**********************************/

	socks->rx_sock = socket(socket_domain, SOCK_DGRAM, 0);
	if (socks->rx_sock == -1) {
		LM_ERR("cannot create RX socket: %s\n", strerror(errno));
		return -1;
	}

	switch(socket_domain) {
		case AF_LOCAL:
			LM_DBG("we have a unix socket: %s\n", addr->unix_addr.sun_path);
			socket_name = addr->unix_addr.sun_path;
			if(bind(socks->rx_sock,(struct sockaddr*)&addr->unix_addr,
					SUN_LEN(&addr->unix_addr))< 0) {
				LM_ERR("bind: %s\n", strerror(errno));
				goto err_rx;
			}
			if(mi_sock_check(socks->rx_sock, socket_name)!=0)
				goto err_rx;
			/* change permissions */
			if (mode){
				if (chmod(socket_name, mode)<0){
					LM_ERR("failed to change the permissions for %s to %04o:"
						"%s[%d]\n",socket_name, mode, strerror(errno), errno);
					goto err_rx;
				}
			}
			/* change ownership */
			if ((uid!=-1) || (gid!=-1)){
				if (chown(socket_name, uid, gid)<0){
					LM_ERR("failed to change the owner/group for %s  to %d.%d;"
					"%s[%d]\n",socket_name, uid, gid, strerror(errno), errno);
					goto err_rx;
				}
			}
			/* create TX socket */
			socks->tx_sock = socket( socket_domain, SOCK_DGRAM, 0);
			if (socks->tx_sock == -1) {
				LM_ERR("cannot create socket: %s\n", strerror(errno));
				goto err_rx;
			};
			/* Turn non-blocking mode on for tx*/
			flags = fcntl(socks->tx_sock, F_GETFL);
			if (flags == -1) {
				LM_ERR("fcntl failed: %s\n", strerror(errno));
				goto err_both;
			}
			if (fcntl(socks->tx_sock, F_SETFL, flags | O_NONBLOCK) == -1) {
				LM_ERR("fcntl: set non-blocking failed: %s\n",strerror(errno));
				goto err_both;
			}
			break;

		case AF_INET:
			if (bind(socks->rx_sock, &addr->udp_addr.s,
			sockaddru_len(addr->udp_addr))< 0) {
				LM_ERR("bind: %s\n", strerror(errno));
				goto err_rx;
			}
			socks->tx_sock = socks->rx_sock;
			break;
#ifdef USE_IPV6
		case AF_INET6:
			if(bind(socks->rx_sock, (struct sockaddr*)&addr->udp_addr.sin6,
					sizeof(addr->udp_addr)) < 0) {
				LM_ERR("bind: %s\n", strerror(errno));
				goto err_rx;
			}
			socks->tx_sock = socks->rx_sock;
			break;
#endif
		default:
			LM_ERR("domain not supported\n");
			goto err_rx;

	}

	return 0;
err_both:
	close(socks->tx_sock);
err_rx:
	close(socks->rx_sock);
	return -1;
}
Esempio n. 14
0
/** send an udp packet over an IP_HDRINCL raw socket.
 * If needed, send several fragments.
 * @param rsock - raw socket
 * @param buf - data
 * @param len - data len
 * @param from - source address:port (_must_ be non-null, but the ip address
 *                can be 0, in which case it will be filled by the kernel).
 * @param to - destination address:port
 * @param mtu - maximum datagram size (including the ip header, excluding
 *              link layer headers). Minimum allowed size is 28
 *               (sizeof(ip_header + udp_header)). If mtu is lower, it will
 *               be ignored (the packet will be sent un-fragmented).
 *              0 can be used to disable fragmentation.
 * @return  <0 on error (-2: datagram too big, -1: check errno),
 *          number of bytes sent on success
 *          (including the ip & udp headers =>
 *               on success len + udpheader + ipheader size).
 */
int raw_iphdr_udp4_send(int rsock, char* buf, unsigned int len,
						union sockaddr_union* from,
						union sockaddr_union* to, unsigned short mtu)
{
	struct msghdr snd_msg;
	struct iovec iov[2];
	struct ip_udp_hdr {
		struct ip ip;
		struct udphdr udp;
	} hdr;
	unsigned int totlen;
#ifndef RAW_IPHDR_INC_AUTO_FRAG
	unsigned int ip_frag_size; /* fragment size */
	unsigned int last_frag_extra; /* extra bytes possible in the last frag */
	unsigned int ip_payload;
	unsigned int last_frag_offs;
	void* last_frag_start;
	int frg_no;
#endif /* RAW_IPHDR_INC_AUTO_FRAG */
	int ret;

	totlen = len + sizeof(hdr);
	if (unlikely(totlen) > 65535)
		return -2;
	memset(&snd_msg, 0, sizeof(snd_msg));
	snd_msg.msg_name=&to->sin;
	snd_msg.msg_namelen=sockaddru_len(*to);
	snd_msg.msg_iov=&iov[0];
	/* prepare the udp & ip headers */
	mk_udp_hdr(&hdr.udp, &from->sin, &to->sin, (unsigned char*)buf, len, 1);
	mk_ip_hdr(&hdr.ip, &from->sin.sin_addr, &to->sin.sin_addr,
				len + sizeof(hdr.udp), IPPROTO_UDP);
	iov[0].iov_base=(char*)&hdr;
	iov[0].iov_len=sizeof(hdr);
	snd_msg.msg_iovlen=2;
	snd_msg.msg_control=0;
	snd_msg.msg_controllen=0;
	snd_msg.msg_flags=0;
	/* this part changes for different fragments */
	/* packets are fragmented if mtu has a valid value (at least an
	   IP header + UDP header fit in it) and if the total length is greater
	   then the mtu */
#ifndef RAW_IPHDR_INC_AUTO_FRAG
	if (likely(totlen <= mtu || mtu <= sizeof(hdr))) {
#endif /* RAW_IPHDR_INC_AUTO_FRAG */
		iov[1].iov_base=buf;
		iov[1].iov_len=len;
		ret=sendmsg(rsock, &snd_msg, 0);
#ifndef RAW_IPHDR_INC_AUTO_FRAG
	} else {
		ip_payload = len + sizeof(hdr.udp);
		/* a fragment offset must be a multiple of 8 => its size must
		   also be a multiple of 8, except for the last fragment */
		ip_frag_size = (mtu -sizeof(hdr.ip)) & (~7);
		last_frag_extra = (mtu - sizeof(hdr.ip)) & 7; /* rest */
		frg_no = ip_payload / ip_frag_size +
				 ((ip_payload % ip_frag_size) > last_frag_extra);
		/*ip_last_frag_size = ip_payload % frag_size +
							((ip_payload % frag_size) <= last_frag_extra) *
							ip_frag_size; */
		last_frag_offs = (frg_no - 1) * ip_frag_size;
		/* if we are here mtu => sizeof(ip_h+udp_h) && payload > mtu
		   => last_frag_offs >= sizeof(hdr.udp) */
		last_frag_start = buf + last_frag_offs - sizeof(hdr.udp);
		hdr.ip.ip_id = fastrand_max(65534) + 1; /* random id, should be != 0
											  (if 0 the kernel will fill it) */
		/* send the first fragment */
		iov[1].iov_base=buf;
		/* ip_frag_size >= sizeof(hdr.udp) because we are here only
		   if mtu >= sizeof(hdr.ip) + sizeof(hdr.udp) */
		iov[1].iov_len=ip_frag_size - sizeof(hdr.udp);
		hdr.ip.ip_len = RAW_IPHDR_IP_LEN(ip_frag_size + sizeof(hdr.ip));
		hdr.ip.ip_off = RAW_IPHDR_IP_OFF(0x2000); /* set MF */
		ret=sendmsg(rsock, &snd_msg, 0);
		if (unlikely(ret < 0))
			goto end;
		/* all the other fragments, include only the ip header */
		iov[0].iov_len = sizeof(hdr.ip);
		iov[1].iov_base =  (char*)iov[1].iov_base + iov[1].iov_len;
		/* fragments between the first and the last */
		while(unlikely(iov[1].iov_base < last_frag_start)) {
			iov[1].iov_len = ip_frag_size;
			hdr.ip.ip_len = RAW_IPHDR_IP_LEN(iov[1].iov_len + sizeof(hdr.ip));
			/* set MF  */
			hdr.ip.ip_off = RAW_IPHDR_IP_OFF( (unsigned short)
									(((char*)iov[1].iov_base - (char*)buf +
										sizeof(hdr.udp)) / 8) | 0x2000 );
			ret=sendmsg(rsock, &snd_msg, 0);
			if (unlikely(ret < 0))
				goto end;
			iov[1].iov_base =  (char*)iov[1].iov_base + iov[1].iov_len;
		}
		/* last fragment */
		iov[1].iov_len = buf + len - (char*)iov[1].iov_base;
		hdr.ip.ip_len = RAW_IPHDR_IP_LEN(iov[1].iov_len + sizeof(hdr.ip));
		/* don't set MF (last fragment) */
		hdr.ip.ip_off = RAW_IPHDR_IP_OFF((unsigned short)
									(((char*)iov[1].iov_base - (char*)buf +
										sizeof(hdr.udp)) / 8) );
		ret=sendmsg(rsock, &snd_msg, 0);
		if (unlikely(ret < 0))
			goto end;
	}
end:
#endif /* RAW_IPHDR_INC_AUTO_FRAG */
	return ret;
}
Esempio n. 15
0
static int udp_read_req(struct socket_info *si, int* bytes_read)
{
	struct receive_info ri;
	int len;
#ifdef DYN_BUF
	char* buf;
#else
	static char buf [BUF_SIZE+1];
#endif
	char *tmp;
	unsigned int fromlen;
	callback_list* p;
	str msg;

#ifdef DYN_BUF
	buf=pkg_malloc(BUF_SIZE+1);
	if (buf==0){
		LM_ERR("could not allocate receive buffer\n");
		goto error;
	}
#endif

	fromlen=sockaddru_len(si->su);
	len=recvfrom(bind_address->socket, buf, BUF_SIZE,0,&ri.src_su.s,&fromlen);
	if (len==-1){
		if (errno==EAGAIN)
			return 0;
		if ((errno==EINTR)||(errno==EWOULDBLOCK)|| (errno==ECONNREFUSED))
			return -1;
		LM_ERR("recvfrom:[%d] %s\n", errno, strerror(errno));
		return -2;
	}

	if (len<MIN_UDP_PACKET) {
		LM_DBG("probing packet received len = %d\n", len);
		return 0;
	}

	/* we must 0-term the messages, receive_msg expects it */
	buf[len]=0; /* no need to save the previous char */

	ri.bind_address = si;
	ri.dst_port = si->port_no;
	ri.dst_ip = si->address;
	ri.proto = si->proto;
	ri.proto_reserved1 = ri.proto_reserved2 = 0;

	su2ip_addr(&ri.src_ip, &ri.src_su);
	ri.src_port=su_getport(&ri.src_su);

	msg.s = buf;
	msg.len = len;

	/* run callbacks if looks like non-SIP message*/
	if( !isalpha(msg.s[0]) ){    /* not-SIP related */
		for(p = cb_list; p; p = p->next){
			if(p->b == msg.s[1]){
				if (p->func(bind_address->socket, &ri, &msg, p->param)==0){
					/* buffer consumed by callback */
					break;
				}
			}
		}
		if (p) return 0;
	}

	if (ri.src_port==0){
		tmp=ip_addr2a(&ri.src_ip);
		LM_INFO("dropping 0 port packet from %s\n", tmp);
		return 0;
	}

	/* receive_msg must free buf too!*/
	receive_msg( msg.s, msg.len, &ri);

	return 0;
}
Esempio n. 16
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;
}
Esempio n. 17
0
int sctp_server_rcv_loop()
{
	int len;
#ifdef DYN_BUF
	char* buf;
#else
	static char buf [BUF_SIZE+1];
#endif
	char *tmp;
	union sockaddr_union* from;
	unsigned int fromlen;
	struct receive_info ri;
	struct sctp_sndrcvinfo sinfo;


	from=(union sockaddr_union*) pkg_malloc(sizeof(union sockaddr_union));
	if (from==0){
		LM_ERR("out of pkg memory\n");
		goto error;
	}
	memset(&sinfo, 0 , sizeof(sinfo));
	ri.bind_address=bind_address; /* this will not change, we do it only once*/
	ri.dst_port=bind_address->port_no;
	ri.dst_ip=bind_address->address;
	ri.proto=PROTO_SCTP;
	ri.proto_reserved1=ri.proto_reserved2=0;
	for(;;){
#ifdef DYN_BUF
		buf=pkg_malloc(BUF_SIZE+1);
		if (buf==0){
			LM_ERR(" could not allocate receive buffer in pkg memory\n");
			goto error;
		}
#endif
		fromlen=sockaddru_len(bind_address->su);
		len = sctp_recvmsg(bind_address->socket, buf, BUF_SIZE, &from->s, &fromlen, &sinfo, 0);
		
		if (len==-1){
			if (errno==EAGAIN){
				LM_DBG("packet with bad checksum received\n");
				continue;
			}
			LM_ERR("sctp_recvmsg:[%d] %s\n", errno, strerror(errno));
			if ((errno==EINTR)||(errno==EWOULDBLOCK)|| (errno==ECONNREFUSED))
				continue; /* goto skip;*/
			else goto error;
		}
		/* we must 0-term the messages, receive_msg expects it */
		buf[len]=0; /* no need to save the previous char */

		ri.src_su=*from;
		su2ip_addr(&ri.src_ip, from);
		ri.src_port=su_getport(from);

#ifndef NO_ZERO_CHECKS
		if (buf[len-1]==0) {
			tmp=ip_addr2a(&ri.src_ip);
			LM_WARN("upstream bug - 0-terminated packet from %s %d\n",
					tmp, htons(ri.src_port));
			len--;
		}
#endif
		if (ri.src_port==0){
			tmp=ip_addr2a(&ri.src_ip);
			LM_INFO("dropping 0 port packet from %s\n", tmp);
			continue;
		}
		
		
		/* receive_msg must free buf too!*/
		receive_msg(buf, len, &ri);
		
	/* skip: do other stuff */
		
	}
	/*
	if (from) pkg_free(from);
	return 0;
	*/
	
error:
	if (from) pkg_free(from);
	return -1;
}
Esempio n. 18
0
struct socket_info* get_out_socket(union sockaddr_union* to, int proto)
{
	int* temp_sock;
	socklen_t len;
	union sockaddr_union from; 
	struct socket_info* si;
	struct ip_addr ip;
	union sockaddr_union uncon;

	memset(&uncon, 0, sizeof(union sockaddr_union));
	uncon.sin.sin_family = AF_UNSPEC;

	if (unlikely(proto!=PROTO_UDP)) {
		LOG(L_CRIT, "BUG: get_out_socket can only be called for UDP\n");
		return 0;
	}
retry:
	switch(to->s.sa_family){
	case AF_INET : {
		if(unlikely(sock_inet < 0)){
			sock_inet = socket(AF_INET, SOCK_DGRAM, 0);
			if (sock_inet==-1) {
				LM_ERR("socket() failed: %s\n", strerror(errno));
				return 0;
			}
		}
		temp_sock = &sock_inet;
		break;
	}
#ifdef USE_IPV6
	case AF_INET6 : {
		if(unlikely(sock_inet6 < 0)){
			sock_inet6 = socket(AF_INET6, SOCK_DGRAM, 0);
			if (sock_inet6==-1) {
				LM_ERR("socket() failed: %s\n", strerror(errno));
				return 0;
			}
		}
		temp_sock = &sock_inet6;
		break;
	}
#endif /* USE_IPV6 */
	default: {
		LM_ERR("Unknown protocol family \n");
		return 0;
	}
	}

	if( !mhomed_sock_cache_disabled ){
		/* some Linux kernel versions (all?) along with other UNIXes don't re-bound the sock if already bound */
		/* to un-bound a socket set sin_family to AF_UNSPEC and zero out the rest*/
		if (unlikely(connect(*temp_sock, &uncon.s, sockaddru_len(uncon)) < 0))
				mhomed_sock_cache_disabled = 1;
	}

	if (unlikely(connect(*temp_sock, &to->s, sockaddru_len(*to))==-1)) {
		if (unlikely(errno==EISCONN && !mhomed_sock_cache_disabled)){
			/*  no multiple connects support on the same socket */
			mhomed_sock_cache_disabled=1;
			if (sock_inet>=0){
				close(sock_inet);
				sock_inet=-1;
			}
#ifdef USE_IPV6
			if (sock_inet6>=0){
				close(sock_inet6);
				sock_inet6=-1;
			}
#endif /* USE_IPV6 */
			goto retry;
		}
		LOG(L_ERR, "ERROR: get_out_socket: connect failed: %s\n",
				strerror(errno));
		goto error;
	}
	len=sizeof(from);
	if (unlikely(getsockname(*temp_sock, &from.s, &len)==-1)) {
		LOG(L_ERR, "ERROR: get_out_socket: getsockname failed: %s\n",
				strerror(errno));
		goto error;
	}
	su2ip_addr(&ip, &from);
	si=find_si(&ip, 0, proto);
	if (si==0) goto error;
	DBG("DEBUG: get_out_socket: socket determined: %p\n", si );
	if (unlikely(mhomed_sock_cache_disabled)){
		close(*temp_sock);
		*temp_sock=-1;
	}
	return si;
error:
	LOG(L_ERR, "ERROR: get_out_socket: no socket found\n");
	if (unlikely(mhomed_sock_cache_disabled && *temp_sock >=0)){
		close(*temp_sock);
		*temp_sock=-1;
	}
	return 0;
}
Esempio n. 19
0
int jsonrpc_dgram_init_server(jsonrpc_dgram_sockaddr_t *addr,
		unsigned int socket_domain,
		jsonrpc_dgram_rx_tx_t *socks,
		int mode, int uid, int gid )
{
	char *socket_name;
	int flags;
	int optval;

	/* create sockets for rx and tx ... */
	jsonrpc_dgram_socket_domain = socket_domain;

	socks->rx_sock = socket(socket_domain, SOCK_DGRAM, 0);
	if (socks->rx_sock == -1) {
		LM_ERR("cannot create RX socket: %s\n", strerror(errno));
		return -1;
	}

	switch(socket_domain)
	{
	case AF_LOCAL:
			LM_DBG("we have a unix socket: %s\n", addr->unix_addr.sun_path);
			socket_name = addr->unix_addr.sun_path;
			if(bind(socks->rx_sock,(struct sockaddr*)&addr->unix_addr,
						SUN_LEN(&addr->unix_addr))< 0) {
				LM_ERR("bind: %s\n", strerror(errno));
				goto err_rx;
			}
			if(jsonrpc_dgram_sock_check(socks->rx_sock, socket_name)!=0)
				goto err_rx;
			/* change permissions */
			if (mode){
				if (chmod(socket_name, mode)<0){
					LM_ERR("failed to change the permissions for %s to %04o:"
						"%s[%d]\n",socket_name, mode, strerror(errno), errno);
					goto err_rx;
				}
			}
			/* change ownership */
			if ((uid!=-1) || (gid!=-1)){
				if (chown(socket_name, uid, gid)<0){
					LM_ERR("failed to change the owner/group for %s  to %d.%d;"
					"%s[%d]\n", socket_name, uid, gid, strerror(errno), errno);
					goto err_rx;
				}
			}
			break;

	case AF_INET:
			if (bind(socks->rx_sock, &addr->udp_addr.s,
			sockaddru_len(addr->udp_addr))< 0) {
				LM_ERR("bind: %s\n", strerror(errno));
				goto err_rx;
			}
			break;
	case AF_INET6:
			if(bind(socks->rx_sock, (struct sockaddr*)&addr->udp_addr.sin6,
						sizeof(addr->udp_addr)) < 0) {
				LM_ERR("bind: %s\n", strerror(errno));
				goto err_rx;
			}
			break;
	default:
			LM_ERR("domain not supported\n");
			goto err_both;

	}
	jsonrpc_dgram_create_reply_socket(socks->tx_sock, socket_domain, err_both);

	optval = 64 * 1024;
	if (setsockopt(socks->tx_sock, SOL_SOCKET, SO_SNDBUF,
					(void*)&optval, sizeof(optval)) ==-1){
		LM_ERR("failed to increse send buffer size via setsockopt "
				" SO_SNDBUF (%d) - %d: %s\n", optval,
				errno, strerror(errno));
		/* continue, non-critical */
	}

	return 0;
err_both:
	close(socks->tx_sock);
err_rx:
	close(socks->rx_sock);
	return -1;
}
Esempio n. 20
0
/* opens, binds and listens-on a control tcp socket
 * returns socket fd or -1 on error */
int init_tcpudp_sock(union sockaddr_union* sa_un, char* address, int port,
						enum socket_protos type)
{
	union sockaddr_union su;
	struct hostent* he;
	int s;
	int optval;
	
	s=-1;
	if ((type!=UDP_SOCK) && (type!=TCP_SOCK)){
		LOG(L_CRIT, "BUG: init_tcpudp_sock called with bad type: %d\n",
				type);
		goto error;
	}
	memset(&su, 0, sizeof (su));
	/* if no address specified, or address=='*', listen on all
	 * ipv4 addresses */
	if ((address==0)||((*address)==0)||((*address=='*') && (*(address+1)==0))){
		su.sin.sin_family=AF_INET;
		su.sin.sin_port=htons(port);
		su.sin.sin_addr.s_addr=INADDR_ANY;
#ifdef HAVE_SOCKADDR_SA_LEN
		su.sin.sin_len=sizeof(struct sockaddr_in);
#endif
	}else{
		he=resolvehost(address);
		if (he==0){
			LOG(L_ERR, "ERROR: init_tcpudp_sock: bad address %s\n", address);
			goto error;
		}
		if (hostent2su(&su, he, 0, port)==-1) goto error;
	}
	s=socket(AF2PF(su.s.sa_family), (type==TCP_SOCK)?SOCK_STREAM:SOCK_DGRAM,0);
	if (s==-1){
		LOG(L_ERR, "ERROR: init_tcpudp_sock: cannot create tcp socket:"
				" %s [%d]\n", strerror(errno), errno);
		goto error;
	}
	/* REUSEADDR */
	optval=1;
	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval))==-1){
		LOG(L_ERR, "ERROR: init_tcpudp_sock: setsockopt: %s [%d]\n", 
				strerror(errno), errno);
		/* continue */
	}
	/* tos */
	optval=IPTOS_LOWDELAY;
	if (setsockopt(s, IPPROTO_IP, IP_TOS, (void*)&optval,sizeof(optval)) ==-1){
		LOG(L_WARN, "WARNING: init_tcpudp_sock: setsockopt tos: %s\n",
				strerror(errno));
		/* continue since this is not critical */
	}
	if (set_non_blocking(s)==-1){
		LOG(L_ERR, "ERROR: init_tcpudp_sock: set non blocking failed\n");
	}
	
	if (bind(s, &su.s, sockaddru_len(su))==-1){
		LOG(L_ERR, "ERROR: init_tcpudp_sock: bind: %s [%d]\n",
				strerror(errno), errno);
		goto error;
	}
	if ((type==TCP_SOCK) && (listen(s, 128)==-1)){
		LOG(L_ERR, "ERROR: init_tcpudp_sock: listen: %s [%d]\n",
				strerror(errno), errno);
		goto error;
	}
	*sa_un=su;
	return s;
error:
	if (s!=-1) close(s);
	return -1;
}
Esempio n. 21
0
static int tcpconn_async_connect(struct socket_info* send_sock,
					union sockaddr_union* server, char *buf, unsigned len,
					struct tcp_connection** c, int *ret_fd)
{
	int fd, n;
	union sockaddr_union my_name;
	socklen_t my_name_len;
	struct tcp_connection* con;

	struct pollfd pf;

	unsigned int elapsed,to;
	int err;
	unsigned int err_len;
	int poll_err;
	char *ip;
	unsigned short port;
	struct timeval begin;

	/* create the socket */
	fd = socket(AF2PF(server->s.sa_family), SOCK_STREAM, 0);
	if (fd == -1){
		LM_ERR("socket: (%d) %s\n", errno, strerror(errno));
		return -1;
	}
	if (tcp_init_sock_opt(fd)<0){
		LM_ERR("tcp_init_sock_opt failed\n");
		goto error;
	}
	my_name_len = sockaddru_len(send_sock->su);
	memcpy( &my_name, &send_sock->su, my_name_len);
	su_setport( &my_name, 0);
	if (bind(fd, &my_name.s, my_name_len )!=0) {
		LM_ERR("bind failed (%d) %s\n", errno,strerror(errno));
		goto error;
	}

	/* attempt to do connect and see if we do block or not */
	poll_err = 0;
	elapsed = 0;
	to = hep_async_local_connect_timeout*1000;

	if (gettimeofday(&(begin), NULL)) {
		LM_ERR("Failed to get TCP connect start time\n");
		goto error;
	}

again:
	n = connect(fd, &server->s, sockaddru_len(*server));
	if (n == -1) {
		if (errno == EINTR){
			elapsed=get_time_diff(&begin);
			if (elapsed < to) goto again;
			else {
				LM_DBG("Local connect attempt failed \n");
				goto async_connect;
			}
		}
		if (errno != EINPROGRESS && errno!=EALREADY) {
			get_su_info(&server->s, ip, port);
			LM_ERR("[server=%s:%d] (%d) %s\n",ip, port, errno,strerror(errno));
			goto error;
		}
	} else goto local_connect;

	/* let's poll for a little */

	pf.fd = fd;
	pf.events = POLLOUT;

	while(1){
		elapsed = get_time_diff(&begin);
		if (elapsed < to)
			to -= elapsed;
		else {
			LM_DBG("Polling is overdue \n");
			goto async_connect;
		}

		n = poll(&pf, 1, to/1000);

		if (n < 0){
			if (errno == EINTR) continue;
			get_su_info(&server->s, ip, port);
			LM_ERR("poll/select failed:[server=%s:%d] (%d) %s\n",
				ip, port, errno, strerror(errno));
			goto error;
		} else if (n==0) /* timeout */ continue;

		if (pf.revents & (POLLERR|POLLHUP|POLLNVAL)){
			LM_ERR("poll error: flags %x\n", pf.revents);
			poll_err=1;
		}


		err_len=sizeof(err);
		getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &err_len);
		if ((err==0) && (poll_err==0)) goto local_connect;
		if (err!=EINPROGRESS && err!=EALREADY){
			get_su_info(&server->s, ip, port);
			LM_ERR("failed to retrieve SO_ERROR [server=%s:%d] (%d) %s\n",
				ip, port, err, strerror(err));
			goto error;
		}
	}

async_connect:
	LM_DBG("Create connection for async connect\n");
	/* create a new dummy connection */
	con = tcp_conn_create(fd, server, send_sock, S_CONN_CONNECTING);
	if (con==NULL) {
		LM_ERR("tcp_conn_create failed\n");
		goto error;
	}

	/* attach the write buffer to it */
	lock_get(&con->write_lock);

	if (add_write_chunk(con,buf,len,0) < 0) {
		LM_ERR("Failed to add the initial write chunk\n");
		/* FIXME - seems no more SHM now ...
		 * continue the async connect process ? */
	}

	lock_release(&con->write_lock);
	/* report an async, in progress connect */
	*c = con;
	return 0;

local_connect:
	con = tcp_conn_create(fd, server, send_sock, S_CONN_OK);
	if (con==NULL) {
		LM_ERR("tcp_conn_create failed, closing the socket\n");
		goto error;
	}
	*c = con;
	*ret_fd = fd;
	/* report a local connect */
	return 1;

error:
	close(fd);
	*c = NULL;
	return -1;
}
Esempio n. 22
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;
}
Esempio n. 23
0
static int hep_udp_read_req(struct socket_info *si, int* bytes_read)
{
	struct receive_info ri;
	int len;
#ifdef DYN_BUF
	char* buf;
#else
	static char buf [BUF_SIZE+1];
#endif
	char *tmp;
	unsigned int fromlen;
	str msg;

	struct hep_context *hep_ctx;

	int ret = 0;

	context_p ctx=NULL;

#ifdef DYN_BUF
	buf=pkg_malloc(BUF_SIZE+1);
	if (buf==0){
		LM_ERR("could not allocate receive buffer\n");
		goto error;
	}
#endif

	fromlen=sockaddru_len(si->su);
	len=recvfrom(bind_address->socket, buf, BUF_SIZE,0,&ri.src_su.s,&fromlen);
	if (len==-1){
		if (errno==EAGAIN)
			return 0;
		if ((errno==EINTR)||(errno==EWOULDBLOCK)|| (errno==ECONNREFUSED))
			return -1;
		LM_ERR("recvfrom:[%d] %s\n", errno, strerror(errno));
		return -2;
	}


	if (len<MIN_UDP_PACKET) {
		LM_DBG("probing packet received len = %d\n", len);
		return 0;
	}

	/* we must 0-term the messages, receive_msg expects it */
	buf[len]=0; /* no need to save the previous char */

	ri.bind_address = si;
	ri.dst_port = si->port_no;
	ri.dst_ip = si->address;
	ri.proto = si->proto;
	ri.proto_reserved1 = ri.proto_reserved2 = 0;

	su2ip_addr(&ri.src_ip, &ri.src_su);
	ri.src_port=su_getport(&ri.src_su);

	/* if udp we are sure that version 1 or 2 of the
	 * protocol is used */
	if ((hep_ctx = shm_malloc(sizeof(struct hep_context))) == NULL) {
		LM_ERR("no more shared memory!\n");
		return -1;
	}

	memset(hep_ctx, 0, sizeof(struct hep_context));
	memcpy(&hep_ctx->ri, &ri, sizeof(struct receive_info));


	if (len < 4) {
		LM_ERR("invalid message! too short!\n");
		return -1;
	}

	if (!memcmp(buf, HEP_HEADER_ID, HEP_HEADER_ID_LEN)) {
		/* HEPv3 */
		if (unpack_hepv3(buf, len, &hep_ctx->h)) {
			LM_ERR("hepv3 unpacking failed\n");
			return -1;
		}
	} else {
		/* HEPv2 */
		if (unpack_hepv12(buf, len, &hep_ctx->h)) {
			LM_ERR("hepv12 unpacking failed\n");
			return -1;
		}
	}

	/* set context for receive_msg */
	if ((ctx=context_alloc(CONTEXT_GLOBAL)) == NULL) {
		LM_ERR("failed to allocate new context! skipping...\n");
		goto error_free_hep;
	}

	memset(ctx, 0, context_size(CONTEXT_GLOBAL));

	context_put_ptr(CONTEXT_GLOBAL, ctx, hep_ctx_idx, hep_ctx);

	update_recv_info(&ri, &hep_ctx->h);

	/* run hep callbacks; set the current processing context
	 * to hep context; this way callbacks will have all the data
	 * needed */
	current_processing_ctx = ctx;
	ret=run_hep_cbs();
	if (ret < 0) {
		LM_ERR("failed to run hep callbacks\n");
		return -1;
	}
	current_processing_ctx = NULL;

	if (hep_ctx->h.version == 3) {
		/* HEPv3 */
		msg.len =
			hep_ctx->h.u.hepv3.payload_chunk.chunk.length- sizeof(hep_chunk_t);
		msg.s = hep_ctx->h.u.hepv3.payload_chunk.data;
	} else {
		/* HEPv12 */
		msg.len = len - hep_ctx->h.u.hepv12.hdr.hp_l;
		msg.s = buf + hep_ctx->h.u.hepv12.hdr.hp_l;

		if (hep_ctx->h.u.hepv12.hdr.hp_v == 2) {
			msg.s += sizeof(struct hep_timehdr);
			msg.len -= sizeof(struct hep_timehdr);
		}
	}

	if (ri.src_port==0){
		tmp=ip_addr2a(&ri.src_ip);
		LM_INFO("dropping 0 port packet for %s\n", tmp);
		return 0;
	}

	if (ret != HEP_SCRIPT_SKIP) {
		/* receive_msg must free buf too!*/
		receive_msg( msg.s, msg.len, &ri, ctx);
	}

	return 0;

error_free_hep:
	shm_free(hep_ctx);
	return -1;

}
Esempio n. 24
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;
}
Esempio n. 25
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;
}