Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/hid/remcons/user.c

    r5f5d375 r28a5ebd  
    11/*
    2  * Copyright (c) 2024 Jiri Svoboda
    32 * Copyright (c) 2012 Vojtech Horky
    43 * All rights reserved.
     
    3837#include <adt/prodcons.h>
    3938#include <errno.h>
    40 #include <macros.h>
    41 #include <mem.h>
    4239#include <str_error.h>
    4340#include <loc.h>
     
    5148#include <inttypes.h>
    5249#include <assert.h>
    53 #include "remcons.h"
    5450#include "user.h"
    5551#include "telnet.h"
     
    5854static LIST_INITIALIZE(users);
    5955
    60 static errno_t telnet_user_send_raw_locked(telnet_user_t *, const void *,
    61     size_t);
    62 static errno_t telnet_user_flush_locked(telnet_user_t *);
    63 
    6456/** Create new telnet user.
    6557 *
    6658 * @param conn Incoming connection.
    67  * @param cb Callback functions
    68  * @param arg Argument to callback functions
    6959 * @return New telnet user or NULL when out of memory.
    7060 */
    71 telnet_user_t *telnet_user_create(tcp_conn_t *conn, telnet_cb_t *cb, void *arg)
     61telnet_user_t *telnet_user_create(tcp_conn_t *conn)
    7262{
    7363        static int telnet_user_id_counter = 0;
     
    7868        }
    7969
    80         user->cb = cb;
    81         user->arg = arg;
    8270        user->id = ++telnet_user_id_counter;
    8371
    84         int rc = asprintf(&user->service_name, "%s/telnet%u.%d", NAMESPACE,
    85             (unsigned)task_get_id(), user->id);
     72        int rc = asprintf(&user->service_name, "%s/telnet%d", NAMESPACE, user->id);
    8673        if (rc < 0) {
    8774                free(user);
     
    9178        user->conn = conn;
    9279        user->service_id = (service_id_t) -1;
     80        prodcons_initialize(&user->in_events);
    9381        link_initialize(&user->link);
    9482        user->socket_buffer_len = 0;
    9583        user->socket_buffer_pos = 0;
    96         user->send_buf_used = 0;
    9784
    9885        fibril_condvar_initialize(&user->refcount_cv);
    99         fibril_mutex_initialize(&user->send_lock);
    100         fibril_mutex_initialize(&user->recv_lock);
     86        fibril_mutex_initialize(&user->guard);
    10187        user->task_finished = false;
    10288        user->socket_closed = false;
     
    10490
    10591        user->cursor_x = 0;
    106         user->cursor_y = 0;
    10792
    10893        return user;
     
    152137
    153138        telnet_user_t *tmp = user;
    154         fibril_mutex_lock(&tmp->recv_lock);
     139        fibril_mutex_lock(&tmp->guard);
    155140        user->locsrv_connection_count++;
    156141
     
    164149        }
    165150
    166         fibril_mutex_unlock(&tmp->recv_lock);
     151        fibril_mutex_unlock(&tmp->guard);
    167152
    168153        fibril_mutex_unlock(&users_guard);
     
    177162void telnet_user_notify_client_disconnected(telnet_user_t *user)
    178163{
    179         fibril_mutex_lock(&user->recv_lock);
     164        fibril_mutex_lock(&user->guard);
    180165        assert(user->locsrv_connection_count > 0);
    181166        user->locsrv_connection_count--;
    182167        fibril_condvar_signal(&user->refcount_cv);
    183         fibril_mutex_unlock(&user->recv_lock);
     168        fibril_mutex_unlock(&user->guard);
    184169}
    185170
     
    190175bool telnet_user_is_zombie(telnet_user_t *user)
    191176{
    192         fibril_mutex_lock(&user->recv_lock);
     177        fibril_mutex_lock(&user->guard);
    193178        bool zombie = user->socket_closed || user->task_finished;
    194         fibril_mutex_unlock(&user->recv_lock);
     179        fibril_mutex_unlock(&user->guard);
    195180
    196181        return zombie;
    197182}
    198183
    199 static errno_t telnet_user_fill_recv_buf(telnet_user_t *user)
    200 {
    201         errno_t rc;
    202         size_t recv_length;
    203 
    204         rc = tcp_conn_recv_wait(user->conn, user->socket_buffer,
    205             BUFFER_SIZE, &recv_length);
    206         if (rc != EOK)
    207                 return rc;
    208 
    209         if (recv_length == 0) {
    210                 user->socket_closed = true;
    211                 user->srvs.aborted = true;
    212                 return ENOENT;
    213         }
    214 
    215         user->socket_buffer_len = recv_length;
    216         user->socket_buffer_pos = 0;
    217 
    218         return EOK;
    219 }
    220 
    221 /** Receive next byte from a socket (use buffering).
    222  *
    223  * @param user Telnet user
    224  * @param byte Place to store the received byte
    225  * @return EOK on success or an error code
    226  */
    227 static errno_t telnet_user_recv_next_byte_locked(telnet_user_t *user,
    228     uint8_t *byte)
    229 {
    230         errno_t rc;
    231 
     184/** Receive next byte from a socket (use buffering.
     185 * We need to return the value via extra argument because the read byte
     186 * might be negative.
     187 */
     188static errno_t telnet_user_recv_next_byte_no_lock(telnet_user_t *user, char *byte)
     189{
    232190        /* No more buffered data? */
    233191        if (user->socket_buffer_len <= user->socket_buffer_pos) {
    234                 rc = telnet_user_fill_recv_buf(user);
     192                errno_t rc;
     193                size_t recv_length;
     194
     195                rc = tcp_conn_recv_wait(user->conn, user->socket_buffer,
     196                    BUFFER_SIZE, &recv_length);
    235197                if (rc != EOK)
    236198                        return rc;
    237         }
    238 
    239         *byte = (uint8_t)user->socket_buffer[user->socket_buffer_pos++];
     199
     200                if (recv_length == 0) {
     201                        user->socket_closed = true;
     202                        user->srvs.aborted = true;
     203                        return ENOENT;
     204                }
     205
     206                user->socket_buffer_len = recv_length;
     207                user->socket_buffer_pos = 0;
     208        }
     209
     210        *byte = user->socket_buffer[user->socket_buffer_pos++];
     211
    240212        return EOK;
    241213}
    242214
    243 /** Determine if a received byte is available without waiting.
    244  *
    245  * @param user Telnet user
    246  * @return @c true iff a byte is currently available
    247  */
    248 static bool telnet_user_byte_avail(telnet_user_t *user)
    249 {
    250         return user->socket_buffer_len > user->socket_buffer_pos;
    251 }
    252 
    253 static errno_t telnet_user_send_opt(telnet_user_t *user, telnet_cmd_t cmd,
    254     telnet_cmd_t opt)
    255 {
    256         uint8_t cmdb[3];
    257 
    258         cmdb[0] = TELNET_IAC;
    259         cmdb[1] = cmd;
    260         cmdb[2] = opt;
    261 
    262         return telnet_user_send_raw_locked(user, (char *)cmdb, sizeof(cmdb));
    263 }
    264 
    265 /** Process telnet WILL NAWS command.
    266  *
    267  * @param user Telnet user structure.
    268  * @param cmd Telnet command.
    269  */
    270 static void process_telnet_will_naws(telnet_user_t *user)
    271 {
    272         telnet_user_log(user, "WILL NAWS");
    273         /* Send DO NAWS */
    274         (void) telnet_user_send_opt(user, TELNET_DO, TELNET_NAWS);
    275         (void) telnet_user_flush_locked(user);
    276 }
    277 
    278 /** Process telnet SB NAWS command.
    279  *
    280  * @param user Telnet user structure.
    281  * @param cmd Telnet command.
    282  */
    283 static void process_telnet_sb_naws(telnet_user_t *user)
    284 {
    285         uint8_t chi, clo;
    286         uint8_t rhi, rlo;
    287         uint16_t cols;
    288         uint16_t rows;
    289         uint8_t iac;
    290         uint8_t se;
    291         errno_t rc;
    292 
    293         telnet_user_log(user, "SB NAWS...");
    294 
    295         rc = telnet_user_recv_next_byte_locked(user, &chi);
    296         if (rc != EOK)
    297                 return;
    298         rc = telnet_user_recv_next_byte_locked(user, &clo);
    299         if (rc != EOK)
    300                 return;
    301 
    302         rc = telnet_user_recv_next_byte_locked(user, &rhi);
    303         if (rc != EOK)
    304                 return;
    305         rc = telnet_user_recv_next_byte_locked(user, &rlo);
    306         if (rc != EOK)
    307                 return;
    308 
    309         rc = telnet_user_recv_next_byte_locked(user, &iac);
    310         if (rc != EOK)
    311                 return;
    312         rc = telnet_user_recv_next_byte_locked(user, &se);
    313         if (rc != EOK)
    314                 return;
    315 
    316         cols = (chi << 8) | clo;
    317         rows = (rhi << 8) | rlo;
    318 
    319         telnet_user_log(user, "cols=%u rows=%u\n", cols, rows);
    320 
    321         if (cols < 1 || rows < 1) {
    322                 telnet_user_log(user, "Ignoring invalid window size update.");
    323                 return;
    324         }
    325 
    326         user->cb->ws_update(user->arg, cols, rows);
    327 }
    328 
    329 /** Process telnet WILL command.
    330  *
    331  * @param user Telnet user structure.
    332  * @param opt Option code.
    333  */
    334 static void process_telnet_will(telnet_user_t *user, telnet_cmd_t opt)
    335 {
    336         telnet_user_log(user, "WILL");
    337         switch (opt) {
    338         case TELNET_NAWS:
    339                 process_telnet_will_naws(user);
    340                 return;
    341         }
    342 
    343         telnet_user_log(user, "Ignoring telnet command %u %u %u.",
    344             TELNET_IAC, TELNET_WILL, opt);
    345 }
    346 
    347 /** Process telnet SB command.
    348  *
    349  * @param user Telnet user structure.
    350  * @param opt Option code.
    351  */
    352 static void process_telnet_sb(telnet_user_t *user, telnet_cmd_t opt)
    353 {
    354         telnet_user_log(user, "SB");
    355         switch (opt) {
    356         case TELNET_NAWS:
    357                 process_telnet_sb_naws(user);
    358                 return;
    359         }
    360 
    361         telnet_user_log(user, "Ignoring telnet command %u %u %u.",
    362             TELNET_IAC, TELNET_SB, opt);
    363 }
    364 
    365 /** Process telnet command.
     215/** Creates new keyboard event from given char.
     216 *
     217 * @param type Event type (press / release).
     218 * @param c Pressed character.
     219 */
     220static kbd_event_t *new_kbd_event(kbd_event_type_t type, char32_t c)
     221{
     222        kbd_event_t *event = malloc(sizeof(kbd_event_t));
     223        assert(event);
     224
     225        link_initialize(&event->link);
     226        event->type = type;
     227        event->c = c;
     228        event->mods = 0;
     229
     230        switch (c) {
     231        case '\n':
     232                event->key = KC_ENTER;
     233                break;
     234        case '\t':
     235                event->key = KC_TAB;
     236                break;
     237        case '\b':
     238        case 127: /* This is what Linux telnet sends. */
     239                event->key = KC_BACKSPACE;
     240                event->c = '\b';
     241                break;
     242        default:
     243                event->key = KC_A;
     244                break;
     245        }
     246
     247        return event;
     248}
     249
     250/** Process telnet command (currently only print to screen).
    366251 *
    367252 * @param user Telnet user structure.
     
    372257    telnet_cmd_t option_code, telnet_cmd_t cmd)
    373258{
    374         switch (option_code) {
    375         case TELNET_SB:
    376                 process_telnet_sb(user, cmd);
    377                 return;
    378         case TELNET_WILL:
    379                 process_telnet_will(user, cmd);
    380                 return;
    381         }
    382 
    383259        if (option_code != 0) {
    384260                telnet_user_log(user, "Ignoring telnet command %u %u %u.",
     
    390266}
    391267
    392 /** Receive data from telnet connection.
     268/** Get next keyboard event.
    393269 *
    394270 * @param user Telnet user.
    395  * @param buf Destination buffer
    396  * @param size Buffer size
    397  * @param nread Place to store number of bytes read (>0 on success)
    398  * @return EOK on success or an error code
    399  */
    400 errno_t telnet_user_recv(telnet_user_t *user, void *buf, size_t size,
    401     size_t *nread)
    402 {
    403         uint8_t *bp = (uint8_t *)buf;
    404         fibril_mutex_lock(&user->recv_lock);
    405 
    406         assert(size > 0);
    407         *nread = 0;
    408 
    409         do {
    410                 uint8_t next_byte = 0;
     271 * @param event Where to store the keyboard event.
     272 * @return Error code.
     273 */
     274errno_t telnet_user_get_next_keyboard_event(telnet_user_t *user, kbd_event_t *event)
     275{
     276        fibril_mutex_lock(&user->guard);
     277        if (list_empty(&user->in_events.list)) {
     278                char next_byte = 0;
    411279                bool inside_telnet_command = false;
    412280
     
    414282
    415283                /* Skip zeros, bail-out on error. */
    416                 do {
    417                         errno_t rc = telnet_user_recv_next_byte_locked(user,
    418                             &next_byte);
     284                while (next_byte == 0) {
     285                        errno_t rc = telnet_user_recv_next_byte_no_lock(user, &next_byte);
    419286                        if (rc != EOK) {
    420                                 fibril_mutex_unlock(&user->recv_lock);
     287                                fibril_mutex_unlock(&user->guard);
    421288                                return rc;
    422289                        }
    423                         uint8_t byte = next_byte;
     290                        uint8_t byte = (uint8_t) next_byte;
    424291
    425292                        /* Skip telnet commands. */
     
    427294                                inside_telnet_command = false;
    428295                                next_byte = 0;
    429                                 if (TELNET_IS_OPTION_CODE(byte) ||
    430                                     byte == TELNET_SB) {
     296                                if (TELNET_IS_OPTION_CODE(byte)) {
    431297                                        telnet_option_code = byte;
    432298                                        inside_telnet_command = true;
     
    440306                                next_byte = 0;
    441307                        }
    442                 } while (next_byte == 0 && telnet_user_byte_avail(user));
     308                }
    443309
    444310                /* CR-LF conversions. */
     
    447313                }
    448314
    449                 if (next_byte != 0) {
    450                         *bp++ = next_byte;
    451                         ++*nread;
    452                         --size;
    453                 }
    454         } while (size > 0 && (telnet_user_byte_avail(user) || *nread == 0));
    455 
    456         fibril_mutex_unlock(&user->recv_lock);
    457         return EOK;
    458 }
    459 
    460 static errno_t telnet_user_send_raw_locked(telnet_user_t *user,
    461     const void *data, size_t size)
    462 {
    463         size_t remain;
    464         size_t now;
    465         errno_t rc;
    466 
    467         remain = sizeof(user->send_buf) - user->send_buf_used;
    468         while (size > 0) {
    469                 if (remain == 0) {
    470                         rc = tcp_conn_send(user->conn, user->send_buf,
    471                             sizeof(user->send_buf));
    472                         if (rc != EOK)
    473                                 return rc;
    474 
    475                         user->send_buf_used = 0;
    476                         remain = sizeof(user->send_buf);
    477                 }
    478 
    479                 now = min(remain, size);
    480                 memcpy(user->send_buf + user->send_buf_used, data, now);
    481                 user->send_buf_used += now;
    482                 remain -= now;
    483                 data += now;
    484                 size -= now;
    485         }
     315                kbd_event_t *down = new_kbd_event(KEY_PRESS, next_byte);
     316                kbd_event_t *up = new_kbd_event(KEY_RELEASE, next_byte);
     317                assert(down);
     318                assert(up);
     319                prodcons_produce(&user->in_events, &down->link);
     320                prodcons_produce(&user->in_events, &up->link);
     321        }
     322
     323        link_t *link = prodcons_consume(&user->in_events);
     324        kbd_event_t *tmp = list_get_instance(link, kbd_event_t, link);
     325
     326        fibril_mutex_unlock(&user->guard);
     327
     328        *event = *tmp;
     329
     330        free(tmp);
    486331
    487332        return EOK;
     
    494339 * @param size Size of @p data buffer in bytes.
    495340 */
    496 static errno_t telnet_user_send_data_locked(telnet_user_t *user,
    497     const char *data, size_t size)
     341static errno_t telnet_user_send_data_no_lock(telnet_user_t *user, uint8_t *data, size_t size)
    498342{
    499343        uint8_t *converted = malloc(3 * size + 1);
     
    507351                        converted[converted_size++] = 10;
    508352                        user->cursor_x = 0;
    509                         if (user->cursor_y < (int)user->rows - 1)
    510                                 ++user->cursor_y;
    511353                } else {
    512354                        converted[converted_size++] = data[i];
     
    519361        }
    520362
    521         errno_t rc = telnet_user_send_raw_locked(user, converted,
    522             converted_size);
     363        errno_t rc = tcp_conn_send(user->conn, converted, converted_size);
    523364        free(converted);
    524365
     
    532373 * @param size Size of @p data buffer in bytes.
    533374 */
    534 errno_t telnet_user_send_data(telnet_user_t *user, const char *data,
    535     size_t size)
    536 {
    537         fibril_mutex_lock(&user->send_lock);
    538 
    539         errno_t rc = telnet_user_send_data_locked(user, data, size);
    540 
    541         fibril_mutex_unlock(&user->send_lock);
    542 
    543         return rc;
    544 }
    545 
    546 /** Send raw non-printable data to the socket.
    547  *
    548  * @param user Telnet user.
    549  * @param data Data buffer (not zero terminated).
    550  * @param size Size of @p data buffer in bytes.
    551  */
    552 errno_t telnet_user_send_raw(telnet_user_t *user, const char *data,
    553     size_t size)
    554 {
    555         fibril_mutex_lock(&user->send_lock);
    556 
    557         errno_t rc = telnet_user_send_raw_locked(user, data, size);
    558 
    559         fibril_mutex_unlock(&user->send_lock);
    560 
    561         return rc;
    562 }
    563 
    564 static errno_t telnet_user_flush_locked(telnet_user_t *user)
    565 {
    566         errno_t rc;
    567 
    568         rc = tcp_conn_send(user->conn, user->send_buf, user->send_buf_used);
    569         if (rc != EOK)
    570                 return rc;
    571 
    572         user->send_buf_used = 0;
    573         return EOK;
    574 }
    575 
    576 errno_t telnet_user_flush(telnet_user_t *user)
    577 {
    578         errno_t rc;
    579 
    580         fibril_mutex_lock(&user->send_lock);
    581         rc = telnet_user_flush_locked(user);
    582         fibril_mutex_unlock(&user->send_lock);
     375errno_t telnet_user_send_data(telnet_user_t *user, uint8_t *data, size_t size)
     376{
     377        fibril_mutex_lock(&user->guard);
     378
     379        errno_t rc = telnet_user_send_data_no_lock(user, data, size);
     380
     381        fibril_mutex_unlock(&user->guard);
     382
    583383        return rc;
    584384}
     
    593393void telnet_user_update_cursor_x(telnet_user_t *user, int new_x)
    594394{
    595         fibril_mutex_lock(&user->send_lock);
     395        fibril_mutex_lock(&user->guard);
    596396        if (user->cursor_x - 1 == new_x) {
    597                 char data = '\b';
     397                uint8_t data = '\b';
    598398                /* Ignore errors. */
    599                 telnet_user_send_data_locked(user, &data, 1);
     399                telnet_user_send_data_no_lock(user, &data, 1);
    600400        }
    601401        user->cursor_x = new_x;
    602         fibril_mutex_unlock(&user->send_lock);
    603 
    604 }
    605 
    606 /** Resize telnet session.
    607  *
    608  * @param user Telnet user
    609  * @param cols New number of columns
    610  * @param rows New number of rows
    611  */
    612 void telnet_user_resize(telnet_user_t *user, unsigned cols, unsigned rows)
    613 {
    614         user->cols = cols;
    615         user->rows = rows;
    616         if ((unsigned)user->cursor_x > cols - 1)
    617                 user->cursor_x = cols - 1;
    618         if ((unsigned)user->cursor_y > rows - 1)
    619                 user->cursor_y = rows - 1;
     402        fibril_mutex_unlock(&user->guard);
     403
    620404}
    621405
Note: See TracChangeset for help on using the changeset viewer.