Exemple #1
0
int ws_raw_writev(struct tcp_connection *c, int fd,
		const struct iovec *iov, int iovcnt, int tout)
{
	int n;

	/* we do not have any threosholds for ws
	struct timeval snd;

	start_expire_timer(snd,tcpthreshold);
	*/
	lock_get(&c->write_lock);

	/* optimize write for a single chunk */
	if (iovcnt == 1)
		n=tsend_stream(fd, iov[0].iov_base, iov[0].iov_len, tout);
	else
		n=tsend_stream_ev(fd, iov, iovcnt, tout);

	lock_release(&c->write_lock);
	/*
	 get_time_difference(snd, tcpthreshold, tout);
	 */

	return n;
}
Exemple #2
0
inline static int _hep_write_on_socket(struct tcp_connection *c, int fd,
												char *buf, int len){
	int n;

	lock_get(&c->write_lock);
	if (hep_async) {
		n=async_tsend_stream(c,fd,buf,len, hep_async_local_write_timeout);
	} else {
		n = tsend_stream(fd, buf, len, hep_send_timeout);
	}
	lock_release(&c->write_lock);

	return n;
}
Exemple #3
0
void release_tcpconn(struct tcp_connection* c, long state, int unix_sock)
{
	long response[2];
	
	LM_DBG("%s:%d %s releasing\n", __FILE__, __LINE__, __PRETTY_FUNCTION__);
		LM_DBG("releasing con %p, state %ld, fd=%d, id=%d\n",
				c, state, c->fd, c->id);
		LM_DBG("extra_data %p\n", c->extra_data);
		/* release req & signal the parent */
		c->reader_pid=0; /* reset it */
		if (c->fd!=-1){
			close(c->fd);
			c->fd=-1;
		}
		/* errno==EINTR, EWOULDBLOCK a.s.o todo */
		response[0]=(long)c;
		response[1]=state;
		
		if (tsend_stream(unix_sock, (char*)response, sizeof(response), -1)<=0)
			LM_ERR("tsend_stream failed\n");
}
Exemple #4
0
/*! \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){
			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;
}
Exemple #5
0
/**
 * Runs a JSON-RPC command (request or notification)
 * Params:
 *  dst: destination of the command
 *  cmd: comand to send
 *  id: if present, unique ID of the command, otherwise this is a notification
 *  ret: value returned in case of a request
 *
 * Returns:
 *  -2: communication error
 *  -3: reply error
 *   1: success
 */
static int jsonrpc_handle_cmd(union sockaddr_union *dst, char *cmd, int *id,
		pv_value_t *vret)
{
	int r, fd, ret = -2;
	unsigned int cmd_len;
	struct timeval begin;
	struct pollfd pf;
	int tout_left, total;
	cJSON *obj = NULL, *aux;

	char buffer[JSONRPC_DEFAULT_BUFFER_SIZE + 1/* null terminate */];

	/* connect to the destination */
	fd = jsonrpc_get_fd(dst);
	if (fd < 0) {
		LM_ERR("cannot get a connection to %s:%hu\n", JSONRPC_PRINT(dst));
		return -2;
	}

	/* we have a connection - send the command now */
	cmd_len = strlen(cmd);

	if (tsend_stream(fd, cmd, cmd_len, jrpc_write_timeout) < 0) {
		LM_ERR("cannot send stream to %s:%hu\n", JSONRPC_PRINT(dst));
		goto end;
	}
	
	/* notification - no need to wait for a reply */
	if (!id) {
		ret = 1;
		goto end;
	}

	/* read the reply */
	pf.fd = fd;
	pf.events = POLLIN;

	total = 0;
	gettimeofday(&begin, NULL);
	while (1) {
		/* compute how long we are allowed to block */
		tout_left = jrpc_read_timeout - (get_time_diff(&begin) / 1000);
		if (tout_left <= 0) {
			LM_ERR("read timeout reached (%s:%hu)\n", JSONRPC_PRINT(dst));
			goto end;
		}
		r = poll(&pf, 1, tout_left);
		if (r < 0) {
			if (errno == EINTR)
				continue;
			LM_ERR("poll failed: %s [%d\n", strerror(errno), errno);
			goto end;
		}
		if (pf.revents & POLLIN) {
			/* now we can read */
			r = read(fd, buffer + total, JSONRPC_DEFAULT_BUFFER_SIZE - total);
			if (r < 0) {
				if (errno == EINTR)
					continue;
				LM_ERR("cannot read reply from JSON-RPC server %s:%hu\n",
						JSONRPC_PRINT(dst));
				goto end;
			}
			total += r;
			buffer[total] = '\0';
			/* everything read - try to parse it now */
			obj = cJSON_Parse(buffer);
			if (!obj) {
				LM_DBG("could not parse json [%s] - perhapse we did not "
						"receive all of it, retrying!\n", buffer);
				continue;
			}
			/* yey, we have an object */
			break;
		} else if (pf.revents & POLLERR) {
			/* someting happened with the connection */
			LM_ERR("connection error to %s:%hu - %s:%d\n",
					JSONRPC_PRINT(dst), strerror(errno), errno);
			goto end;
		}
	}

	aux = cJSON_GetObjectItem(obj, "error");
	if (aux) {
		/* return the entire error */
		vret->rs.s = cJSON_Print(aux);
		vret->rs.len = strlen(vret->rs.s);
		vret->flags = PV_VAL_STR;
		LM_DBG("Error got from JSON-RPC: %s!\n", buffer);
		ret = -3;
		goto end;
	}

	aux = cJSON_GetObjectItem(obj, "result");
	if (!aux) {
		LM_WARN("Invalid reply from JSON-RPC: %s!\n", buffer);
		pv_get_null(NULL, NULL, vret);
		ret = -3;
		goto end;
	}

	if (aux->type == cJSON_Number)
		pv_get_sintval(NULL, NULL, vret, aux->valueint);
	else {
		vret->rs.s = cJSON_Print(aux);
		vret->rs.len = strlen(vret->rs.s);
		vret->flags = PV_VAL_STR;
	}

	ret = 1;
end:
	shutdown(fd, SHUT_RDWR);
	close(fd);
	return ret;
}