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; }
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; }