Refactoring of RESTCONF/TLS close code

Single closing function: restconf_close_ssl_socket
Added constant HTTP_ON_HTTPS_REPLY for http request on https socket
This commit is contained in:
Olof hagsand 2022-09-13 22:55:11 +02:00
parent e39d18d59f
commit c1e4595949
11 changed files with 354 additions and 272 deletions

View file

@ -164,7 +164,12 @@ restconf_stream_free(restconf_stream_data *sd)
return 0;
}
/*! Create restconf connection struct
/*! Create restconf connection struct, per connect, ie transient
*
* @param[in] h Clixon handle
* @param[in] s Connected socket
* @param[in] rsock Backpointer to server struct
* @see restconf_conn_free
*/
restconf_conn *
restconf_conn_new(clicon_handle h,
@ -180,22 +185,30 @@ restconf_conn_new(clicon_handle h,
memset(rc, 0, sizeof(restconf_conn));
rc->rc_h = h;
rc->rc_s = s;
rc->rc_callhome = rsock->rs_callhome;
rc->rc_socket = rsock;
INSQ(rc, rsock->rs_conns);
clicon_debug(1, "%s %p", __FUNCTION__, rc);
return rc;
}
/*! Free clixon/cbuf resources related to a connection
* @param[in] rc restconf connection
*/
int
static int
restconf_conn_free(restconf_conn *rc)
{
int retval = -1;
restconf_stream_data *sd;
restconf_socket *rsock;
restconf_conn *rc1;
clicon_debug(1, "%s", __FUNCTION__);
if (rc == NULL){
clicon_err(OE_RESTCONF, EINVAL, "rc is NULL");
return -1;
goto done;
}
clicon_debug(1, "%s %p", __FUNCTION__, rc);
#ifdef HAVE_LIBNGHTTP2
if (rc->rc_ngsession)
nghttp2_session_del(rc->rc_ngsession);
@ -206,8 +219,21 @@ restconf_conn_free(restconf_conn *rc)
if (sd)
restconf_stream_free(sd);
}
/* Free connect from server sock */
if ((rsock = rc->rc_socket) != NULL &&
(rc1 = rsock->rs_conns) != NULL){
do {
if (rc == rc1){
DELQ(rc, rsock->rs_conns, restconf_conn *);
break;
}
rc1 = NEXTQ(restconf_conn *, rc1);
} while (rc1 && rc1 != rsock->rs_conns);
}
free(rc);
return 0;
retval = 0;
done:
return retval;
}
/*! Given SSL connection, get peer certificate one-line name
@ -337,20 +363,27 @@ restconf_connection_sanity(clicon_handle h,
/* Write buf to socket
* see also this function in restcont_api_openssl.c
* @retval 1 OK
* @retval 0 OK, but socket write returned error, caller should close rc
* @retval -1 Error
*/
static int
native_buf_write(clicon_handle h,
char *buf,
size_t buflen,
int s,
SSL *ssl,
restconf_socket *rsock)
restconf_conn *rc)
{
int retval = -1;
ssize_t len;
ssize_t totlen = 0;
int er;
SSL *ssl;
if (rc == NULL){
clicon_err(OE_RESTCONF, EINVAL, "rc is NULL");
goto done;
}
ssl = rc->rc_ssl;
/* Two problems with debugging buffers that this fixes:
* 1. they are not "strings" in the sense they are not NULL-terminated
* 2. they are often very long
@ -376,12 +409,9 @@ native_buf_write(clicon_handle h,
case SSL_ERROR_SYSCALL: /* 5 */
if (er == ECONNRESET || /* Connection reset by peer */
er == EPIPE) { /* Reading end of socket is closed */
if (ssl){
SSL_free(ssl);
}
if (restconf_connection_close(h, s, rsock) < 0)
if (0 && restconf_close_ssl_socket(rc, __FUNCTION__, 0) < 0)
goto done;
goto ok; /* Close socket and ssl */
goto closed; /* Close socket and ssl */
}
else if (er == EAGAIN){
clicon_debug(1, "%s write EAGAIN", __FUNCTION__);
@ -402,7 +432,7 @@ native_buf_write(clicon_handle h,
}
}
else{
if ((len = write(s, buf+totlen, buflen-totlen)) < 0){
if ((len = write(rc->rc_s, buf+totlen, buflen-totlen)) < 0){
switch (errno){
case EAGAIN: /* Operation would block */
clicon_debug(1, "%s write EAGAIN", __FUNCTION__);
@ -412,9 +442,9 @@ native_buf_write(clicon_handle h,
// case EBADF: // XXX if this happens there is some larger error
case ECONNRESET: /* Connection reset by peer */
case EPIPE: /* Broken pipe */
if (restconf_connection_close(h, s, rsock) < 0)
if (0 && restconf_close_ssl_socket(rc, __FUNCTION__, 0) < 0)
goto done;
goto ok; /* Close socket and ssl */
goto closed; /* Close socket and ssl */
break;
default:
clicon_err(OE_UNIX, errno, "write %d", errno);
@ -426,27 +456,30 @@ native_buf_write(clicon_handle h,
}
totlen += len;
} /* while */
ok:
retval = 0;
retval = 1;
done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
return retval;
closed:
retval = 0;
goto done;
}
/*! Send early handcoded bad request reply before actual packet received, just after accept
* @param[in] h Clixon handle
* @param[in] s Socket
* @param[in] ssl If set, it will be freed
* @param[in] media
* @param[in] body If given add message body using media
* @param[in] rc Restconf connection, note may be closed in this
* @retval 1 OK
* @retval 0 OK, but socket write returned error, caller should close rc
* @retval -1 Error
* @see restconf_badrequest which can only be called in a request context
*/
static int
native_send_badrequest(clicon_handle h,
int s,
SSL *ssl,
char *media,
char *body,
restconf_socket *rsock)
native_send_badrequest(clicon_handle h,
char *media,
char *body,
restconf_conn *rc)
{
int retval = -1;
cbuf *cb = NULL;
@ -466,9 +499,7 @@ native_send_badrequest(clicon_handle h,
cprintf(cb, "\r\n");
if (body)
cprintf(cb, "%s\r\n", body);
if (native_buf_write(h, cbuf_get(cb), cbuf_len(cb), s, ssl, rsock) < 0) // XXX rsock
goto done;
retval = 0;
retval = native_buf_write(h, cbuf_get(cb), cbuf_len(cb), rc);
done:
if (cb)
cbuf_free(cb);
@ -579,9 +610,8 @@ read_regular(restconf_conn *rc,
switch(errno){
case ECONNRESET:/* Connection reset by peer */
clicon_debug(1, "%s %d Connection reset by peer", __FUNCTION__, rc->rc_s);
if (restconf_connection_close(rc->rc_h, rc->rc_s, rc->rc_socket) < 0)
if (restconf_close_ssl_socket(rc, __FUNCTION__, 0) < 0)
goto done;
restconf_conn_free(rc);
retval = 0; /* Close socket and ssl */
goto done;
break;
@ -614,10 +644,10 @@ read_regular(restconf_conn *rc,
* @retval 1 OK
*/
static int
restconf_http1_process(restconf_conn *rc,
char *buf,
size_t n,
int *readmore)
restconf_http1_process(restconf_conn *rc,
char *buf,
size_t n,
int *readmore)
{
int retval = -1;
restconf_stream_data *sd;
@ -680,7 +710,7 @@ restconf_http1_process(restconf_conn *rc,
goto done;
}
cprintf(cberr, "<errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\"><error><error-type>protocol</error-type><error-tag>malformed-message</error-tag><error-message>%s</error-message></error></errors>", clicon_err_reason);
if (native_send_badrequest(h, rc->rc_s, rc->rc_ssl, "application/yang-data+xml", cbuf_get(cberr), rc->rc_socket) < 0)
if ((ret = native_send_badrequest(h, "application/yang-data+xml", cbuf_get(cberr), rc)) < 0)
goto done;
goto ok;
}
@ -690,11 +720,17 @@ restconf_http1_process(restconf_conn *rc,
if ((ret = http1_check_expect(h, rc, sd)) < 0)
goto done;
if (ret == 1){
if (native_buf_write(h, cbuf_get(sd->sd_outp_buf), cbuf_len(sd->sd_outp_buf),
rc->rc_s, rc->rc_ssl, rc->rc_socket) < 0)
if ((ret = native_buf_write(h, cbuf_get(sd->sd_outp_buf), cbuf_len(sd->sd_outp_buf), rc)) < 0)
goto done;
cvec_reset(sd->sd_outp_hdrs);
cbuf_reset(sd->sd_outp_buf);
if (ret == 0){
if (restconf_close_ssl_socket(rc, __FUNCTION__, 0) < 0)
goto done;
rc = NULL;
retval = 0;
goto done;
}
}
}
/* Check whole message is read.
@ -718,19 +754,15 @@ restconf_http1_process(restconf_conn *rc,
/* main restconf processing */
if (restconf_http1_path_root(h, rc) < 0)
goto done;
if (native_buf_write(h, cbuf_get(sd->sd_outp_buf), cbuf_len(sd->sd_outp_buf),
rc->rc_s, rc->rc_ssl, rc->rc_socket) < 0)
if ((ret = native_buf_write(h, cbuf_get(sd->sd_outp_buf), cbuf_len(sd->sd_outp_buf), rc)) < 0)
goto done;
cvec_reset(sd->sd_outp_hdrs); /* Can be done in native_send_reply */
cbuf_reset(sd->sd_outp_buf);
cbuf_reset(sd->sd_inbuf);
cbuf_reset(sd->sd_indata);
if (rc->rc_exit){ /* Server-initiated exit */
SSL_free(rc->rc_ssl);
rc->rc_ssl = NULL;
if (restconf_connection_close(h, rc->rc_s, rc->rc_socket) < 0)
if (ret == 0 || rc->rc_exit){ /* Server-initiated exit */
if (restconf_close_ssl_socket(rc, __FUNCTION__, 0) < 0)
goto done;
restconf_conn_free(rc);
retval = 0;
goto done;
}
@ -761,7 +793,7 @@ restconf_http2_upgrade(restconf_conn *rc)
/* Switch to http/2 according to RFC 7540 Sec 3.2 and RFC 7230 Sec 6.7 */
rc->rc_proto = HTTP_2;
if (http2_session_init(rc) < 0){
restconf_close_ssl_socket(rc, 1);
restconf_close_ssl_socket(rc, __FUNCTION__, 0);
goto done;
}
/* The HTTP/1.1 request that is sent prior to upgrade is assigned a
@ -780,7 +812,7 @@ restconf_http2_upgrade(restconf_conn *rc)
goto done;
}
if (http2_send_server_connection(rc) < 0){
restconf_close_ssl_socket(rc, 1);
restconf_close_ssl_socket(rc, __FUNCTION__, 0);
goto done;
}
/* Use params from original http/1 session to http/2 stream */
@ -836,8 +868,7 @@ restconf_http2_process(restconf_conn *rc,
if ((ret = http2_recv(rc, (unsigned char *)buf, n)) < 0)
goto done;
if (ret == 0){
restconf_close_ssl_socket(rc, 0);
if (restconf_conn_free(rc) < 0)
if (restconf_close_ssl_socket(rc, __FUNCTION__, 0) < 0)
goto done;
retval = 0;
goto done;
@ -860,7 +891,7 @@ restconf_http2_process(restconf_conn *rc,
/*! Get restconf native handle
* @param[in] h Clicon handle
* @retval rh Restconf native handle
* @retval rn Restconf native handle
*/
restconf_native_handle *
restconf_native_handle_get(clicon_handle h)
@ -925,9 +956,8 @@ restconf_connection(int s,
continue;
if (n == 0){
clicon_debug(1, "%s n=0 closing socket", __FUNCTION__);
if (restconf_close_ssl_socket(rc, 0) < 0)
if (restconf_close_ssl_socket(rc, __FUNCTION__, 0) < 0)
goto done;
restconf_conn_free(rc);
rc = NULL;
goto ok;
}
@ -966,27 +996,33 @@ restconf_connection(int s,
return retval;
} /* restconf_connection */
/*----------------------------- Close socket ------------------------------*/
/*! Close Restconf native connection socket and unregister callback
* For callhome also start reconnect timer
* @param[in] rc rstconf connection
*/
int
restconf_connection_close(clicon_handle h,
int s,
restconf_socket *rsock)
static int
restconf_connection_close1(restconf_conn *rc)
{
int retval = -1;
int retval = -1;
restconf_socket *rsock;
clicon_debug(1, "%s %s", __FUNCTION__, rsock->rs_description);
if (close(s) < 0){
if (rc == NULL){
clicon_err(OE_RESTCONF, EINVAL, "rc is NULL");
goto done;
}
rsock = rc->rc_socket;
clicon_debug(1, "%s \"%s\"", __FUNCTION__, rsock->rs_description);
if (close(rc->rc_s) < 0){
clicon_err(OE_UNIX, errno, "close");
goto done;
}
clixon_event_unreg_fd(s, restconf_connection);
clixon_event_unreg_fd(rc->rc_s, restconf_connection);
/* re-set timer */
if (rsock->rs_callhome){
if (rsock->rs_periodic &&
restconf_idle_timer_unreg(rsock) < 0)
goto done;
if (rc->rc_callhome){
if (rsock->rs_periodic)
restconf_idle_timer_unreg(rc);
if (restconf_callhome_timer(rsock, 1) < 0)
goto done;
}
@ -995,7 +1031,62 @@ restconf_connection_close(clicon_handle h,
clicon_debug(1, "%s %d", __FUNCTION__, retval);
return retval;
}
/*! Utility function to close restconf server ssl socket.
* There are many variants to closing, one could probably make this more generic
* and always use this function, but it is difficult.
* @param[in] rc restconf connection
* @param[in] callfn For debug
* @param[in] dontshutdown If != 0, do not shutdown
*/
int
restconf_close_ssl_socket(restconf_conn *rc,
const char *callfn,
int dontshutdown)
{
int retval = -1;
int ret;
int sslerr;
int er;
clicon_debug(1, "%s", __FUNCTION__);
if (rc->rc_ssl != NULL){
if (!dontshutdown &&
(ret = SSL_shutdown(rc->rc_ssl)) < 0){
er = errno;
sslerr = SSL_get_error(rc->rc_ssl, ret);
clicon_debug(1, "%s errno:%d sslerr:%d", __FUNCTION__, er, sslerr);
// case SSL_ERROR_ZERO_RETURN: /* 6 */
// Note that in this case SSL_ERROR_ZERO_RETURN does not necessarily indicate that the underlying transport has been closed.
if (sslerr == SSL_ERROR_SSL){ /* 1 */
}
else if (sslerr == SSL_ERROR_SYSCALL){ /* 5 */
/* Some non-recoverable, fatal I/O error occurred. The OpenSSL error queue
may contain more information on the error. For socket I/O on Unix systems,
consult errno for details. If this error occurs then no further I/O
operations should be performed on the connection and SSL_shutdown() must
not be called.*/
/* Ignore eg EBADF/ECONNRESET/EPIPE */
}
else{
clicon_err(OE_SSL, sslerr, "SSL_shutdown, %s err:%d %d", callfn, sslerr, er);
goto done;
}
}
SSL_free(rc->rc_ssl);
rc->rc_ssl = NULL;
}
if (restconf_connection_close1(rc) < 0)
goto done;
if (restconf_conn_free(rc) < 0)
goto done;
retval = 0;
done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
return retval;
}
/*------------------------------ Accept--------------------------------*/
/*! Check ALPN result
@ -1012,7 +1103,6 @@ ssl_alpn_check(clicon_handle h,
restconf_http_proto *proto)
{
int retval = -1;
int ret;
cbuf *cberr = NULL;
clicon_debug(1, "%s", __FUNCTION__);
@ -1037,34 +1127,17 @@ ssl_alpn_check(clicon_handle h,
if (alpn != NULL){
cprintf(cberr, "<errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\"><error><error-type>protocol</error-type><error-tag>malformed-message</error-tag><error-message>ALPN: protocol not recognized: %s</error-message></error></errors>", alpn);
clicon_log(LOG_INFO, "%s Warning: %s", __FUNCTION__, cbuf_get(cberr));
if (native_send_badrequest(h, rc->rc_s, rc->rc_ssl,
"application/yang-data+xml",
cbuf_get(cberr), rc->rc_socket) < 0)
if (native_send_badrequest(h,
"application/yang-data+xml",
cbuf_get(cberr), rc) < 0)
goto done;
}
else{
/* XXX Sending badrequest here gives a segv in SSL_shutdown() later or a SIGPIPE here */
clicon_log(LOG_INFO, "%s Warning: ALPN: No protocol selected, or no ALPN?", __FUNCTION__);
}
if (rc->rc_ssl){
/* nmap ssl-known-key SEGV at s->method->ssl_shutdown(s);
* OR OpenSSL error: : SSL_shutdown, err: SSL_ERROR_SYSCALL(5)
*/
if ((ret = SSL_shutdown(rc->rc_ssl)) < 0){
int e = SSL_get_error(rc->rc_ssl, ret);
if (e == SSL_ERROR_SYSCALL){
clicon_log(LOG_INFO, "%s Warning: SSL_shutdown SSL_ERROR_SYSCALL", __FUNCTION__);
/* Continue */
}
else {
clicon_err(OE_SSL, 0, "SSL_shutdown, err:%d", e);
goto done;
}
}
SSL_free(rc->rc_ssl);
}
restconf_conn_free(rc);
if (restconf_close_ssl_socket(rc, __FUNCTION__, 0) < 0)
goto done;
}
retval = 0; /* ALPN not OK */
done:
@ -1078,15 +1151,18 @@ ssl_alpn_check(clicon_handle h,
* @param[in] h Clixon handle
* @param[in] s Socket (unix or ip)
* @param[in] rsock Socket struct
* @param[out] rcp Restconf connection
* @see openssl_init_socket where this callback is registered
*/
int
restconf_ssl_accept_client(clicon_handle h,
int s,
restconf_socket *rsock)
restconf_socket *rsock,
restconf_conn **rcp
)
{
int retval = -1;
restconf_native_handle *rh = NULL;
restconf_native_handle *rn = NULL;
restconf_conn *rc = NULL;
char *name = NULL;
int ret;
@ -1103,7 +1179,7 @@ restconf_ssl_accept_client(clicon_handle h,
proto = HTTP_2; /* If nghttp2 only let default be 2.0 */
#endif
#endif
if ((rh = restconf_native_handle_get(h)) == NULL){
if ((rn = restconf_native_handle_get(h)) == NULL){
clicon_err(OE_XML, EFAULT, "No openssl handle");
goto done;
}
@ -1114,7 +1190,7 @@ restconf_ssl_accept_client(clicon_handle h,
goto done;
clicon_debug(1, "%s s:%d", __FUNCTION__, rc->rc_s);
if (rsock->rs_ssl){
if ((rc->rc_ssl = SSL_new(rh->rh_ctx)) == NULL){
if ((rc->rc_ssl = SSL_new(rn->rn_ctx)) == NULL){
clicon_err(OE_SSL, 0, "SSL_new");
goto done;
}
@ -1160,11 +1236,15 @@ restconf_ssl_accept_client(clicon_handle h,
switch (e){
case SSL_ERROR_SSL: /* 1 */
clicon_debug(1, "%s SSL_ERROR_SSL (non-ssl message on ssl socket)", __FUNCTION__);
#ifdef HTTP_ON_HTTPS_REPLY
SSL_free(rc->rc_ssl);
rc->rc_ssl = NULL;
if (restconf_connection_close(h, rc->rc_s, rc->rc_socket) < 0)
if (native_send_badrequest(h, "application/yang-data+xml",
"<errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\"><error><error-type>protocol</error-type><error-tag>malformed-message</error-tag><error-message>The plain HTTP request was sent to HTTPS port</error-message></error></errors>", rc) < 0)
goto done;
#endif
if (restconf_close_ssl_socket(rc, __FUNCTION__, 1) < 0)
goto done;
restconf_conn_free(rc);
goto ok;
break;
case SSL_ERROR_SYSCALL: /* 5 */
@ -1174,9 +1254,8 @@ restconf_ssl_accept_client(clicon_handle h,
operations should be performed on the connection and SSL_shutdown() must
not be called.*/
clicon_debug(1, "%s SSL_accept() SSL_ERROR_SYSCALL %d", __FUNCTION__, er);
if (restconf_close_ssl_socket(rc, 0) < 0)
if (restconf_close_ssl_socket(rc, __FUNCTION__, 1) < 0)
goto done;
restconf_conn_free(rc);
rc = NULL;
goto ok;
break;
@ -1237,18 +1316,10 @@ restconf_ssl_accept_client(clicon_handle h,
else { /* Get certificates (if available) */
if (proto != HTTP_2 &&
native_send_badrequest(h, rc->rc_s, rc->rc_ssl, "application/yang-data+xml",
"<errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\"><error><error-type>protocol</error-type><error-tag>malformed-message</error-tag><error-message>Peer certificate required</error-message></error></errors>", rc->rc_socket) < 0)
"<errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\"><error><error-type>protocol</error-type><error-tag>malformed-message</error-tag><error-message>Peer certificate required</error-message></error></errors>", rc->rc_socket, rc) < 0)
goto done;
if (restconf_close_ssl_socket(rc, __FUNCTION__, 0) < 0)
goto done;
restconf_conn_free(rc);
if (rc->rc_ssl){
if ((ret = SSL_shutdown(rc->rc_ssl)) < 0){
int e = SSL_get_error(rc->rc_ssl, ret);
clicon_err(OE_SSL, 0, "SSL_shutdown, err:%d", e);
goto done;
}
SSL_free(rc->rc_ssl);
rc->rc_ssl = NULL;
}
goto ok;
}
}
@ -1291,25 +1362,11 @@ restconf_ssl_accept_client(clicon_handle h,
#ifdef HAVE_LIBNGHTTP2
case HTTP_2:{
if (http2_session_init(rc) < 0){
restconf_close_ssl_socket(rc, 1);
restconf_close_ssl_socket(rc, __FUNCTION__, 0);
goto done;
}
if (http2_send_server_connection(rc) < 0){
restconf_close_ssl_socket(rc, 1);
#ifdef NYI
if (ssl) {
SSL_shutdown(ssl);
}
bufferevent_free(session_data->bev);
nghttp2_session_del(session_data->session);
for (stream_data = session_data->root.next; stream_data;) {
http2_stream_data *next = stream_data->next;
delete_http2_stream_data(stream_data);
stream_data = next;
}
free(session_data->client_addr);
free(session_data);
#endif
restconf_close_ssl_socket(rc, __FUNCTION__, 0);
goto done;
}
break;
@ -1320,6 +1377,8 @@ restconf_ssl_accept_client(clicon_handle h,
} /* switch proto */
if (clixon_event_reg_fd(rc->rc_s, restconf_connection, (void*)rc, "restconf client socket") < 0)
goto done;
if (rcp)
*rcp = rc;
ok:
retval = 0;
done:
@ -1330,6 +1389,7 @@ restconf_ssl_accept_client(clicon_handle h,
} /* restconf_ssl_accept_client */
/*! idle timeout timer callback
* @param[in] rc restconf connection, more specifically: callhome connection
*/
static int
restconf_idle_cb(int fd,
@ -1337,15 +1397,20 @@ restconf_idle_cb(int fd,
{
int retval = -1;
restconf_socket *rsock;
restconf_conn *rc;
if ((rsock = (restconf_socket *)arg) == NULL){
if ((rc = (restconf_conn *)arg) == NULL){
clicon_err(OE_YANG, EINVAL, "rc is NULL");
goto done;
}
if ((rsock = rc->rc_socket) == NULL){
clicon_err(OE_YANG, EINVAL, "rsock is NULL");
goto done;
}
clicon_debug(1, "%s %s", __FUNCTION__, rsock->rs_description);
clicon_debug(1, "%s \"%s\"", __FUNCTION__, rsock->rs_description);
/* sanity */
if (rsock->rs_callhome && rsock->rs_periodic && rsock->rs_idle_timeout && rsock->rs_ss > 0){
if (restconf_connection_close(rsock->rs_h, rsock->rs_ss, rsock) < 0)
if (rc->rc_callhome && rsock->rs_periodic && rsock->rs_idle_timeout && rc->rc_s > 0){
if (restconf_close_ssl_socket(rc, __FUNCTION__, 0) < 0)
goto done;
}
retval = 0;
@ -1354,9 +1419,9 @@ restconf_idle_cb(int fd,
}
int
restconf_idle_timer_unreg(restconf_socket *rsock)
restconf_idle_timer_unreg(restconf_conn *rc)
{
return clixon_event_unreg_timeout(restconf_idle_cb, rsock);
return clixon_event_unreg_timeout(restconf_idle_cb, rc);
}
/*! Set callhome periodic idle-timeout
@ -1370,19 +1435,25 @@ restconf_idle_timer_unreg(restconf_socket *rsock)
* @see restconf_idle_timer_unreg
*/
int
restconf_idle_timer(restconf_socket *rsock)
restconf_idle_timer(restconf_conn *rc)
{
int retval = -1;
struct timeval now;
struct timeval t;
struct timeval t1 = {0, 0};
cbuf *cb = NULL;
restconf_socket *rsock;
if (rsock == NULL || !rsock->rs_callhome || !rsock->rs_periodic || rsock->rs_idle_timeout==0){
clicon_err(OE_YANG, EINVAL, "rsock is NULL or not periodic callhome");
if (rc == NULL || !rc->rc_callhome){
clicon_err(OE_YANG, EINVAL, "rc is NULL or not callhome");
goto done;
}
clicon_debug(1, "%s %s register", __FUNCTION__, rsock->rs_description);
rsock = rc->rc_socket;
if (rsock == NULL || !rsock->rs_periodic || rsock->rs_idle_timeout==0){
clicon_err(OE_YANG, EINVAL, "rsock is NULL or not periodic");
goto done;
}
clicon_debug(1, "%s \"%s\" register", __FUNCTION__, rsock->rs_description);
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
@ -1394,7 +1465,7 @@ restconf_idle_timer(restconf_socket *rsock)
clicon_debug(1, "%s now:%lu timeout:%lu.%lu", __FUNCTION__, now.tv_sec, t.tv_sec, t.tv_usec);
if (clixon_event_reg_timeout(t,
restconf_idle_cb,
rsock,
rc,
cbuf_get(cb)) < 0)
goto done;
retval = 0;
@ -1423,13 +1494,14 @@ restconf_callhome_cb(int fd,
struct sockaddr *sa = (struct sockaddr *)&sin6;
size_t sa_len;
int s;
restconf_conn *rc = NULL;
rsock = (restconf_socket *)arg;
if (rsock == NULL || !rsock->rs_callhome){
clicon_err(OE_YANG, EINVAL, "rsock is NULL");
goto done;
}
clicon_debug(1, "%s %s", __FUNCTION__, rsock->rs_description);
clicon_debug(1, "%s \"%s\"", __FUNCTION__, rsock->rs_description);
h = rsock->rs_h;
/* Already computed in restconf_socket_init, could be saved in rsock? */
if (clixon_inet2sin(rsock->rs_addrtype, rsock->rs_addrstr, rsock->rs_port, sa, &sa_len) < 0)
@ -1438,26 +1510,23 @@ restconf_callhome_cb(int fd,
clicon_err(OE_UNIX, errno, "socket");
goto done;
}
clicon_debug(1, "%s connect %hu", __FUNCTION__, rsock->rs_port);
if (connect(s, sa, sa_len) < 0){
clicon_debug(1, "%s connect:%d %s", __FUNCTION__, errno, strerror(errno));
clicon_debug(1, "%s connect %hu fail:%d %s", __FUNCTION__, rsock->rs_port, errno, strerror(errno));
close(s);
rsock->rs_attempts++;
rsock->rs_ss = -1;
/* Fail: Initiate new timer */
if (restconf_callhome_timer(rsock, 0) < 0)
goto done;
}
else {
rsock->rs_ss = s;
clicon_debug(1, "%s connect %hu OK", __FUNCTION__, rsock->rs_port);
rsock->rs_attempts = 0;
if (restconf_ssl_accept_client(h, s, rsock) < 0)
if (restconf_ssl_accept_client(h, s, rsock, &rc) < 0)
goto done;
if (rsock->rs_periodic && rsock->rs_idle_timeout &&
restconf_idle_timer(rsock) < 0)
restconf_idle_timer(rc) < 0)
goto done;
}
clicon_debug(1, "%s connect done", __FUNCTION__);
retval = 0;
done:
return retval;
@ -1491,7 +1560,7 @@ restconf_callhome_timer(restconf_socket *rsock,
clicon_err(OE_YANG, EINVAL, "rsock is NULL or not callhome");
goto done;
}
clicon_debug(1, "%s %s", __FUNCTION__, rsock->rs_description);
clicon_debug(1, "%s \"%s\"", __FUNCTION__, rsock->rs_description);
if (!rsock->rs_callhome)
goto ok; /* shouldnt happen */
gettimeofday(&now, NULL);
@ -1519,7 +1588,7 @@ restconf_callhome_timer(restconf_socket *rsock,
}
cprintf(cb, "restconf callhome timer %s", rsock->rs_description);
if (rsock->rs_description)
clicon_debug(1, "%s registering %s: %lu", __FUNCTION__, rsock->rs_description, t.tv_sec);
clicon_debug(1, "%s registering \"%s\": %lu", __FUNCTION__, rsock->rs_description, t.tv_sec);
else
clicon_debug(1, "%s: %lu", __FUNCTION__, t.tv_sec);
/* Should be only place restconf_callhome_cb is registered */