session CHANGE new timeout introduced

Also described with other options in README.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index de1b049..e9d4293 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -36,7 +36,9 @@
 option(ENABLE_SSH "Enable NETCONF over SSH support (via libssh)" ON)
 option(ENABLE_TLS "Enable NETCONF over TLS support (via OpenSSL)" ON)
 option(ENABLE_DNSSEC "Enable support for SSHFP retrieval using DNSSEC for SSH (requires OpenSSL and libval)" OFF)
-set(READ_TIMEOUT 30 CACHE STRING "Maximum number of seconds waiting for some expected data")
+set(READ_INACTIVE_TIMEOUT 20 CACHE STRING "Maximum number of seconds waiting for new data once some data have arrived")
+set(READ_ACTIVE_TIMEOUT 300 CACHE STRING "Maximum number of seconds for receiving a full message")
+set(MAX_PSPOLL_THREAD_COUNT 6 CACHE STRING "Maximum number of threads that could simultaneously access a ps_poll structure")
 
 if(ENABLE_DNSSEC AND NOT ENABLE_SSH)
     message(WARNING "DNSSEC SSHFP retrieval cannot be used without SSH support.")
diff --git a/README.md b/README.md
index a0d48e1..f7fd08f 100644
--- a/README.md
+++ b/README.md
@@ -54,7 +54,7 @@
 datastore implementation are not available in **libnetconf2**. In the case of
 the Netopeer2 server, all these features (and much more) are implemented as
 part of the server itself or its datastore implementation -
