static int w_tls_blocking_write(struct tcp_connection *c, int fd, const char *buf, size_t len) { int ret; lock_get(&c->write_lock); ret = tls_blocking_write(c, fd, buf, len, &tls_mgm_api); lock_release(&c->write_lock); return ret; }
static int wss_raw_writev(struct tcp_connection *c, int fd, const struct iovec *iov, int iovcnt, int tout) { struct timeval snd; int i, n, ret = 0; #ifdef TLS_DONT_WRITE_FRAGMENTS static char *buf = NULL; #endif start_expire_timer(snd,tcpthreshold); #ifndef TLS_DONT_WRITE_FRAGMENTS for (i = 0; i < iovcnt; i++) { n = tls_blocking_write(c, fd, iov[i].iov_base, iov[i].iov_len, &tls_mgm_api); if (n < 0) { ret = -1; goto end; } ret += n; } #else n = 0; for (i = 0; i < iovcnt; i++) n += iov[i].iov_len; buf = pkg_realloc(buf, n); if (!buf) { ret = -2; goto end; } n = 0; for (i = 0; i < iovcnt; i++) { memcpy(buf + n, iov[i].iov_base, iov[i].iov_len); n += iov[i].iov_len; } n = tls_blocking_write(c, fd, buf, n, &tls_mgm_api); #endif /* TLS_DONT_WRITE_FRAGMENTS */ end: get_time_difference(snd, tcpthreshold, tout); return ret; }
static int wss_raw_writev(struct tcp_connection *c, int fd, const struct iovec *iov, int iovcnt, int tout) { int i, n, ret = 0; #ifdef TLS_DONT_WRITE_FRAGMENTS static char *buf = NULL; #endif #ifndef TLS_DONT_WRITE_FRAGMENTS lock_get(&c->write_lock); for (i = 0; i < iovcnt; i++) { n = tls_blocking_write(c, fd, iov[i].iov_base, iov[i].iov_len, &tls_mgm_api); if (n < 0) { ret = -1; goto end; } ret += n; } #else n = 0; for (i = 0; i < iovcnt; i++) n += iov[i].iov_len; buf = pkg_realloc(buf, n); if (!buf) { ret = -2; goto end; } n = 0; for (i = 0; i < iovcnt; i++) { memcpy(buf + n, iov[i].iov_base, iov[i].iov_len); n += iov[i].iov_len; } lock_get(&c->write_lock); n = tls_blocking_write(c, fd, buf, n, &tls_mgm_api); #endif /* TLS_DONT_WRITE_FRAGMENTS */ end: lock_release(&c->write_lock); return ret; }
/* finds a tcpconn & sends on it */ int tcp_send(int type, char* buf, unsigned len, union sockaddr_union* to, int id) { struct tcp_connection *c; struct tcp_connection *tmp; struct ip_addr ip; int port; int fd; long response[2]; int n; port=0; if (to){ su2ip_addr(&ip, to); port=su_getport(to); c=tcpconn_get(id, &ip, port, TCP_CON_SEND_TIMEOUT); }else if (id){ c=tcpconn_get(id, 0, 0, TCP_CON_SEND_TIMEOUT); }else{ LOG(L_CRIT, "BUG: tcp_send called with null id & to\n"); return -1; } if (id){ if (c==0) { if (to){ /* try again w/o id */ c=tcpconn_get(0, &ip, port, TCP_CON_SEND_TIMEOUT); goto no_id; }else{ LOG(L_ERR, "ERROR: tcp_send: id %d not found, dropping\n", id); return -1; } }else goto get_fd; } no_id: if (c==0){ DBG("tcp_send: no open tcp connection found, opening new one\n"); /* create tcp connection */ if ((c=tcpconn_connect(to, type))==0){ LOG(L_ERR, "ERROR: tcp_send: connect failed\n"); return -1; } c->refcnt++; /* safe to do it w/o locking, it's not yet available to the rest of the world */ fd=c->s; /* send the new tcpconn to "tcp main" */ response[0]=(long)c; response[1]=CONN_NEW; n=send_all(unix_tcp_sock, response, sizeof(response)); if (n<=0){ LOG(L_ERR, "BUG: tcp_send: failed write: %s (%d)\n", strerror(errno), errno); n=-1; goto end; } n=send_fd(unix_tcp_sock, &c, sizeof(c), c->s); if (n<=0){ LOG(L_ERR, "BUG: tcp_send: failed send_fd: %s (%d)\n", strerror(errno), errno); n=-1; goto end; } goto send_it; } get_fd: /* todo: see if this is not the same process holding * c and if so send directly on c->fd */ DBG("tcp_send: tcp connection found (%p), acquiring fd\n", c); /* get the fd */ response[0]=(long)c; response[1]=CONN_GET_FD; n=send_all(unix_tcp_sock, response, sizeof(response)); if (n<=0){ LOG(L_ERR, "BUG: tcp_send: failed to get fd(write):%s (%d)\n", strerror(errno), errno); n=-1; goto release_c; } DBG("tcp_send, c= %p, n=%d\n", c, n); tmp=c; n=receive_fd(unix_tcp_sock, &c, sizeof(c), &fd); if (n<=0){ LOG(L_ERR, "BUG: tcp_send: failed to get fd(receive_fd):" " %s (%d)\n", strerror(errno), errno); n=-1; goto release_c; } if (c!=tmp){ LOG(L_CRIT, "BUG: tcp_send: get_fd: got different connection:" " %p (id= %d, refcnt=%d state=%d != " " %p (id= %d, refcnt=%d state=%d (n=%d)\n", c, c->id, c->refcnt, c->state, tmp, tmp->id, tmp->refcnt, tmp->state, n ); n=-1; /* fail */ goto end; } DBG("tcp_send: after receive_fd: c= %p n=%d fd=%d\n",c, n, fd); send_it: DBG("tcp_send: sending...\n"); lock_get(&c->write_lock); #ifdef USE_TLS if (c->type==PROTO_TLS) n=tls_blocking_write(c, fd, buf, len); else #endif n=tcp_blocking_write(c, fd, buf, len); lock_release(&c->write_lock); DBG("tcp_send: after write: c= %p n=%d fd=%d\n",c, n, fd); DBG("tcp_send: buf=\n%.*s\n", (int)len, buf); if (n<0){ LOG(L_ERR, "ERROR: tcp_send: failed to send\n"); /* error on the connection , mark it as bad and set 0 timeout */ c->state=S_CONN_BAD; c->timeout=0; /* tell "main" it should drop this (optional it will t/o anyway?)*/ response[0]=(long)c; response[1]=CONN_ERROR; n=send_all(unix_tcp_sock, response, sizeof(response)); /* CONN_ERROR will auto-dec refcnt => we must not call tcpconn_put !!*/ if (n<=0){ LOG(L_ERR, "BUG: tcp_send: error return failed (write):%s (%d)\n", strerror(errno), errno); n=-1; } close(fd); return n; /* error return, no tcpconn_put */ } end: close(fd); release_c: tcpconn_put(c); /* release c (lock; dec refcnt; unlock) */ return n; }
/*! \brief Finds a tcpconn & sends on it */ int tcp_send(struct socket_info* send_sock, int type, char* buf, unsigned len, union sockaddr_union* to, int id) { struct tcp_connection *c; struct tcp_connection *tmp; struct ip_addr ip; int port; int fd; long response[2]; int n; struct timeval get,rcv,snd; port=0; reset_tcp_vars(tcpthreshold); start_expire_timer(get,tcpthreshold); if (to){ su2ip_addr(&ip, to); port=su_getport(to); c=tcpconn_get(id, &ip, port, tcp_con_lifetime); }else if (id){ c=tcpconn_get(id, 0, 0, tcp_con_lifetime); }else{ LM_CRIT("tcp_send called with null id & to\n"); get_time_difference(get,tcpthreshold,tcp_timeout_con_get); return -1; } if (id){ if (c==0) { if (to){ /* try again w/o id */ c=tcpconn_get(0, &ip, port, tcp_con_lifetime); goto no_id; }else{ LM_ERR("id %d not found, dropping\n", id); get_time_difference(get,tcpthreshold,tcp_timeout_con_get); return -1; } }else goto get_fd; } no_id: if (c==0){ if (tcp_no_new_conn) { return -1; } LM_DBG("no open tcp connection found, opening new one\n"); /* create tcp connection */ if ((c=tcpconn_connect(send_sock, to, type))==0){ LM_ERR("connect failed\n"); get_time_difference(get,tcpthreshold,tcp_timeout_con_get); return -1; } c->refcnt++; /* safe to do it w/o locking, it's not yet available to the rest of the world */ fd=c->s; /* send the new tcpconn to "tcp main" */ response[0]=(long)c; response[1]=CONN_NEW; n=send_fd(unix_tcp_sock, response, sizeof(response), c->s); get_time_difference(get,tcpthreshold,tcp_timeout_con_get); if (n<=0){ LM_ERR("failed send_fd: %s (%d)\n", strerror(errno), errno); n=-1; goto end; } goto send_it; } get_fd: get_time_difference(get,tcpthreshold,tcp_timeout_con_get); /* todo: see if this is not the same process holding * c and if so send directly on c->fd */ LM_DBG("tcp connection found (%p), acquiring fd\n", c); /* get the fd */ response[0]=(long)c; response[1]=CONN_GET_FD; start_expire_timer(rcv,tcpthreshold); n=send_all(unix_tcp_sock, response, sizeof(response)); if (n<=0){ LM_ERR("failed to get fd(write):%s (%d)\n", strerror(errno), errno); n=-1; get_time_difference(rcv,tcpthreshold,tcp_timeout_receive_fd); goto release_c; } LM_DBG("c= %p, n=%d\n", c, n); tmp=c; n=receive_fd(unix_tcp_sock, &c, sizeof(c), &fd, MSG_WAITALL); get_time_difference(rcv,tcpthreshold,tcp_timeout_receive_fd); if (n<=0){ LM_ERR("failed to get fd(receive_fd):" " %s (%d)\n", strerror(errno), errno); n=-1; goto release_c; } if (c!=tmp){ LM_CRIT("got different connection:" " %p (id= %d, refcnt=%d state=%d != " " %p (id= %d, refcnt=%d state=%d (n=%d)\n", c, c->id, c->refcnt, c->state, tmp, tmp->id, tmp->refcnt, tmp->state, n ); n=-1; /* fail */ goto end; } LM_DBG("after receive_fd: c= %p n=%d fd=%d\n",c, n, fd); send_it: LM_DBG("sending...\n"); lock_get(&c->write_lock); #ifdef USE_TLS if (c->type==PROTO_TLS) n=tls_blocking_write(c, fd, buf, len); else #endif /* n=tcp_blocking_write(c, fd, buf, len); */ start_expire_timer(snd,tcpthreshold); n=tsend_stream(fd, buf, len, tcp_send_timeout*1000); get_time_difference(snd,tcpthreshold,tcp_timeout_send); stop_expire_timer(get,tcpthreshold,0,buf,(int)len,1); lock_release(&c->write_lock); LM_DBG("after write: c= %p n=%d fd=%d\n",c, n, fd); LM_DBG("buf=\n%.*s\n", (int)len, buf); if (n<0){ LM_ERR("failed to send\n"); /* error on the connection , mark it as bad and set 0 timeout */ c->state=S_CONN_BAD; c->timeout=0; /* tell "main" it should drop this (optional it will t/o anyway?)*/ response[0]=(long)c; response[1]=CONN_ERROR; n=send_all(unix_tcp_sock, response, sizeof(response)); /* CONN_ERROR will auto-dec refcnt => we must not call tcpconn_put !!*/ if (n<=0){ LM_ERR("return failed (write):%s (%d)\n", strerror(errno), errno); } close(fd); return -1; /* error return, no tcpconn_put */ } end: close(fd); release_c: tcpconn_put(c); /* release c (lock; dec refcnt; unlock) */ return n; }
static int proto_tls_send(struct socket_info* send_sock, char* buf, unsigned int len, union sockaddr_union* to, int id) { struct tcp_connection *c; struct ip_addr ip; int port; int fd, n; struct tls_data* data; if (to){ su2ip_addr(&ip, to); port=su_getport(to); n = tcp_conn_get(id, &ip, port, PROTO_TLS, &c, &fd); }else if (id){ n = tcp_conn_get(id, 0, 0, PROTO_NONE, &c, &fd); }else{ LM_CRIT("prot_tls_send called with null id & to\n"); return -1; } if (n<0) { /* error during conn get, return with error too */ LM_ERR("failed to acquire connection\n"); return -1; } /* was connection found ?? */ if (c==0) { if (tcp_no_new_conn) { return -1; } LM_DBG("no open tcp connection found, opening new one\n"); /* create tcp connection */ if ((c=tls_sync_connect(send_sock, to, &fd))==0) { LM_ERR("connect failed\n"); return -1; } goto send_it; } /* now we have a connection, let's what we can do with it */ /* BE CAREFUL now as we need to release the conn before exiting !!! */ if (fd==-1) { /* connection is not writable because of its state */ /* return error, nothing to do about it */ tcp_conn_release(c, 0); return -1; } send_it: /* if there is pending tracing data on a connection startet by us * (connected) -> flush it * As this is a write op, we look only for connected conns, not to conflict * with accepted conns (flushed on read op) */ if ( (c->flags&F_CONN_ACCEPTED)==0 && c->proto_flags & F_TLS_TRACE_READY ) { data = c->proto_data; /* send the message if set from tls_mgm */ if ( data->message ) { send_trace_message( data->message, t_dst); data->message = NULL; } /* don't allow future traces for this connection */ data->tprot = 0; data->dest = 0; c->proto_flags &= ~( F_TLS_TRACE_READY ); } LM_DBG("sending via fd %d...\n",fd); lock_get(&c->write_lock); n = tls_blocking_write(c, fd, buf, len, &tls_mgm_api); lock_release(&c->write_lock); tcp_conn_set_lifetime( c, tcp_con_lifetime); LM_DBG("after write: c= %p n=%d fd=%d\n",c, n, fd); LM_DBG("buf=\n%.*s\n", (int)len, buf); if (n<0){ LM_ERR("failed to send\n"); c->state=S_CONN_BAD; if (c->proc_id != process_no) close(fd); tcp_conn_release(c, 0); return -1; } /* only close the FD if not already in the context of our process either we just connected, or main sent us the FD */ if (c->proc_id != process_no) close(fd); /* mark the ID of the used connection (tracing purposes) */ last_outgoing_tcp_id = c->id; tcp_conn_release(c, 0); return n; }
static int proto_tls_send(struct socket_info* send_sock, char* buf, unsigned int len, union sockaddr_union* to, int id) { struct tcp_connection *c; struct ip_addr ip; int port; int fd, n; if (to){ su2ip_addr(&ip, to); port=su_getport(to); n = tcp_conn_get(id, &ip, port, &c, &fd); }else if (id){ n = tcp_conn_get(id, 0, 0, &c, &fd); }else{ LM_CRIT("prot_tls_send called with null id & to\n"); return -1; } if (n<0) { /* error during conn get, return with error too */ LM_ERR("failed to aquire connection\n"); return -1; } /* was connection found ?? */ if (c==0) { if (tcp_no_new_conn) { return -1; } LM_DBG("no open tcp connection found, opening new one\n"); /* create tcp connection */ if ((c=tls_sync_connect(send_sock, to, &fd))==0) { LM_ERR("connect failed\n"); return -1; } goto send_it; } /* now we have a connection, let's what we can do with it */ /* BE CAREFUL now as we need to release the conn before exiting !!! */ if (fd==-1) { /* connection is not writable because of its state */ /* return error, nothing to do about it */ tcp_conn_release(c, 0); return -1; } send_it: LM_DBG("sending via fd %d...\n",fd); n = tls_blocking_write(c, fd, buf, len); tcp_conn_set_lifetime( c, tcp_con_lifetime); LM_DBG("after write: c= %p n=%d fd=%d\n",c, n, fd); LM_DBG("buf=\n%.*s\n", (int)len, buf); if (n<0){ LM_ERR("failed to send\n"); c->state=S_CONN_BAD; if (c->proc_id != process_no) close(fd); tcp_conn_release(c, 0); return -1; } /* only close the FD if not already in the context of our process either we just connected, or main sent us the FD */ if (c->proc_id != process_no) close(fd); tcp_conn_release(c, 0); return n; }