Index: uspace/srv/hid/remcons/remcons.c
===================================================================
--- uspace/srv/hid/remcons/remcons.c	(revision 261bbdc1ca1fd5d732e25e8481ec324931db7966)
+++ uspace/srv/hid/remcons/remcons.c	(revision 99c2e9f3c319eeb78d3eeebdeef3d90d3d9f6a7b)
@@ -74,21 +74,4 @@
     sizeof(telnet_force_character_mode_command) / sizeof(telnet_cmd_t);
 
-/** Creates new keyboard event from given char.
- *
- * @param type Event type (press / release).
- * @param c Pressed character.
- */
-static kbd_event_t* new_kbd_event(kbd_event_type_t type, wchar_t c) {
-	kbd_event_t *event = malloc(sizeof(kbd_event_t));
-	assert(event);
-
-	link_initialize(&event->link);
-	event->type = type;
-	event->c = c;
-	event->mods = 0;
-	event->key = (c == '\n' ? KC_ENTER : KC_A);
-
-	return event;
-}
 
 /** Handling client requests (VFS and console interface).
@@ -101,12 +84,16 @@
 		ipc_call_t call;
 		ipc_callid_t callid = 0;
+
+		/*
+		 * The getterm task might terminate while we are here,
+		 * waiting for a call. Also, the socket might be closed
+		 * meanwhile.
+		 * We want to detect this situation early, so we use a
+		 * timeout variant of async_get_call().
+		 */
 		while (callid == 0) {
 			callid = async_get_call_timeout(&call, 1000);
 
-			fibril_mutex_lock(&user->guard);
-			bool bail_out = user->socket_closed || user->task_finished;
-			fibril_mutex_unlock(&user->guard);
-
-			if (bail_out) {
+			if (telnet_user_is_zombie(user)) {
 				if (callid != 0) {
 					async_answer_0(callid, EINTR);
@@ -117,5 +104,4 @@
 		
 		if (!IPC_GET_IMETHOD(call)) {
-			/* Clean-up. */
 			return;
 		}
@@ -129,42 +115,12 @@
 			break;
 		case CONSOLE_GET_EVENT: {
-			if (list_empty(&user->in_events.list)) {
-				retry:
-				if (user->socket_buffer_len <= user->socket_buffer_pos) {
-					int recv_length = recv(user->socket, user->socket_buffer, BUFFER_SIZE, 0);
-					if ((recv_length == 0) || (recv_length == ENOTCONN)) {
-						fibril_mutex_lock(&user->guard);
-						user->socket_closed = true;
-						fibril_mutex_unlock(&user->guard);
-						async_answer_0(callid, ENOENT);
-						return;
-					}
-					if (recv_length < 0) {
-						async_answer_0(callid, EINVAL);
-						return;
-					}
-					user->socket_buffer_len = recv_length;
-					user->socket_buffer_pos = 0;
-				}
-				char data = user->socket_buffer[user->socket_buffer_pos++];
-				if (data == 13) {
-					data = 10;
-				}
-				if (data == 0)
-					goto retry;
-
-				kbd_event_t *down = new_kbd_event(KEY_PRESS, data);
-				kbd_event_t *up = new_kbd_event(KEY_RELEASE, data);
-				assert(down);
-				assert(up);
-				prodcons_produce(&user->in_events, &down->link);
-				prodcons_produce(&user->in_events, &up->link);
-			}
-
-
-			link_t *link = prodcons_consume(&user->in_events);
-			kbd_event_t *event = list_get_instance(link, kbd_event_t, link);
-			async_answer_4(callid, EOK, event->type, event->key, event->mods, event->c);
-			free(event);
+			kbd_event_t event;
+			int rc = telnet_user_get_next_keyboard_event(user, &event);
+			if (rc != EOK) {
+				/* Silently ignore. */
+				async_answer_0(callid, EOK);
+				break;
+			}
+			async_answer_4(callid, EOK, event.type, event.key, event.mods, event.c);
 			break;
 		}
@@ -185,5 +141,5 @@
 				break;
 			}
-			buf_converted = malloc(2 * size);
+			buf_converted = malloc(2 * size + 1);
 			assert(buf_converted);
 			int buf_converted_size = 0;
@@ -197,5 +153,10 @@
 				}
 			}
+			/* Add terminating zero for printing purposes. */
+			buf_converted[buf_converted_size] = 0;
+
+			fibril_mutex_lock(&user->guard);
 			rc = send(user->socket, buf_converted, buf_converted_size, 0);
+			fibril_mutex_unlock(&user->guard);
 			free(buf);
 
@@ -206,5 +167,4 @@
 
 			async_answer_1(callid, EOK, size);
-
 			break;
 		}
@@ -249,9 +209,7 @@
 		return;
 	}
+	async_answer_0(iid, EOK);
 
 	telnet_user_log(user, "New client connected (%" PRIxn").", iid);
-
-	/* Accept the connection, increment reference. */
-	async_answer_0(iid, EOK);
 
 	/* Force character mode. */