-[**sysrepo**](https://github.com/sysrepo/sysrepo). 
+[**sysrepo**](https://github.com/sysrepo/sysrepo).
 
 ### Notifications
 
@@ -221,6 +221,37 @@
 ```
 $ cmake -D CMAKE_BUILD_TYPE:String="Release" ..
 ```
+
+### Inactive Read Timeout
+
+It is possible to adjust inactive read timeout. It is used when a new message is
+being read and no new data had arrived for this amount of seconds. 20 is the default value.
+
+```
+$ cmake -D READ_INACTIVE_TIMEOUT:String="20" ..
+```
+
+### Active Read Timeout
+
+Active read timeout is used to limit the maximum number of seconds a message is given
+to arrive in its entirety once a beginning is read. The default is 300 (5 minutes).
+
+```
+$ cmake -D READ_ACTIVE_TIMEOUT:String="300" ..
+```
+
+### PSPoll Thread Count
+
+This value limits the maximum number of threads that can concurrently access
+(wait for access) a single pspoll structure. To simplify, how many threads could
+simultaneously call a function whose parameter is one and the same pspoll structure.
+If using **netopeer2-server**, it will warn that this value needs to be adjusted if
+too small.
+
+```
+$ cmake -D MAX_PSPOLL_THREAD_COUNT:String="6" ..
+```
+
 ### CMake Notes
 
 Note that, with CMake, if you want to change the compiler or its options after
diff --git a/nc_server.h.in b/nc_server.h.in
index a2b6add..f01fc93 100644
--- a/nc_server.h.in
+++ b/nc_server.h.in
@@ -3,12 +3,12 @@
  * \author Radek Krejci <rkrejci@cesnet.cz>
  * \brief libnetconf2's main public header for NETCONF servers.
  *
- * Copyright (c) 2015 CESNET, z.s.p.o.
+ * Copyright (c) 2015 - 2017 CESNET, z.s.p.o.
  *
  * This source code is licensed under BSD 3-Clause License (the "License").
  * You may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
- * 
+ *
  *     https://opensource.org/licenses/BSD-3-Clause
  */
 
@@ -18,6 +18,8 @@
 @SSH_MACRO@
 @TLS_MACRO@
 
+#define NC_PS_QUEUE_SIZE @MAX_PSPOLL_THREAD_COUNT@
+
 #include <libnetconf2/netconf.h>
 #include <libnetconf2/log.h>
 #include <libnetconf2/messages_server.h>
diff --git a/src/config.h.in b/src/config.h.in
index 0179821..4af2bb9 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -3,7 +3,7 @@
  * \author Radek Krejci <rkrejci@cesnet.cz>
  * \brief libnetconf2 various configuration settings.
  *
- * Copyright (c) 2015 CESNET, z.s.p.o.
+ * Copyright (c) 2015 - 2017 CESNET, z.s.p.o.
  *
  * This source code is licensed under BSD 3-Clause License (the "License").
  * You may not use this file except in compliance with the License.
@@ -50,9 +50,14 @@
 #define SCHEMAS_DIR "@CMAKE_INSTALL_PREFIX@/@DATA_INSTALL_DIR@"
 
 /*
- * Partial message read timeout in seconds
- * (also used as nc_pollsession lock timeout and internal <get-schema> RPC reply timeout)
+ * Inactive read timeout
  */
-#define NC_READ_TIMEOUT @READ_TIMEOUT@
+#define NC_READ_INACT_TIMEOUT @READ_INACTIVE_TIMEOUT@
+
+/*
+ * Active read timeout in seconds
+ * (also used for internal <get-schema> RPC reply timeout)
+ */
+#define NC_READ_ACT_TIMEOUT @READ_ACTIVE_TIMEOUT@
 
 #endif /* NC_CONFIG_H_ */
diff --git a/src/io.c b/src/io.c
index 33c1e08..6e31e87 100644
--- a/src/io.c
+++ b/src/io.c
@@ -35,11 +35,12 @@
 #define BUFFERSIZE 512
 
 static ssize_t
-nc_read(struct nc_session *session, char *buf, size_t count, uint16_t *read_timeout)
+nc_read(struct nc_session *session, char *buf, size_t count, uint32_t inact_timeout, uint32_t *act_timeout)
 {
     size_t readd = 0;
     ssize_t r = -1;
     uint16_t sleep_count = 0;
+    uint32_t cur_inact_timeout = inact_timeout;
 
     assert(session);
     assert(buf);
@@ -134,24 +135,32 @@
 #endif
         }
 
-        /* nothing read */
         if (r == 0) {
+            /* nothing read */
             usleep(NC_TIMEOUT_STEP);
             ++sleep_count;
-            if (1000000 / NC_TIMEOUT_STEP == sleep_count) {
-                /* we slept a full second */
-                --(*read_timeout);
+            if (1000 / NC_TIMEOUT_STEP == sleep_count) {
+                /* we slept a full millisecond */
+                --cur_inact_timeout;
+                --(*act_timeout);
                 sleep_count = 0;
             }
-            if (!*read_timeout) {
-                ERR("Session %u: reading a full NETCONF message timeout elapsed.", session->id);
+            if (!cur_inact_timeout || !*act_timeout) {
+                if (!inact_timeout) {
+                    ERR("Session %u: inactive read timeout elapsed.", session->id);
+                } else {
+                    ERR("Session %u: active read timeout elapsed.", session->id);
+                }
                 session->status = NC_STATUS_INVALID;
                 session->term_reason = NC_SESSION_TERM_OTHER;
                 return -1;
             }
+        } else {
+            /* something read */
+            readd += r;
+            cur_inact_timeout = inact_timeout;
         }
 
-        readd += r;
     } while (readd < count);
     buf[count] = '\0';
 
@@ -159,7 +168,7 @@
 }
 
 static ssize_t
-nc_read_chunk(struct nc_session *session, size_t len, uint16_t *read_timeout, char **chunk)
+nc_read_chunk(struct nc_session *session, size_t len, uint32_t inact_timeout, uint32_t *act_timeout, char **chunk)
 {
     ssize_t r;
 
@@ -176,7 +185,7 @@
         return -1;
     }
 
-    r = nc_read(session, *chunk, len, read_timeout);
+    r = nc_read(session, *chunk, len, inact_timeout, act_timeout);
     if (r <= 0) {
         free(*chunk);
         return -1;
@@ -189,7 +198,8 @@
 }
 
 static ssize_t
-nc_read_until(struct nc_session *session, const char *endtag, size_t limit, uint16_t *read_timeout, char **result)
+nc_read_until(struct nc_session *session, const char *endtag, size_t limit, uint32_t inact_timeout, uint32_t *act_timeout,
+              char **result)
 {
     char *chunk = NULL;
     size_t size, count = 0, r, len;
@@ -229,7 +239,7 @@
         }
 
         /* get another character */
-        r = nc_read(session, &(chunk[count]), 1, read_timeout);
+        r = nc_read(session, &(chunk[count]), 1, inact_timeout, act_timeout);
         if (r != 1) {
             free(chunk);
             return -1;
@@ -264,7 +274,8 @@
     int ret;
     char *msg = NULL, *chunk;
     uint64_t chunk_len, len = 0;
-    uint16_t read_timeout = NC_READ_TIMEOUT;
+    /* use timeouts in milliseconds instead seconds */
+    uint32_t act_timeout = NC_READ_ACT_TIMEOUT * 1000, inact_timeout = NC_READ_INACT_TIMEOUT * 1000;
     struct nc_server_reply *reply;
 
     assert(session && data);
@@ -278,7 +289,7 @@
     /* read the message */
     switch (session->version) {
     case NC_VERSION_10:
-        ret = nc_read_until(session, NC_VERSION_10_ENDTAG, 0, &read_timeout, &msg);
+        ret = nc_read_until(session, NC_VERSION_10_ENDTAG, 0, inact_timeout, &act_timeout, &msg);
         if (ret == -1) {
             goto error;
         }
@@ -288,11 +299,11 @@
         break;
     case NC_VERSION_11:
         while (1) {
-            ret = nc_read_until(session, "\n#", 0, &read_timeout, NULL);
+            ret = nc_read_until(session, "\n#", 0, inact_timeout, &act_timeout, NULL);
             if (ret == -1) {
                 goto error;
             }
-            ret = nc_read_until(session, "\n", 0, &read_timeout, &chunk);
+            ret = nc_read_until(session, "\n", 0, inact_timeout, &act_timeout, &chunk);
             if (ret == -1) {
                 goto error;
             }
@@ -316,7 +327,7 @@
             }
 
             /* now we have size of next chunk, so read the chunk */
-            ret = nc_read_chunk(session, chunk_len, &read_timeout, &chunk);
+            ret = nc_read_chunk(session, chunk_len, inact_timeout, &act_timeout, &chunk);
             if (ret == -1) {
                 goto error;
             }
diff --git a/src/netconf.h b/src/netconf.h
index 1221b08..aea5dbd 100644
--- a/src/netconf.h
+++ b/src/netconf.h
@@ -35,7 +35,7 @@
 #define NC_PORT_CH_TLS 4335
 
 /** @brief Microseconds after which tasks are repeated until the full timeout elapses.
- *         A second (1000 000) should be divisible by this number without remain.
+ *         A millisecond (1000) should be divisible by this number without remain.
  */
 #define NC_TIMEOUT_STEP 20
 
diff --git a/src/session.c b/src/session.c
index afc89f5..b52de4e 100644
--- a/src/session.c
+++ b/src/session.c
@@ -333,7 +333,7 @@
     }
 
     if (session->ti_lock) {
-        r = nc_timedlock(session->ti_lock, NC_READ_TIMEOUT * 1000, __func__);
+        r = nc_timedlock(session->ti_lock, NC_SESSION_FREE_LOCK_TIMEOUT, __func__);
         if (r == -1) {
             return;
         } else if (!r) {
diff --git a/src/session_client.c b/src/session_client.c
index 15fa4a8..5b9902c 100644
--- a/src/session_client.c
+++ b/src/session_client.c
@@ -216,7 +216,7 @@
     }
 
     do {
-        msg = nc_recv_reply(session, rpc, msgid, NC_READ_TIMEOUT * 1000, 0, &reply);
+        msg = nc_recv_reply(session, rpc, msgid, NC_READ_ACT_TIMEOUT * 1000, 0, &reply);
     } while (msg == NC_MSG_NOTIF);
     nc_rpc_free(rpc);
     if (msg == NC_MSG_WOULDBLOCK) {
diff --git a/src/session_p.h b/src/session_p.h
index 37c231b..1396473 100644
--- a/src/session_p.h
+++ b/src/session_p.h
@@ -25,6 +25,7 @@
 #include "netconf.h"
 #include "session.h"
 #include "messages_client.h"
+#include "../nc_server.h"
 
 #ifdef NC_ENABLED_SSH
 
@@ -246,6 +247,16 @@
 #define NC_TRANSPORT_TIMEOUT 2000
 
 /**
+ * Timeout in msec for acquiring a lock of a session that is supposed to be freed.
+ */
+#define NC_SESSION_FREE_LOCK_TIMEOUT 5000
+
+/**
+ * Timeout in msec for acquiring a lock of a pollsession structure.
+ */
+#define NC_PS_LOCK_TIMEOUT 500
+
+/**
  * Number of sockets kept waiting to be accepted.
  */
 #define NC_REVERSE_QUEUE 5
@@ -362,8 +373,6 @@
     } opts;
 };
 
-#define NC_PS_QUEUE_SIZE 6
-
 /* ACCESS locked */
 struct nc_pollsession {
     struct nc_session **sessions;
diff --git a/src/session_server.c b/src/session_server.c
index b142dd9..b96432c 100644
--- a/src/session_server.c
+++ b/src/session_server.c
@@ -666,7 +666,11 @@
     struct timespec ts;
 
     nc_gettimespec(&ts);
-    ts.tv_sec += NC_READ_TIMEOUT;
+    ts.tv_nsec += NC_PS_LOCK_TIMEOUT * 1000000;
+    while (ts.tv_nsec >= 1000000000L) {
+        ts.tv_nsec -= 1000000000L;
+        ++ts.tv_sec;
+    }
 
     /* LOCK */
     ret = pthread_mutex_timedlock(&ps->lock, &ts);
@@ -702,7 +706,11 @@
     /* is it our turn? */
     while (ps->queue[ps->queue_begin] != *id) {
         nc_gettimespec(&ts);
-        ts.tv_sec += NC_READ_TIMEOUT;
+        ts.tv_nsec += NC_PS_LOCK_TIMEOUT * 1000000;
+        while (ts.tv_nsec >= 1000000000L) {
+            ts.tv_nsec -= 1000000000L;
+            ++ts.tv_sec;
+        }
 
         ret = pthread_cond_timedwait(&ps->cond, &ps->lock, &ts);
         if (ret) {
@@ -727,7 +735,11 @@
     struct timespec ts;
 
     nc_gettimespec(&ts);
-    ts.tv_sec += NC_READ_TIMEOUT;
+    ts.tv_nsec += NC_PS_LOCK_TIMEOUT * 1000000;
+    while (ts.tv_nsec >= 1000000000L) {
+        ts.tv_nsec -= 1000000000L;
+        ++ts.tv_sec;
+    }
 
     /* LOCK */
     ret = pthread_mutex_timedlock(&ps->lock, &ts);