/* creates a new tcp connection structure and informs the TCP Main on that * a +1 ref is set for the new conn ! * IMPORTANT - the function assumes you want to create a new TCP conn as * a result of a connect operation - the conn will be set as connect !! * Accepted connection are triggered internally only */ struct tcp_connection* tcp_conn_create(int sock, union sockaddr_union* su, struct socket_info* si, int state) { struct tcp_connection *c; /* create the connection structure */ c = tcp_conn_new(sock, su, si, state); if (c==NULL) return NULL; return (tcp_conn_send(c) == 0 ? c : NULL); }
/** OPEN user call * * @param epp Endpoint pair * @param acpass Active/passive * @param oflags Open flags * @param conn Connection * * Unlike in the spec we allow specifying the local address. This means * the implementation does not need to magically guess it, especially * considering there can be more than one local address. * * XXX We should be able to call active open on an existing listening * connection. * XXX We should be able to get connection structure immediately, before * establishment. */ tcp_error_t tcp_uc_open(inet_ep2_t *epp, acpass_t acpass, tcp_open_flags_t oflags, tcp_conn_t **conn) { tcp_conn_t *nconn; int rc; log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_uc_open(%p, %s, %s, %p)", epp, acpass == ap_active ? "active" : "passive", oflags == tcp_open_nonblock ? "nonblock" : "none", conn); nconn = tcp_conn_new(epp); rc = tcp_conn_add(nconn); if (rc != EOK) { tcp_conn_delete(nconn); return TCP_EEXISTS; } tcp_conn_lock(nconn); if (acpass == ap_active) { /* Synchronize (initiate) connection */ tcp_conn_sync(nconn); } if (oflags == tcp_open_nonblock) { tcp_conn_unlock(nconn); log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_uc_open -> %p", nconn); *conn = nconn; return TCP_EOK; } /* Wait for connection to be established or reset */ log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_uc_open: Wait for connection."); while (nconn->cstate == st_listen || nconn->cstate == st_syn_sent || nconn->cstate == st_syn_received) { fibril_condvar_wait(&nconn->cstate_cv, &nconn->lock); } if (nconn->cstate != st_established) { log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_uc_open: Connection was reset."); assert(nconn->cstate == st_closed); tcp_conn_unlock(nconn); return TCP_ERESET; } tcp_conn_unlock(nconn); log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_uc_open: Connection was established."); *conn = nconn; log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_uc_open -> %p", nconn); return TCP_EOK; }
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; }