- Restconf native: Fixed ssl/non-ssl read/write behaviour for data that is different in freebsd than in linux

- test: removed sed -i in tests since it is not portable between linux and bsd
This commit is contained in:
Olof Hagsand 2021-06-25 10:46:53 +00:00
parent 940f4d4fb9
commit b31107f646
4 changed files with 64 additions and 15 deletions

View file

@ -679,6 +679,8 @@ restconf_connection(int s,
ssize_t n; ssize_t n;
char buf[BUFSIZ]; /* from stdio.h, typically 8K XXX: reduce for test */ char buf[BUFSIZ]; /* from stdio.h, typically 8K XXX: reduce for test */
int readmore = 1; int readmore = 1;
int sslerr;
#ifdef HAVE_LIBEVHTP #ifdef HAVE_LIBEVHTP
clicon_handle h; clicon_handle h;
evhtp_connection_t *evconn = NULL; evhtp_connection_t *evconn = NULL;
@ -700,21 +702,47 @@ restconf_connection(int s,
curl -Ssik --key /var/tmp/./test_restconf_ssl_certs.sh/certs/limited.key --cert /var/tmp/./test_restconf_ssl_certs.sh/certs/limited.crt -X GET https://localhost/restconf/data/example:x curl -Ssik --key /var/tmp/./test_restconf_ssl_certs.sh/certs/limited.key --cert /var/tmp/./test_restconf_ssl_certs.sh/certs/limited.crt -X GET https://localhost/restconf/data/example:x
*/ */
if ((n = SSL_read(rc->rc_ssl, buf, sizeof(buf))) < 0){ if ((n = SSL_read(rc->rc_ssl, buf, sizeof(buf))) < 0){
clicon_err(OE_XML, errno, "SSL_read"); sslerr = SSL_get_error(rc->rc_ssl, n);
goto done; clicon_debug(1, "%s SSL_read() n:%ld errno:%d sslerr:%d", __FUNCTION__, n, errno, sslerr);
switch (sslerr){
case SSL_ERROR_WANT_READ: /* 2 */
/* SSL_ERROR_WANT_READ is returned when the last operation was a read operation
* from a nonblocking BIO.
* That is, it can happen if restconf_socket_init() below is called
* with SOCK_NONBLOCK
*/
clicon_debug(1, "%s SSL_read SSL_ERROR_WANT_READ", __FUNCTION__);
usleep(1000);
readmore = 1;
break;
default:
clicon_err(OE_XML, errno, "SSL_read");
goto done;
} /* switch */
continue; /* readmore */
} }
} }
else{ else{
if ((n = read(rc->rc_s, buf, sizeof(buf))) < 0){ /* XXX atomicio ? */ if ((n = read(rc->rc_s, buf, sizeof(buf))) < 0){ /* XXX atomicio ? */
if (errno == ECONNRESET) {/* Connection reset by peer */ switch(errno){
case ECONNRESET:/* Connection reset by peer */
clicon_debug(1, "%s %d Connection reset by peer", __FUNCTION__, rc->rc_s); clicon_debug(1, "%s %d Connection reset by peer", __FUNCTION__, rc->rc_s);
clixon_event_unreg_fd(rc->rc_s, restconf_connection); clixon_event_unreg_fd(rc->rc_s, restconf_connection);
close(rc->rc_s); close(rc->rc_s);
restconf_conn_free(rc); restconf_conn_free(rc);
goto ok; /* Close socket and ssl */ goto ok; /* Close socket and ssl */
break;
case EAGAIN:
clicon_debug(1, "%s read EAGAIN", __FUNCTION__);
usleep(1000);
readmore = 1;
break;
default:;
clicon_err(OE_XML, errno, "read");
goto done;
break;
} }
clicon_err(OE_XML, errno, "read"); continue;
goto done;
} }
} }
clicon_debug(1, "%s read:%ld", __FUNCTION__, n); clicon_debug(1, "%s read:%ld", __FUNCTION__, n);

View file

