/** read from a mbuf. * (internal openssl use via the tls_mbuf method) * @return bytes read on success (0< ret <=dst_len), -1 on empty buffer & sets * should_retry_read, -1 on some other errors (w/o should_retry_read set). */ static int tls_bio_mbuf_read(BIO* b, char* dst, int dst_len) { struct tls_bio_mbuf_data* d; struct tls_mbuf* rd; int ret; ret = 0; if (likely(dst)) { #if OPENSSL_VERSION_NUMBER < 0x010100000L d = b->ptr; #else d = BIO_get_data(b); #endif BIO_clear_retry_flags(b); if (unlikely(d == 0 || d->rd->buf == 0)) { if (d == 0) BUG("tls_BIO_mbuf %p: read called with null b->ptr\n", b); else { /* this form of calling read with a null buffer is used as a shortcut when no data is available => simulate EAGIAN/WANT_READ */ TLS_BIO_DBG("read (%p, %p, %d) called with null read buffer" "(%p->%p) => simulating EAGAIN/WANT_READ\n", b, dst, dst_len, d, d->rd); BIO_set_retry_read(b); } return -1; } rd = d->rd; if (unlikely(rd->used == rd->pos && dst_len)) { /* mimic non-blocking read behaviour */ TLS_BIO_DBG("read (%p, %p, %d) called with full rd (%d)" " => simulating EAGAIN/WANT_READ\n", b, dst, dst_len, rd->used); BIO_set_retry_read(b); return -1; } ret = MIN_int(rd->used - rd->pos, dst_len); /* copy data from rd.buf into dst */ memcpy(dst, rd->buf+rd->pos, ret); TLS_BIO_DBG("read(%p, %p, %d) called with rd=%p pos=%d => %d bytes\n", b, dst, dst_len, rd->buf, rd->pos, ret); rd->pos += ret; /* if (unlikely(rd->pos < rd->used)) BIO_set_retry_read(b); */ } return ret; }
/** write to a mbuf. * (internal openssl use via the tls_mbuf method) * @return bytes written on success (0<= ret <=src_len), -1 on error or buffer * full (in this case sets should_retry_write). */ static int tls_bio_mbuf_write(BIO* b, const char* src, int src_len) { struct tls_bio_mbuf_data* d; struct tls_mbuf* wr; int ret; ret = 0; #if OPENSSL_VERSION_NUMBER < 0x010100000L d = b->ptr; #else d = BIO_get_data(b); #endif BIO_clear_retry_flags(b); if (unlikely(d == 0 || d->wr->buf == 0)) { if (d == 0) BUG("tls_BIO_mbuf %p: write called with null b->ptr\n", b); else { /* this form of calling write with a null buffer is used as a shortcut when no data is available => simulate EAGAIN/WANT_WRITE */ TLS_BIO_DBG("write (%p, %p, %d) called with null buffer" " => simulating WANT_WRITE\n", b, src, src_len); BIO_set_retry_write(b); } return -1; } wr = d->wr; if (unlikely(wr->size == wr->used && src_len)) { /* mimic non-blocking socket behaviour */ TLS_BIO_DBG("write (%p, %p, %d) called with full wr buffer (%d)" " => simulating WANT_WRITE\n", b, src, src_len, wr->used); BIO_set_retry_write(b); return -1; } ret = MIN_int(wr->size - wr->used, src_len); memcpy(wr->buf + wr->used, src, ret); wr->used += ret; /* if (unlikely(ret < src_len)) BIO_set_retry_write(); */ TLS_BIO_DBG("write called (%p, %p, %d) => %d\n", b, src, src_len, ret); return ret; }
int t_append_branches(void) { struct cell *t = NULL; struct sip_msg *orig_msg = NULL; short outgoings; int success_branch; str current_uri; str dst_uri, path, instance, ruid, location_ua; struct socket_info* si; int q, i, found; flag_t backup_bflags = 0; flag_t bflags = 0; int new_branch, branch_ret, lowest_ret; branch_bm_t added_branches; int replies_locked = 0; t = get_t(); if(t == NULL) { LM_ERR("cannot get transaction\n"); return -1; } LM_DBG("transaction %u:%u in status %d\n", t->hash_index, t->label, t->uas.status); /* test if transaction has already been canceled */ if (t->flags & T_CANCELED) { ser_error=E_CANCELED; return -1; } if ((t->uas.status >= 200 && t->uas.status<=399) || ((t->uas.status >= 600 && t->uas.status) && !(t->flags & (T_6xx | T_DISABLE_6xx))) ) { LM_DBG("transaction %u:%u in status %d: cannot append new branch\n", t->hash_index, t->label, t->uas.status); return -1; } /* set the lock on the transaction here */ LOCK_REPLIES(t); replies_locked = 1; outgoings = t->nr_of_outgoings; orig_msg = t->uas.request; LM_DBG("Call %.*s: %d (%d) outgoing branches\n",orig_msg->callid->body.len, orig_msg->callid->body.s,outgoings, nr_branches); lowest_ret=E_UNSPEC; added_branches=0; /* it's a "late" branch so the on_branch variable has already been reset by previous execution of t_forward_nonack: we use the saved value */ if (t->on_branch_delayed) { /* tell add_uac that it should run branch route actions */ set_branch_route(t->on_branch_delayed); } outgoings = t->nr_of_outgoings; /* not really sure that the following is needed */ set_branch_iterator(nr_branches-1); found = 0; while((current_uri.s=next_branch( ¤t_uri.len, &q, &dst_uri, &path, &bflags, &si, &ruid, &instance, &location_ua))) { LM_DBG("Current uri %.*s\n",current_uri.len, current_uri.s); for (i=0; i<nr_branches; i++) { if (t->uac[i].ruid.len == ruid.len && !memcmp(t->uac[i].ruid.s, ruid.s, ruid.len)) { LM_DBG("branch already added [%.*s]\n", ruid.len, ruid.s); found = 1; break; } } if (found) continue; setbflagsval(0, bflags); new_branch=add_uac( t, orig_msg, ¤t_uri, (dst_uri.len) ? (&dst_uri) : ¤t_uri, &path, 0, si, orig_msg->fwd_send_flags, orig_msg->rcv.proto, (dst_uri.len)?-1:UAC_SKIP_BR_DST_F, &instance, &ruid, &location_ua); /* test if cancel was received meanwhile */ if (t->flags & T_CANCELED) goto canceled; if (new_branch>=0) added_branches |= 1<<new_branch; else lowest_ret=MIN_int(lowest_ret, new_branch); } clear_branches(); LM_DBG("Call %.*s: %d (%d) outgoing branches after clear_branches()\n", orig_msg->callid->body.len, orig_msg->callid->body.s,outgoings, nr_branches); setbflagsval(0, backup_bflags); /* update message flags, if changed in branch route */ t->uas.request->flags = orig_msg->flags; if (added_branches==0) { if(lowest_ret!=E_CFG) LOG(L_ERR, "ERROR: t_append_branch: failure to add branches\n"); ser_error=lowest_ret; replies_locked = 0; UNLOCK_REPLIES(t); return lowest_ret; } ser_error=0; /* clear branch adding errors */ /* send them out now */ success_branch=0; /* since t_append_branch can only be called from REQUEST_ROUTE, always lock replies */ for (i=outgoings; i<t->nr_of_outgoings; i++) { if (added_branches & (1<<i)) { branch_ret=t_send_branch(t, i, orig_msg , 0, 0 /* replies are already locked */ ); if (branch_ret>=0){ /* some kind of success */ if (branch_ret==i) { /* success */ success_branch++; if (unlikely(has_tran_tmcbs(t, TMCB_REQUEST_OUT))) run_trans_callbacks_with_buf( TMCB_REQUEST_OUT, &t->uac[nr_branches].request, orig_msg, 0, -orig_msg->REQ_METHOD); } else /* new branch added */ added_branches |= 1<<branch_ret; } } } if (success_branch<=0) { /* return always E_SEND for now * (the real reason could be: denied by onsend routes, blacklisted, * send failed or any of the errors listed before + dns failed * when attempting dns failover) */ ser_error=E_SEND; /* else return the last error (?) */ /* the caller should take care and delete the transaction */ replies_locked = 0; UNLOCK_REPLIES(t); return -1; } ser_error=0; /* clear branch send errors, we have overall success */ set_kr(REQ_FWDED); replies_locked = 0; UNLOCK_REPLIES(t); return 1; canceled: DBG("t_append_branches: cannot append branches to a canceled transaction\n"); /* reset processed branches */ clear_branches(); /* restore backup flags from initial env */ setbflagsval(0, backup_bflags); /* update message flags, if changed in branch route */ t->uas.request->flags = orig_msg->flags; /* if needed unlock transaction's replies */ if (likely(replies_locked)) { /* restore the number of outgoing branches * since new branches have not been completed */ t->nr_of_outgoings = outgoings; replies_locked = 0; UNLOCK_REPLIES(t); } ser_error=E_CANCELED; return -1; }