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; }
/*! \brief * handles a new connection, called internally by tcp_main_loop/handle_io. * \param si - pointer to one of the tcp socket_info structures on which * an io event was detected (connection attempt) * \return handle_* return convention: -1 on error, 0 on EAGAIN (no more * io events queued), >0 on success. success/error refer only to * the accept. */ static inline int handle_new_connect(struct socket_info* si) { union sockaddr_union su; struct tcp_connection* tcpconn; socklen_t su_len; int new_sock; /* got a connection on r */ su_len=sizeof(su); new_sock=accept(si->socket, &(su.s), &su_len); if (new_sock==-1){ if ((errno==EAGAIN)||(errno==EWOULDBLOCK)) return 0; LM_ERR("failed to accept connection(%d): %s\n", errno, strerror(errno)); return -1; } if (tcp_connections_no>=tcp_max_connections){ LM_ERR("maximum number of connections exceeded: %d/%d\n", tcp_connections_no, tcp_max_connections); close(new_sock); return 1; /* success, because the accept was succesfull */ } if (init_sock_opt(new_sock)<0){ LM_ERR("init_sock_opt failed\n"); close(new_sock); return 1; /* success, because the accept was succesfull */ } /* add socket to list */ tcpconn=tcpconn_new(new_sock, &su, si, si->proto, S_CONN_ACCEPT); if (tcpconn){ tcpconn->refcnt++; /* safe, not yet available to the outside world */ tcpconn_add(tcpconn); LM_DBG("new connection: %p %d flags: %04x\n", tcpconn, tcpconn->s, tcpconn->flags); /* pass it to a child */ if(send2child(tcpconn)<0){ LM_ERR("no children available\n"); TCPCONN_LOCK; tcpconn->refcnt--; if (tcpconn->refcnt==0){ close(tcpconn->s); _tcpconn_rm(tcpconn); }else tcpconn->timeout=0; /* force expire */ TCPCONN_UNLOCK; } }else{ /*tcpconn==0 */ LM_ERR("tcpconn_new failed, closing socket\n"); close(new_sock); } return 1; /* accept() was succesfull */ }
/* handle a new connection, called internally by tcp_main_loop */ static inline void handle_new_connect(struct socket_info* si, fd_set* sel_set, int* n) { union sockaddr_union su; struct tcp_connection* tcpconn; socklen_t su_len; int new_sock; if ((FD_ISSET(si->socket, sel_set))){ /* got a connection on r */ su_len=sizeof(su); new_sock=accept(si->socket, &(su.s), &su_len); (*n)--; if (new_sock==-1){ LOG(L_ERR, "WARNING: tcp_main_loop: error while accepting" " connection(%d): %s\n", errno, strerror(errno)); return; } if (init_sock_opt(new_sock)<0){ LOG(L_ERR, "ERROR: tcp_main_loop: init_sock_opt failed\n"); close(new_sock); return; } /* add socket to list */ tcpconn=tcpconn_new(new_sock, &su, si, si->proto, S_CONN_ACCEPT); if (tcpconn){ tcpconn->refcnt++; /* safe, not yet available to the outside world */ tcpconn_add(tcpconn); DBG("tcp_main_loop: new connection: %p %d\n", tcpconn, tcpconn->s); /* pass it to a child */ if(send2child(tcpconn)<0){ LOG(L_ERR,"ERROR: tcp_main_loop: no children " "available\n"); TCPCONN_LOCK; tcpconn->refcnt--; if (tcpconn->refcnt==0){ close(tcpconn->s); _tcpconn_rm(tcpconn); }else tcpconn->timeout=0; /* force expire */ TCPCONN_UNLOCK; } }else{ /*tcpconn==0 */ LOG(L_ERR, "ERROR: tcp_main_loop: tcpconn_new failed, " "closing socket\n"); close(new_sock); } } }
struct tcp_connection* tcpconn_connect(struct socket_info* send_sock, union sockaddr_union* server, int type) { 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 (init_sock_opt(s)<0){ LM_ERR("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_blocking_connect(s, &server->s, sockaddru_len(*server))<0){ LM_ERR("tcp_blocking_connect failed\n"); goto error; } con=tcpconn_new(s, server, send_sock, type, S_CONN_CONNECT); if (con==0){ LM_ERR("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; }