@ -182,6 +182,7 @@ session_send_callback(nghttp2_session *session,
ssize_t totlen = 0; ssize_t totlen = 0;
int s; int s;
SSL *ssl; SSL *ssl;
int sslerr;
clicon_debug(1, "%s buflen:%lu", __FUNCTION__, buflen); clicon_debug(1, "%s buflen:%lu", __FUNCTION__, buflen);
s = rc->rc_s; s = rc->rc_s;
@ -190,7 +191,14 @@ session_send_callback(nghttp2_session *session,
if (ssl){ if (ssl){
if ((len = SSL_write(ssl, buf+totlen, buflen-totlen)) <= 0){ if ((len = SSL_write(ssl, buf+totlen, buflen-totlen)) <= 0){
er = errno; er = errno;
switch (SSL_get_error(ssl, len)){ sslerr = SSL_get_error(ssl, len);
clicon_debug(1, "%s errno:;%d sslerr:%d", __FUNCTION__, errno, sslerr);
switch (sslerr){
case SSL_ERROR_WANT_WRITE: /* 3 */
clicon_debug(1, "%s write SSL_ERROR_WANT_WRITE", __FUNCTION__);
usleep(1000);
continue;
break;
case SSL_ERROR_SYSCALL: /* 5 */ case SSL_ERROR_SYSCALL: /* 5 */
if (er == ECONNRESET) {/* Connection reset by peer */ if (er == ECONNRESET) {/* Connection reset by peer */
if (ssl) if (ssl)
@ -200,8 +208,12 @@ session_send_callback(nghttp2_session *session,
goto ok; /* Close socket and ssl */ goto ok; /* Close socket and ssl */
} }
else if (er == EAGAIN){ else if (er == EAGAIN){
/* same as want_write above, but different behaviour on different
* platforms, linux here, freebsd want_write, or possibly differnt
* ssl lib versions?
*/
clicon_debug(1, "%s write EAGAIN", __FUNCTION__); clicon_debug(1, "%s write EAGAIN", __FUNCTION__);
usleep(10000); usleep(1000);
continue; continue;
} }
else{ else{

View file

@ -105,6 +105,9 @@ expectpart "$($clixon_cli -1 -f $cfg -l o debug restconf 1)" 0 "^$"
new "get and put config using restconf" new "get and put config using restconf"
expectpart "$(curl $CURLOPTS -H "Accept: application/yang-data+xml" -X GET $RCPROTO://localhost/restconf/data?content=config --next $CURLOPTS -H "Content-Type: application/yang-data+json" -X POST $RCPROTO://localhost/restconf/data -d '{"example:table":{"parameter":{"name":"local0","value":"foo"}}}')" 0 "HTTP/$HVER 200" '<data>' "HTTP/$HVER 201" expectpart "$(curl $CURLOPTS -H "Accept: application/yang-data+xml" -X GET $RCPROTO://localhost/restconf/data?content=config --next $CURLOPTS -H "Content-Type: application/yang-data+json" -X POST $RCPROTO://localhost/restconf/data -d '{"example:table":{"parameter":{"name":"local0","value":"foo"}}}')" 0 "HTTP/$HVER 200" '<data>' "HTTP/$HVER 201"
# In freebsd, backend dies in stop_restconf below unless sleep
sleep $DEMSLEEP
if [ $RC -ne 0 ]; then if [ $RC -ne 0 ]; then
new "Kill restconf daemon" new "Kill restconf daemon"
stop_restconf stop_restconf
@ -115,7 +118,7 @@ if [ $BE -ne 0 ]; then
# Check if premature kill # Check if premature kill
pid=$(pgrep -u root -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err1 "backend pid !=0" 0
fi fi
# kill backend # kill backend
stop_backend -f $cfg stop_backend -f $cfg

View file

@ -32,6 +32,7 @@ ftest=$dir/test.xml
fconfig=$dir/large.xml fconfig=$dir/large.xml
fconfig2=$dir/large2.xml # leaf-list fconfig2=$dir/large2.xml # leaf-list
foutput=$dir/output.xml foutput=$dir/output.xml
foutput2=$dir/output2.xml
cat <<EOF > $fyang cat <<EOF > $fyang
module scaling{ module scaling{
@ -132,15 +133,20 @@ expecteof "time -p $clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><co
new "Check running-db contents" new "Check running-db contents"
curl $CURLOPTS -X GET -H "Accept: application/yang-data+xml" $RCPROTO://localhost/restconf/data?content=config > $foutput curl $CURLOPTS -X GET -H "Accept: application/yang-data+xml" $RCPROTO://localhost/restconf/data?content=config > $foutput
r=$?
if [ $r -ne 0 ]; then
err1 "retval 0" $r
fi
# Remove Content-Length line (depends on size) # Remove Content-Length line (depends on size)
sed -i '/Content-Length:/d' $foutput # Note: do not use sed -i since it is not portable between gnu and bsd
sed -i '/content-length:/d' $foutput sed '/Content-Length:/d' $foutput > $foutput2 && mv $foutput2 $foutput
sed '/content-length:/d' $foutput > $foutput2 && mv $foutput2 $foutput
# Remove (nginx) web-server specific lines # Remove (nginx) web-server specific lines
sed -i '/Server:/d' $foutput sed '/Server:/d' $foutput > $foutput2 && mv $foutput2 $foutput
sed -i '/Date:/d' $foutput sed '/Date:/d' $foutput > $foutput2 && mv $foutput2 $foutput
sed -i '/Transfer-Encoding:/d' $foutput sed '/Transfer-Encoding:/d' $foutput > $foutput2 && mv $foutput2 $foutput
sed -i '/Connection:/d' $foutput sed '/Connection:/d' $foutput > $foutput2 && mv $foutput2 $foutput
# Create a file to compare with # Create a file to compare with
if ${HAVE_LIBNGHTTP2}; then if ${HAVE_LIBNGHTTP2}; then
@ -165,7 +171,7 @@ echo "</data> " >> $ftest
ret=$(diff -i $ftest $foutput) ret=$(diff -i $ftest $foutput)
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo "$ret" echo "diff -i $ftest $foutput"
err1 "Matching running-db with $fconfigonly" err1 "Matching running-db with $fconfigonly"
fi fi