Пример #1
0
extern t_connection * s2s_create(char const * server, unsigned short def_port, t_conn_class cclass)
{
	struct sockaddr_in	addr, laddr;
	psock_t_socklen		laddr_len;
	unsigned int		ip;
	unsigned short		port;
	int			sock, connected;
	t_connection		* c;
	char			* p, * tserver;

	ASSERT(server,NULL);
	tserver=xstrdup(server);
	p=std::strchr(tserver,':');
	if (p) {
		port=(unsigned short)std::strtoul(p+1,NULL,10);
		*p='\0';
	} else {
		port=def_port;
	}

	if ((sock=net_socket(PSOCK_SOCK_STREAM))<0) {
		eventlog(eventlog_level_error,__FUNCTION__,"error creating s2s socket");
		xfree(tserver);
		return NULL;
	}

	std::memset(&addr,0,sizeof(addr));
	addr.sin_family = PSOCK_AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr= net_inet_addr(tserver);
	xfree(tserver);

	eventlog(eventlog_level_info,__FUNCTION__,"try make s2s connection to {}",server);
	if (psock_connect(sock,(struct sockaddr *)&addr,sizeof(addr))<0) {
		if (psock_errno()!=PSOCK_EWOULDBLOCK && psock_errno() != PSOCK_EINPROGRESS) {
			eventlog(eventlog_level_error,__FUNCTION__,"error connecting to {} (psock_connect: {})",server,pstrerror(psock_errno()));
			psock_close(sock);
			return NULL;
		}
		connected=0;
		eventlog(eventlog_level_info,__FUNCTION__,"connection to s2s server {} is in progress",server);
	} else {
		connected=1;
		eventlog(eventlog_level_info,__FUNCTION__,"connected to s2s server {}",server);
	}
	laddr_len=sizeof(laddr);
	std::memset(&laddr,0,sizeof(laddr));
	ip=port=0;
	if (psock_getsockname(sock,(struct sockaddr *)&laddr,&laddr_len)<0) {
		eventlog(eventlog_level_error,__FUNCTION__,"unable to get local socket info");
	} else {
		if (laddr.sin_family != PSOCK_AF_INET) {
			eventlog(eventlog_level_error,__FUNCTION__,"got bad socket family {}",laddr.sin_family);
		} else {
			ip=ntohl(laddr.sin_addr.s_addr);
			port=ntohs(laddr.sin_port);
		}
	}
	if (!(c=d2cs_conn_create(sock,ip,port, ntohl(addr.sin_addr.s_addr), ntohs(addr.sin_port)))) {
		eventlog(eventlog_level_error,__FUNCTION__,"error create s2s connection");
		psock_close(sock);
		return NULL;
	}
	if (connected) {
		if (conn_add_fd(c,fdwatch_type_read, d2cs_server_handle_tcp)<0) {
		    eventlog(eventlog_level_error, __FUNCTION__, "error adding socket {} to fdwatch pool (max sockets?)",sock);
		    d2cs_conn_set_state(c,conn_state_destroy);
		    return NULL;
		}
		d2cs_conn_set_state(c,conn_state_init);
	} else {
		if (conn_add_fd(c, fdwatch_type_write, d2cs_server_handle_tcp)<0) {
		    eventlog(eventlog_level_error, __FUNCTION__, "error adding socket {} to fdwatch pool (max sockets?)",sock);
		    d2cs_conn_set_state(c,conn_state_destroy);
		    return NULL;
		}
		d2cs_conn_set_state(c,conn_state_connecting);
	}
	d2cs_conn_set_class(c,cclass);
	return c;
}
Пример #2
0
static int sd_accept(t_addr const * curr_laddr, t_laddr_info const * laddr_info, int ssocket, int usocket)
{
    char               tempa[32];
    int                csocket;
    struct sockaddr_in caddr;
    psock_t_socklen    caddr_len;
    unsigned int       raddr;
    unsigned short     rport;

    if (!addr_get_addr_str(curr_laddr,tempa,sizeof(tempa)))
	strcpy(tempa,"x.x.x.x:x");

    /* accept the connection */
    memset(&caddr,0,sizeof(caddr)); /* not sure if this is needed... modern systems are ok anyway */
    caddr_len = sizeof(caddr);
    if ((csocket = psock_accept(ssocket,(struct sockaddr *)&caddr,&caddr_len))<0)
    {
	/* BSD, POSIX error for aborted connections, SYSV often uses EAGAIN or EPROTO */
	if (
#ifdef PSOCK_EWOULDBLOCK
	    psock_errno()==PSOCK_EWOULDBLOCK ||
#endif
#ifdef PSOCK_ECONNABORTED
	    psock_errno()==PSOCK_ECONNABORTED ||
#endif
#ifdef PSOCK_EPROTO
	    psock_errno()==PSOCK_EPROTO ||
#endif
	    0)
	    eventlog(eventlog_level_error,"sd_accept","client aborted connection on %s (psock_accept: %s)",tempa,strerror(psock_errno()));
	else /* EAGAIN can mean out of resources _or_ connection aborted :( */
	    if (
#ifdef PSOCK_EINTR
		psock_errno()!=PSOCK_EINTR &&
#endif
		1)
		eventlog(eventlog_level_error,"sd_accept","could not accept new connection on %s (psock_accept: %s)",tempa,strerror(psock_errno()));
	return -1;
    }

#ifdef HAVE_POLL
    if (csocket>=BNETD_MAX_SOCKETS) /* This check is a bit too strict (csocket is probably
                                     * greater than the number of connections) but this makes
                                     * life easier later.
                                     */
    {
	eventlog(eventlog_level_error,"sd_accept","csocket is beyond range allowed by BNETD_MAX_SOCKETS for poll() (%d>=%d)",csocket,BNETD_MAX_SOCKETS);
	psock_close(csocket);
	return -1;
    }
#else
# ifdef FD_SETSIZE
    if (csocket>=FD_SETSIZE) /* fd_set size is determined at compile time */
    {
	eventlog(eventlog_level_error,"sd_accept","csocket is beyond range allowed by FD_SETSIZE for select() (%d>=%d)",csocket,FD_SETSIZE);
	psock_close(csocket);
	return -1;
    }
# endif
#endif
    if (ipbanlist_check(inet_ntoa(caddr.sin_addr))!=0)
    {
	eventlog(eventlog_level_info,"sd_accept","[%d] connection from banned address %s denied (closing connection)",csocket,inet_ntoa(caddr.sin_addr));
	psock_close(csocket);
	return -1;
    }

    eventlog(eventlog_level_info,"sd_accept","[%d] accepted connection from %s on %s",csocket,addr_num_to_addr_str(ntohl(caddr.sin_addr.s_addr),ntohs(caddr.sin_port)),tempa);

    if (prefs_get_use_keepalive())
    {
	int val=1;

	if (psock_setsockopt(csocket,PSOCK_SOL_SOCKET,PSOCK_SO_KEEPALIVE,&val,(psock_t_socklen)sizeof(val))<0)
	    eventlog(eventlog_level_error,"sd_accept","[%d] could not set socket option SO_KEEPALIVE (psock_setsockopt: %s)",csocket,strerror(psock_errno()));
	/* not a fatal error */
    }

    {
	struct sockaddr_in rsaddr;
	psock_t_socklen    rlen;

	memset(&rsaddr,0,sizeof(rsaddr)); /* not sure if this is needed... modern systems are ok anyway */
	rlen = sizeof(rsaddr);
	if (psock_getsockname(csocket,(struct sockaddr *)&rsaddr,&rlen)<0)
	{
	    eventlog(eventlog_level_error,"sd_accept","[%d] unable to determine real local port (psock_getsockname: %s)",csocket,strerror(psock_errno()));
	    /* not a fatal error */
	    raddr = addr_get_ip(curr_laddr);
	    rport = addr_get_port(curr_laddr);
	}
	else
	{
	    if (rsaddr.sin_family!=PSOCK_AF_INET)
	    {
		eventlog(eventlog_level_error,"sd_accept","local address returned with bad address family %d",(int)rsaddr.sin_family);
		/* not a fatal error */
		raddr = addr_get_ip(curr_laddr);
		rport = addr_get_port(curr_laddr);
	    }
	    else
	    {
		raddr = ntohl(rsaddr.sin_addr.s_addr);
		rport = ntohs(rsaddr.sin_port);
	    }
	}
    }

    if (psock_ctl(csocket,PSOCK_NONBLOCK)<0)
    {
	eventlog(eventlog_level_error,"sd_accept","[%d] could not set TCP socket to non-blocking mode (closing connection) (psock_ctl: %s)",csocket,strerror(psock_errno()));
	psock_close(csocket);
	return -1;
    }

    {
	t_connection * c;

	if (!(c = conn_create(csocket,usocket,raddr,rport,addr_get_ip(curr_laddr),addr_get_port(curr_laddr),ntohl(caddr.sin_addr.s_addr),ntohs(caddr.sin_port))))
	{
	    eventlog(eventlog_level_error,"sd_accept","[%d] unable to create new connection (closing connection)",csocket);
	    psock_close(csocket);
	    return -1;
	}

	eventlog(eventlog_level_debug,"sd_accept","[%d] client connected to a %s listening address",csocket,laddr_type_get_str(laddr_info->type));
	switch (laddr_info->type)
	{
	case laddr_type_irc:
	    conn_set_class(c,conn_class_irc);
	    conn_set_state(c,conn_state_connected);
	    break;
	case laddr_type_telnet:
	    conn_set_class(c,conn_class_telnet);
	    conn_set_state(c,conn_state_connected);
	    break;
	case laddr_type_bnet:
	default:
	    /* We have to wait for an initial "magic" byte on bnet connections to
             * tell us exactly what connection class we are dealing with.
             */
	    break;
	}
    }

    return 0;
}