Changeset 47d060d in mainline


Ignore:
Timestamp:
2024-10-04T19:23:16Z (7 days ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
master
Children:
c7ecd290
Parents:
5132379
Message:

Implement telnet window size option

Location:
uspace
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/vt/include/vt/vt100.h

    r5132379 r47d060d  
    157157extern vt100_t *vt100_create(void *, sysarg_t, sysarg_t,
    158158    vt100_cb_t *);
     159extern void vt100_resize(vt100_t *, sysarg_t, sysarg_t);
    159160extern void vt100_destroy(vt100_t *);
    160161
  • uspace/lib/vt/src/vt100.c

    r5132379 r47d060d  
    206206}
    207207
     208/** Resize VT instance.
     209 *
     210 * @param vt VT instance
     211 * @param cols New number of columns
     212 * @param rows New number of rows
     213 */
     214void vt100_resize(vt100_t *vt, sysarg_t cols, sysarg_t rows)
     215{
     216        vt->cols = cols;
     217        vt->rows = rows;
     218
     219        if (vt->cur_col > cols - 1)
     220                vt->cur_col = cols - 1;
     221        if (vt->cur_row > rows - 1)
     222                vt->cur_row = rows - 1;
     223}
     224
    208225/** Destroy VT instance.
    209226 *
  • uspace/srv/hid/remcons/remcons.c

    r5132379 r47d060d  
    144144};
    145145
     146static void remcons_telnet_ws_update(void *, unsigned, unsigned);
     147
     148static telnet_cb_t remcons_telnet_cb = {
     149        .ws_update = remcons_telnet_ws_update
     150};
     151
    146152static loc_srv_t *remcons_srv;
    147153static bool no_ctl;
     
    260266
    261267        if (remcons->enable_ctl) {
    262                 *cols = 80;
    263                 *rows = 25;
     268                *cols = remcons->vt->cols;
     269                *rows = remcons->vt->rows;
    264270        } else {
    265271                *cols = 100;
     
    352358{
    353359        remcons_event_t *event = malloc(sizeof(remcons_event_t));
    354         assert(event);
     360        if (event == NULL) {
     361                fprintf(stderr, "Out of memory.\n");
     362                return NULL;
     363        }
    355364
    356365        link_initialize(&event->link);
    357         event->kbd.type = type;
    358         event->kbd.mods = mods;
    359         event->kbd.key = key;
    360         event->kbd.c = c;
     366        event->cev.type = CEV_KEY;
     367        event->cev.ev.key.type = type;
     368        event->cev.ev.key.mods = mods;
     369        event->cev.ev.key.key = key;
     370        event->cev.ev.key.c = c;
     371
     372        return event;
     373}
     374
     375/** Creates new console resize event.
     376 */
     377static remcons_event_t *new_resize_event(void)
     378{
     379        remcons_event_t *event = malloc(sizeof(remcons_event_t));
     380        if (event == NULL) {
     381                fprintf(stderr, "Out of memory.\n");
     382                return NULL;
     383        }
     384
     385        link_initialize(&event->link);
     386        event->cev.type = CEV_RESIZE;
    361387
    362388        return event;
     
    385411        remcons_event_t *tmp = list_get_instance(link, remcons_event_t, link);
    386412
    387         event->type = CEV_KEY;
    388         event->ev.key = tmp->kbd;
    389 
     413        *event = tmp->cev;
    390414        free(tmp);
    391415
     
    590614
    591615        remcons_event_t *down = new_kbd_event(KEY_PRESS, mods, key, c);
     616        if (down == NULL)
     617                return;
     618
    592619        remcons_event_t *up = new_kbd_event(KEY_RELEASE, mods, key, c);
    593         assert(down);
    594         assert(up);
     620        if (up == NULL) {
     621                free(down);
     622                return;
     623        }
     624
    595625        list_append(&down->link, &remcons->in_events);
    596626        list_append(&up->link, &remcons->in_events);
     627}
     628
     629/** Window size update callback.
     630 *
     631 * @param arg Argument (remcons_t *)
     632 * @param cols New number of columns
     633 * @param rows New number of rows
     634 */
     635static void remcons_telnet_ws_update(void *arg, unsigned cols, unsigned rows)
     636{
     637        remcons_t *remcons = (remcons_t *)arg;
     638
     639        vt100_resize(remcons->vt, cols, rows);
     640        telnet_user_resize(remcons->user, cols, rows);
     641
     642        remcons_event_t *resize = new_resize_event();
     643        if (resize == NULL)
     644                return;
     645
     646        list_append(&resize->link, &remcons->in_events);
    597647}
    598648
     
    605655{
    606656        char_attrs_t attrs;
    607         remcons_t *remcons = calloc(1, sizeof(remcons_t));
    608         assert(remcons != NULL); // XXX
    609         telnet_user_t *user = telnet_user_create(conn);
    610         assert(user);
     657        remcons_t *remcons = NULL;
     658        telnet_user_t *user = NULL;
     659
     660        remcons = calloc(1, sizeof(remcons_t));
     661        if (remcons == NULL) {
     662                fprintf(stderr, "Out of memory.\n");
     663                goto error;
     664        }
     665
     666        user = telnet_user_create(conn, &remcons_telnet_cb,
     667            (void *)remcons);
     668        if (user == NULL) {
     669                fprintf(stderr, "Out of memory.\n");
     670                goto error;
     671        }
    611672
    612673        remcons->enable_ctl = !no_ctl;
     
    626687
    627688        remcons->vt = vt100_create((void *)remcons, 80, 25, &remcons_vt_cb);
    628         assert(remcons->vt != NULL); // XXX
     689        if (remcons->vt == NULL) {
     690                fprintf(stderr, "Error creating VT100 driver instance.\n");
     691                goto error;
     692        }
     693
    629694        remcons->vt->enable_rgb = remcons->enable_rgb;
    630695
     
    649714                telnet_user_error(user, "Unable to register %s with loc: %s.",
    650715                    user->service_name, str_error(rc));
    651                 return;
     716                goto error;
    652717        }
    653718
     
    656721
    657722        fid_t spawn_fibril = fibril_create(spawn_task_fibril, user);
    658         assert(spawn_fibril);
     723        if (spawn_fibril == 0) {
     724                fprintf(stderr, "Failed creating fibril.\n");
     725                goto error;
     726        }
    659727        fibril_add_ready(spawn_fibril);
    660728
     
    685753        telnet_user_log(user, "Destroying...");
    686754        telnet_user_destroy(user);
     755        return;
     756error:
     757        if (user != NULL && user->service_id != 0)
     758                loc_service_unregister(remcons_srv, user->service_id);
     759        if (user != NULL)
     760                free(user);
     761        if (remcons != NULL && remcons->vt != NULL)
     762                vt100_destroy(remcons->vt);
     763        if (remcons != NULL)
     764                free(remcons);
    687765}
    688766
  • uspace/srv/hid/remcons/remcons.h

    r5132379 r47d060d  
    3838
    3939#include <adt/list.h>
    40 #include <io/kbd_event.h>
     40#include <io/cons_event.h>
    4141#include <stdbool.h>
    4242#include <vt/vt100.h>
     
    6464typedef struct {
    6565        link_t link;            /**< link to list of events */
    66         kbd_event_t kbd;        /**< keyboard event */
     66        cons_event_t cev;       /**< console event */
    6767} remcons_event_t;
    6868
  • uspace/srv/hid/remcons/telnet.h

    r5132379 r47d060d  
    11/*
     2 * Copyright (c) 2024 Jiri Svoboda
    23 * Copyright (c) 2012 Vojtech Horky
    34 * All rights reserved.
     
    4445 */
    4546
     47#define TELNET_SE 240
     48#define TELNET_SB 250
    4649#define TELNET_IAC 255
    4750
     
    5558#define TELNET_ECHO 1
    5659#define TELNET_SUPPRESS_GO_AHEAD 3
     60#define TELNET_NAWS 31
    5761#define TELNET_LINEMODE 34
    5862
  • uspace/srv/hid/remcons/user.c

    r5132379 r47d060d  
    5858static LIST_INITIALIZE(users);
    5959
     60static errno_t telnet_user_send_raw_locked(telnet_user_t *, const void *,
     61    size_t);
     62static errno_t telnet_user_flush_locked(telnet_user_t *);
     63
    6064/** Create new telnet user.
    6165 *
    6266 * @param conn Incoming connection.
     67 * @param cb Callback functions
     68 * @param arg Argument to callback functions
    6369 * @return New telnet user or NULL when out of memory.
    6470 */
    65 telnet_user_t *telnet_user_create(tcp_conn_t *conn)
     71telnet_user_t *telnet_user_create(tcp_conn_t *conn, telnet_cb_t *cb, void *arg)
    6672{
    6773        static int telnet_user_id_counter = 0;
     
    7278        }
    7379
     80        user->cb = cb;
     81        user->arg = arg;
    7482        user->id = ++telnet_user_id_counter;
    7583
     
    216224 * @return EOK on success or an error code
    217225 */
    218 static errno_t telnet_user_recv_next_byte_locked(telnet_user_t *user, char *byte)
     226static errno_t telnet_user_recv_next_byte_locked(telnet_user_t *user,
     227    uint8_t *byte)
    219228{
    220229        errno_t rc;
     
    227236        }
    228237
    229         *byte = user->socket_buffer[user->socket_buffer_pos++];
     238        *byte = (uint8_t)user->socket_buffer[user->socket_buffer_pos++];
    230239        return EOK;
    231240}
     
    241250}
    242251
    243 /** Process telnet command (currently only print to screen).
     252static errno_t telnet_user_send_opt(telnet_user_t *user, telnet_cmd_t cmd,
     253    telnet_cmd_t opt)
     254{
     255        uint8_t cmdb[3];
     256
     257        cmdb[0] = TELNET_IAC;
     258        cmdb[1] = cmd;
     259        cmdb[2] = opt;
     260
     261        return telnet_user_send_raw_locked(user, (char *)cmdb, sizeof(cmdb));
     262}
     263
     264/** Process telnet WILL NAWS command.
     265 *
     266 * @param user Telnet user structure.
     267 * @param cmd Telnet command.
     268 */
     269static void process_telnet_will_naws(telnet_user_t *user)
     270{
     271        telnet_user_log(user, "WILL NAWS");
     272        /* Send DO NAWS */
     273        (void) telnet_user_send_opt(user, TELNET_DO, TELNET_NAWS);
     274        (void) telnet_user_flush_locked(user);
     275}
     276
     277/** Process telnet SB NAWS command.
     278 *
     279 * @param user Telnet user structure.
     280 * @param cmd Telnet command.
     281 */
     282static void process_telnet_sb_naws(telnet_user_t *user)
     283{
     284        uint8_t chi, clo;
     285        uint8_t rhi, rlo;
     286        uint16_t cols;
     287        uint16_t rows;
     288        uint8_t iac;
     289        uint8_t se;
     290        errno_t rc;
     291
     292        telnet_user_log(user, "SB NAWS...");
     293
     294        rc = telnet_user_recv_next_byte_locked(user, &chi);
     295        if (rc != EOK)
     296                return;
     297        rc = telnet_user_recv_next_byte_locked(user, &clo);
     298        if (rc != EOK)
     299                return;
     300
     301        rc = telnet_user_recv_next_byte_locked(user, &rhi);
     302        if (rc != EOK)
     303                return;
     304        rc = telnet_user_recv_next_byte_locked(user, &rlo);
     305        if (rc != EOK)
     306                return;
     307
     308        rc = telnet_user_recv_next_byte_locked(user, &iac);
     309        if (rc != EOK)
     310                return;
     311        rc = telnet_user_recv_next_byte_locked(user, &se);
     312        if (rc != EOK)
     313                return;
     314
     315        cols = (chi << 8) | clo;
     316        rows = (rhi << 8) | rlo;
     317
     318        telnet_user_log(user, "cols=%u rows=%u\n", cols, rows);
     319
     320        if (cols < 1 || rows < 1) {
     321                telnet_user_log(user, "Ignoring invalid window size update.");
     322                return;
     323        }
     324
     325        user->cb->ws_update(user->arg, cols, rows);
     326}
     327
     328/** Process telnet WILL command.
     329 *
     330 * @param user Telnet user structure.
     331 * @param opt Option code.
     332 */
     333static void process_telnet_will(telnet_user_t *user, telnet_cmd_t opt)
     334{
     335        telnet_user_log(user, "WILL");
     336        switch (opt) {
     337        case TELNET_NAWS:
     338                process_telnet_will_naws(user);
     339                return;
     340        }
     341
     342        telnet_user_log(user, "Ignoring telnet command %u %u %u.",
     343            TELNET_IAC, TELNET_WILL, opt);
     344}
     345
     346/** Process telnet SB command.
     347 *
     348 * @param user Telnet user structure.
     349 * @param opt Option code.
     350 */
     351static void process_telnet_sb(telnet_user_t *user, telnet_cmd_t opt)
     352{
     353        telnet_user_log(user, "SB");
     354        switch (opt) {
     355        case TELNET_NAWS:
     356                process_telnet_sb_naws(user);
     357                return;
     358        }
     359
     360        telnet_user_log(user, "Ignoring telnet command %u %u %u.",
     361            TELNET_IAC, TELNET_SB, opt);
     362}
     363
     364/** Process telnet command.
    244365 *
    245366 * @param user Telnet user structure.
     
    250371    telnet_cmd_t option_code, telnet_cmd_t cmd)
    251372{
     373        switch (option_code) {
     374        case TELNET_SB:
     375                process_telnet_sb(user, cmd);
     376                return;
     377        case TELNET_WILL:
     378                process_telnet_will(user, cmd);
     379                return;
     380        }
     381
    252382        if (option_code != 0) {
    253383                telnet_user_log(user, "Ignoring telnet command %u %u %u.",
     
    277407
    278408        do {
    279                 char next_byte = 0;
     409                uint8_t next_byte = 0;
    280410                bool inside_telnet_command = false;
    281411
     
    290420                                return rc;
    291421                        }
    292                         uint8_t byte = (uint8_t) next_byte;
     422                        uint8_t byte = next_byte;
    293423
    294424                        /* Skip telnet commands. */
     
    296426                                inside_telnet_command = false;
    297427                                next_byte = 0;
    298                                 if (TELNET_IS_OPTION_CODE(byte)) {
     428                                if (TELNET_IS_OPTION_CODE(byte) ||
     429                                    byte == TELNET_SB) {
    299430                                        telnet_option_code = byte;
    300431                                        inside_telnet_command = true;
     
    430561}
    431562
     563static errno_t telnet_user_flush_locked(telnet_user_t *user)
     564{
     565        errno_t rc;
     566
     567        rc = tcp_conn_send(user->conn, user->send_buf, user->send_buf_used);
     568        if (rc != EOK)
     569                return rc;
     570
     571        user->send_buf_used = 0;
     572        return EOK;
     573}
     574
    432575errno_t telnet_user_flush(telnet_user_t *user)
    433576{
     
    435578
    436579        fibril_mutex_lock(&user->guard);
    437         rc = tcp_conn_send(user->conn, user->send_buf, user->send_buf_used);
    438 
    439         if (rc != EOK) {
    440                 fibril_mutex_unlock(&user->guard);
    441                 return rc;
    442         }
    443 
    444         user->send_buf_used = 0;
     580        rc = telnet_user_flush_locked(user);
    445581        fibril_mutex_unlock(&user->guard);
    446         return EOK;
     582        return rc;
    447583}
    448584
     
    467603}
    468604
     605/** Resize telnet session.
     606 *
     607 * @param user Telnet user
     608 * @param cols New number of columns
     609 * @param rows New number of rows
     610 */
     611void telnet_user_resize(telnet_user_t *user, unsigned cols, unsigned rows)
     612{
     613        user->cols = cols;
     614        user->rows = rows;
     615        if ((unsigned)user->cursor_x > cols - 1)
     616                user->cursor_x = cols - 1;
     617        if ((unsigned)user->cursor_y > rows - 1)
     618                user->cursor_y = rows - 1;
     619}
     620
    469621/**
    470622 * @}
  • uspace/srv/hid/remcons/user.h

    r5132379 r47d060d  
    4545#define SEND_BUF_SIZE 512
    4646
     47/** Telnet callbacks */
     48typedef struct {
     49        void (*ws_update)(void *, unsigned, unsigned);
     50} telnet_cb_t;
     51
    4752/** Representation of a connected (human) user. */
    4853typedef struct {
    4954        /** Mutex guarding the whole structure. */
    5055        fibril_mutex_t guard;
     56        /** Callback functions */
     57        telnet_cb_t *cb;
     58        /** Argument to callback functions */
     59        void *arg;
    5160
    5261        /** Internal id, used for creating locfs entries. */
     
    8796} telnet_user_t;
    8897
    89 extern telnet_user_t *telnet_user_create(tcp_conn_t *);
     98extern telnet_user_t *telnet_user_create(tcp_conn_t *, telnet_cb_t *, void *);
    9099extern void telnet_user_add(telnet_user_t *);
    91100extern void telnet_user_destroy(telnet_user_t *);
     
    99108extern errno_t telnet_user_recv(telnet_user_t *, void *, size_t, size_t *);
    100109extern void telnet_user_update_cursor_x(telnet_user_t *, int);
     110extern void telnet_user_resize(telnet_user_t *, unsigned, unsigned);
    101111
    102112/** Print informational message about connected user. */
Note: See TracChangeset for help on using the changeset viewer.