@@ -259,7 +217,7 @@
 	    telnet_force_character_mode_command_count, 0);
 
+	/* Handle messages. */
 	client_connection_message_loop(user);
 
-	/* Announce user disconnection. */
 	telnet_user_notify_client_disconnected(user);
 	telnet_user_log(user, "Client disconnected (%" PRIxn").", iid);
Index: uspace/srv/hid/remcons/user.c
===================================================================
--- uspace/srv/hid/remcons/user.c	(revision 261bbdc1ca1fd5d732e25e8481ec324931db7966)
+++ uspace/srv/hid/remcons/user.c	(revision 99c2e9f3c319eeb78d3eeebdeef3d90d3d9f6a7b)
@@ -172,4 +172,99 @@
 }
 
+/** Tell whether the launched task already exited and socket is already closed.
+ *
+ * @param user Telnet user in question.
+ */
+bool telnet_user_is_zombie(telnet_user_t *user)
+{
+	fibril_mutex_lock(&user->guard);
+	bool zombie = user->socket_closed || user->task_finished;
+	fibril_mutex_unlock(&user->guard);
+
+	return zombie;
+}
+
+/** Receive next byte from a socket (use buffering.
+ * We need to return the value via extra argument because the read byte
+ * might be negative.
+ */
+static int telnet_user_recv_next_byte_no_lock(telnet_user_t *user, char *byte)
+{
+	/* No more buffered data? */
+	if (user->socket_buffer_len <= user->socket_buffer_pos) {
+		int recv_length = recv(user->socket, user->socket_buffer, BUFFER_SIZE, 0);
+		if ((recv_length == 0) || (recv_length == ENOTCONN)) {
+			user->socket_closed = true;
+			return ENOENT;
+		}
+		if (recv_length < 0) {
+			return recv_length;
+		}
+		user->socket_buffer_len = recv_length;
+		user->socket_buffer_pos = 0;
+	}
+
+	*byte = user->socket_buffer[user->socket_buffer_pos++];
+
+	return EOK;
+}
+
+/** Creates new keyboard event from given char.
+ *
+ * @param type Event type (press / release).
+ * @param c Pressed character.
+ */
+static kbd_event_t* new_kbd_event(kbd_event_type_t type, wchar_t c) {
+	kbd_event_t *event = malloc(sizeof(kbd_event_t));
+	assert(event);
+
+	link_initialize(&event->link);
+	event->type = type;
+	event->c = c;
+	event->mods = 0;
+	event->key = (c == '\n' ? KC_ENTER : KC_A);
+
+	return event;
+}
+
+int telnet_user_get_next_keyboard_event(telnet_user_t *user, kbd_event_t *event)
+{
+	fibril_mutex_lock(&user->guard);
+	if (list_empty(&user->in_events.list)) {
+		char next_byte = 0;
+		/* Skip zeros, bail-out on error. */
+		while (next_byte == 0) {
+			int rc = telnet_user_recv_next_byte_no_lock(user, &next_byte);
+			DEBUG("Got %d.\n", next_byte);
+			if (rc != EOK) {
+				fibril_mutex_unlock(&user->guard);
+				return rc;
+			}
+		}
+
+		/* CR-LF conversions. */
+		if (next_byte == 13) {
+			next_byte = 10;
+		}
+
+		kbd_event_t *down = new_kbd_event(KEY_PRESS, next_byte);
+		kbd_event_t *up = new_kbd_event(KEY_RELEASE, next_byte);
+		assert(down);
+		assert(up);
+		prodcons_produce(&user->in_events, &down->link);
+		prodcons_produce(&user->in_events, &up->link);
+	}
+
+	link_t *link = prodcons_consume(&user->in_events);
+	kbd_event_t *tmp = list_get_instance(link, kbd_event_t, link);
+
+	fibril_mutex_unlock(&user->guard);
+
+	*event = *tmp;
+
+	free(tmp);
+
+	return EOK;
+}
 
 /**
Index: uspace/srv/hid/remcons/user.h
===================================================================
--- uspace/srv/hid/remcons/user.h	(revision 261bbdc1ca1fd5d732e25e8481ec324931db7966)
+++ uspace/srv/hid/remcons/user.h	(revision 99c2e9f3c319eeb78d3eeebdeef3d90d3d9f6a7b)
@@ -40,5 +40,5 @@
 #include "remcons.h"
 
-#define BUFFER_SIZE 1024
+#define BUFFER_SIZE 32
 
 /** Representation of a connected (human) user. */
@@ -76,5 +76,7 @@
 void telnet_user_destroy(telnet_user_t *user);
 telnet_user_t *telnet_user_get_for_client_connection(service_id_t id);
+bool telnet_user_is_zombie(telnet_user_t *user);
 void telnet_user_notify_client_disconnected(telnet_user_t *user);
+int telnet_user_get_next_keyboard_event(telnet_user_t *user, kbd_event_t *event);
 
 /** Print informational message about connected user. */
