Changeset ebb1489 in mainline for uspace/srv/hid/remcons/remcons.c


Ignore:
Timestamp:
2024-10-13T08:23:40Z (2 months ago)
Author:
GitHub <noreply@…>
Children:
0472cf17
Parents:
2a0c827c (diff), b3b79981 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
git-author:
boba-buba <120932204+boba-buba@…> (2024-10-13 08:23:40)
git-committer:
GitHub <noreply@…> (2024-10-13 08:23:40)
Message:

Merge branch 'HelenOS:master' into topic/packet-capture

File:
1 edited

Legend:

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

    r2a0c827c rebb1489  
    11/*
    2  * Copyright (c) 2023 Jiri Svoboda
     2 * Copyright (c) 2024 Jiri Svoboda
    33 * Copyright (c) 2012 Vojtech Horky
    44 * All rights reserved.
     
    3434 */
    3535
     36#include <adt/list.h>
     37#include <as.h>
    3638#include <async.h>
    3739#include <errno.h>
     
    5153#include <inttypes.h>
    5254#include <str.h>
     55#include <vt/vt100.h>
    5356#include "telnet.h"
    5457#include "user.h"
     58#include "remcons.h"
    5559
    5660#define APP_GETTERM  "/app/getterm"
    5761#define APP_SHELL "/app/bdsh"
     62
     63#define DEF_PORT 2223
    5864
    5965/** Telnet commands to force character mode
     
    7480static errno_t remcons_open(con_srvs_t *, con_srv_t *);
    7581static errno_t remcons_close(con_srv_t *);
     82static errno_t remcons_read(con_srv_t *, void *, size_t, size_t *);
    7683static errno_t remcons_write(con_srv_t *, void *, size_t, size_t *);
    7784static void remcons_sync(con_srv_t *);
     
    8188static errno_t remcons_get_size(con_srv_t *, sysarg_t *, sysarg_t *);
    8289static errno_t remcons_get_color_cap(con_srv_t *, console_caps_t *);
     90static void remcons_set_style(con_srv_t *, console_style_t);
     91static void remcons_set_color(con_srv_t *, console_color_t,
     92    console_color_t, console_color_attr_t);
     93static void remcons_set_color(con_srv_t *, console_color_t,
     94    console_color_t, console_color_attr_t);
     95static void remcons_set_rgb_color(con_srv_t *, pixel_t, pixel_t);
     96static void remcons_cursor_visibility(con_srv_t *, bool);
    8397static errno_t remcons_get_event(con_srv_t *, cons_event_t *);
     98static errno_t remcons_map(con_srv_t *, sysarg_t, sysarg_t, charfield_t **);
     99static void remcons_unmap(con_srv_t *);
     100static void remcons_update(con_srv_t *, sysarg_t, sysarg_t, sysarg_t,
     101    sysarg_t);
    84102
    85103static con_ops_t con_ops = {
    86104        .open = remcons_open,
    87105        .close = remcons_close,
    88         .read = NULL,
     106        .read = remcons_read,
    89107        .write = remcons_write,
    90108        .sync = remcons_sync,
     
    94112        .get_size = remcons_get_size,
    95113        .get_color_cap = remcons_get_color_cap,
    96         .set_style = NULL,
    97         .set_color = NULL,
    98         .set_rgb_color = NULL,
    99         .set_cursor_visibility = NULL,
    100         .get_event = remcons_get_event
     114        .set_style = remcons_set_style,
     115        .set_color = remcons_set_color,
     116        .set_rgb_color = remcons_set_rgb_color,
     117        .set_cursor_visibility = remcons_cursor_visibility,
     118        .get_event = remcons_get_event,
     119        .map = remcons_map,
     120        .unmap = remcons_unmap,
     121        .update = remcons_update
     122};
     123
     124static void remcons_vt_putchar(void *, char32_t);
     125static void remcons_vt_cputs(void *, const char *);
     126static void remcons_vt_flush(void *);
     127static void remcons_vt_key(void *, keymod_t, keycode_t, char);
     128static void remcons_vt_pos_event(void *, pos_event_t *);
     129
     130static vt100_cb_t remcons_vt_cb = {
     131        .putuchar = remcons_vt_putchar,
     132        .control_puts = remcons_vt_cputs,
     133        .flush = remcons_vt_flush,
     134        .key = remcons_vt_key,
     135        .pos_event = remcons_vt_pos_event
    101136};
    102137
     
    111146};
    112147
     148static void remcons_telnet_ws_update(void *, unsigned, unsigned);
     149
     150static telnet_cb_t remcons_telnet_cb = {
     151        .ws_update = remcons_telnet_ws_update
     152};
     153
    113154static loc_srv_t *remcons_srv;
     155static bool no_ctl;
     156static bool no_rgb;
    114157
    115158static telnet_user_t *srv_to_user(con_srv_t *srv)
    116159{
    117         return srv->srvs->sarg;
     160        remcons_t *remcons = (remcons_t *)srv->srvs->sarg;
     161        return remcons->user;
     162}
     163
     164static remcons_t *srv_to_remcons(con_srv_t *srv)
     165{
     166        remcons_t *remcons = (remcons_t *)srv->srvs->sarg;
     167        return remcons;
    118168}
    119169
     
    141191}
    142192
    143 static errno_t remcons_write(con_srv_t *srv, void *data, size_t size, size_t *nwritten)
     193static errno_t remcons_read(con_srv_t *srv, void *data, size_t size,
     194    size_t *nread)
    144195{
    145196        telnet_user_t *user = srv_to_user(srv);
    146197        errno_t rc;
    147198
    148         rc = telnet_user_send_data(user, data, size);
     199        rc = telnet_user_recv(user, data, size, nread);
    149200        if (rc != EOK)
    150201                return rc;
    151202
     203        return EOK;
     204}
     205
     206static errno_t remcons_write(con_srv_t *srv, void *data, size_t size, size_t *nwritten)
     207{
     208        remcons_t *remcons = srv_to_remcons(srv);
     209        errno_t rc;
     210
     211        rc = telnet_user_send_data(remcons->user, data, size);
     212        if (rc != EOK)
     213                return rc;
     214
     215        rc = telnet_user_flush(remcons->user);
     216        if (rc != EOK)
     217                return rc;
     218
    152219        *nwritten = size;
    153220        return EOK;
     
    161228static void remcons_clear(con_srv_t *srv)
    162229{
    163         (void) srv;
     230        remcons_t *remcons = srv_to_remcons(srv);
     231
     232        if (remcons->enable_ctl) {
     233                vt100_cls(remcons->vt);
     234                vt100_set_pos(remcons->vt, 0, 0);
     235                remcons->user->cursor_x = 0;
     236                remcons->user->cursor_y = 0;
     237        }
    164238}
    165239
    166240static void remcons_set_pos(con_srv_t *srv, sysarg_t col, sysarg_t row)
    167241{
     242        remcons_t *remcons = srv_to_remcons(srv);
    168243        telnet_user_t *user = srv_to_user(srv);
    169244
    170         telnet_user_update_cursor_x(user, col);
     245        if (remcons->enable_ctl) {
     246                vt100_set_pos(remcons->vt, col, row);
     247                remcons->user->cursor_x = col;
     248                remcons->user->cursor_y = row;
     249                (void)telnet_user_flush(remcons->user);
     250        } else {
     251                telnet_user_update_cursor_x(user, col);
     252        }
    171253}
    172254
     
    176258
    177259        *col = user->cursor_x;
    178         *row = 0;
     260        *row = user->cursor_y;
    179261
    180262        return EOK;
     
    183265static errno_t remcons_get_size(con_srv_t *srv, sysarg_t *cols, sysarg_t *rows)
    184266{
    185         (void) srv;
    186 
    187         *cols = 100;
    188         *rows = 1;
     267        remcons_t *remcons = srv_to_remcons(srv);
     268
     269        if (remcons->enable_ctl) {
     270                *cols = remcons->vt->cols;
     271                *rows = remcons->vt->rows;
     272        } else {
     273                *cols = 100;
     274                *rows = 1;
     275        }
    189276
    190277        return EOK;
     
    193280static errno_t remcons_get_color_cap(con_srv_t *srv, console_caps_t *ccaps)
    194281{
    195         (void) srv;
    196         *ccaps = CONSOLE_CAP_NONE;
     282        remcons_t *remcons = srv_to_remcons(srv);
     283
     284        *ccaps = 0;
     285
     286        if (remcons->enable_ctl) {
     287                *ccaps |= CONSOLE_CAP_CURSORCTL | CONSOLE_CAP_STYLE |
     288                    CONSOLE_CAP_INDEXED;
     289        }
     290
     291        if (remcons->enable_rgb)
     292                *ccaps |= CONSOLE_CAP_RGB;
    197293
    198294        return EOK;
    199295}
    200296
     297static void remcons_set_style(con_srv_t *srv, console_style_t style)
     298{
     299        remcons_t *remcons = srv_to_remcons(srv);
     300        char_attrs_t attrs;
     301
     302        if (remcons->enable_ctl) {
     303                attrs.type = CHAR_ATTR_STYLE;
     304                attrs.val.style = style;
     305                vt100_set_attr(remcons->vt, attrs);
     306        }
     307}
     308
     309static void remcons_set_color(con_srv_t *srv, console_color_t bgcolor,
     310    console_color_t fgcolor, console_color_attr_t flags)
     311{
     312        remcons_t *remcons = srv_to_remcons(srv);
     313        char_attrs_t attrs;
     314
     315        if (remcons->enable_ctl) {
     316                attrs.type = CHAR_ATTR_INDEX;
     317                attrs.val.index.bgcolor = bgcolor;
     318                attrs.val.index.fgcolor = fgcolor;
     319                attrs.val.index.attr = flags;
     320                vt100_set_attr(remcons->vt, attrs);
     321        }
     322}
     323
     324static void remcons_set_rgb_color(con_srv_t *srv, pixel_t bgcolor,
     325    pixel_t fgcolor)
     326{
     327        remcons_t *remcons = srv_to_remcons(srv);
     328        char_attrs_t attrs;
     329
     330        if (remcons->enable_ctl) {
     331                attrs.type = CHAR_ATTR_RGB;
     332                attrs.val.rgb.bgcolor = bgcolor;
     333                attrs.val.rgb.fgcolor = fgcolor;
     334                vt100_set_attr(remcons->vt, attrs);
     335        }
     336}
     337
     338static void remcons_cursor_visibility(con_srv_t *srv, bool visible)
     339{
     340        remcons_t *remcons = srv_to_remcons(srv);
     341
     342        if (remcons->enable_ctl) {
     343                if (!remcons->curs_visible && visible) {
     344                        vt100_set_pos(remcons->vt, remcons->user->cursor_x,
     345                            remcons->user->cursor_y);
     346                }
     347                vt100_cursor_visibility(remcons->vt, visible);
     348        }
     349
     350        remcons->curs_visible = visible;
     351}
     352
     353/** Creates new keyboard event from given char.
     354 *
     355 * @param type Event type (press / release).
     356 * @param c Pressed character.
     357 */
     358static remcons_event_t *new_kbd_event(kbd_event_type_t type, keymod_t mods,
     359    keycode_t key, char c)
     360{
     361        remcons_event_t *event = malloc(sizeof(remcons_event_t));
     362        if (event == NULL) {
     363                fprintf(stderr, "Out of memory.\n");
     364                return NULL;
     365        }
     366
     367        link_initialize(&event->link);
     368        event->cev.type = CEV_KEY;
     369        event->cev.ev.key.type = type;
     370        event->cev.ev.key.mods = mods;
     371        event->cev.ev.key.key = key;
     372        event->cev.ev.key.c = c;
     373
     374        return event;
     375}
     376
     377/** Creates new position event.
     378 *
     379 * @param ev Position event.
     380 * @param c Pressed character.
     381 */
     382static remcons_event_t *new_pos_event(pos_event_t *ev)
     383{
     384        remcons_event_t *event = malloc(sizeof(remcons_event_t));
     385        if (event == NULL) {
     386                fprintf(stderr, "Out of memory.\n");
     387                return NULL;
     388        }
     389
     390        link_initialize(&event->link);
     391        event->cev.type = CEV_POS;
     392        event->cev.ev.pos = *ev;
     393
     394        return event;
     395}
     396
     397/** Creates new console resize event.
     398 */
     399static remcons_event_t *new_resize_event(void)
     400{
     401        remcons_event_t *event = malloc(sizeof(remcons_event_t));
     402        if (event == NULL) {
     403                fprintf(stderr, "Out of memory.\n");
     404                return NULL;
     405        }
     406
     407        link_initialize(&event->link);
     408        event->cev.type = CEV_RESIZE;
     409
     410        return event;
     411}
     412
    201413static errno_t remcons_get_event(con_srv_t *srv, cons_event_t *event)
    202414{
     415        remcons_t *remcons = srv_to_remcons(srv);
    203416        telnet_user_t *user = srv_to_user(srv);
    204         kbd_event_t kevent;
    205         errno_t rc;
    206 
    207         rc = telnet_user_get_next_keyboard_event(user, &kevent);
    208         if (rc != EOK) {
    209                 /* XXX What? */
    210                 memset(event, 0, sizeof(*event));
    211                 return EOK;
    212         }
    213 
    214         event->type = CEV_KEY;
    215         event->ev.key = kevent;
     417        size_t nread;
     418
     419        while (list_empty(&remcons->in_events)) {
     420                char next_byte = 0;
     421
     422                errno_t rc = telnet_user_recv(user, &next_byte, 1,
     423                    &nread);
     424                if (rc != EOK)
     425                        return rc;
     426
     427                vt100_rcvd_char(remcons->vt, next_byte);
     428        }
     429
     430        link_t *link = list_first(&remcons->in_events);
     431        list_remove(link);
     432
     433        remcons_event_t *tmp = list_get_instance(link, remcons_event_t, link);
     434
     435        *event = tmp->cev;
     436        free(tmp);
    216437
    217438        return EOK;
     439}
     440
     441static errno_t remcons_map(con_srv_t *srv, sysarg_t cols, sysarg_t rows,
     442    charfield_t **rbuf)
     443{
     444        remcons_t *remcons = srv_to_remcons(srv);
     445        void *buf;
     446
     447        if (!remcons->enable_ctl)
     448                return ENOTSUP;
     449
     450        if (remcons->ubuf != NULL)
     451                return EBUSY;
     452
     453        buf = as_area_create(AS_AREA_ANY, cols * rows * sizeof(charfield_t),
     454            AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE, AS_AREA_UNPAGED);
     455        if (buf == AS_MAP_FAILED)
     456                return ENOMEM;
     457
     458        remcons->ucols = cols;
     459        remcons->urows = rows;
     460        remcons->ubuf = buf;
     461
     462        *rbuf = buf;
     463        return EOK;
     464
     465}
     466
     467static void remcons_unmap(con_srv_t *srv)
     468{
     469        remcons_t *remcons = srv_to_remcons(srv);
     470        void *buf;
     471
     472        buf = remcons->ubuf;
     473        remcons->ubuf = NULL;
     474
     475        if (buf != NULL)
     476                as_area_destroy(buf);
     477}
     478
     479static void remcons_update(con_srv_t *srv, sysarg_t c0, sysarg_t r0,
     480    sysarg_t c1, sysarg_t r1)
     481{
     482        remcons_t *remcons = srv_to_remcons(srv);
     483        charfield_t *ch;
     484        sysarg_t col, row;
     485        sysarg_t old_x, old_y;
     486
     487        if (remcons->ubuf == NULL)
     488                return;
     489
     490        /* Make sure we have meaningful coordinates, within bounds */
     491
     492        if (c1 > remcons->ucols)
     493                c1 = remcons->ucols;
     494        if (c1 > remcons->user->cols)
     495                c1 = remcons->user->cols;
     496        if (c0 >= c1)
     497                return;
     498
     499        if (r1 > remcons->urows)
     500                r1 = remcons->urows;
     501        if (r1 > remcons->user->rows)
     502                r1 = remcons->user->rows;
     503        if (r0 >= r1)
     504                return;
     505
     506        /* Update screen from user buffer */
     507
     508        old_x = remcons->user->cursor_x;
     509        old_y = remcons->user->cursor_y;
     510
     511        if (remcons->curs_visible)
     512                vt100_cursor_visibility(remcons->vt, false);
     513
     514        for (row = r0; row < r1; row++) {
     515                for (col = c0; col < c1; col++) {
     516                        vt100_set_pos(remcons->vt, col, row);
     517                        ch = &remcons->ubuf[row * remcons->ucols + col];
     518                        vt100_set_attr(remcons->vt, ch->attrs);
     519                        vt100_putuchar(remcons->vt, ch->ch);
     520                }
     521        }
     522
     523        if (remcons->curs_visible) {
     524                old_x = remcons->user->cursor_x = old_x;
     525                remcons->user->cursor_y = old_y;
     526                vt100_set_pos(remcons->vt, old_x, old_y);
     527                vt100_cursor_visibility(remcons->vt, true);
     528        }
     529
     530        /* Flush data */
     531        (void)telnet_user_flush(remcons->user);
    218532}
    219533
     
    248562                    "failed: %s.", APP_GETTERM, user->service_name, APP_SHELL,
    249563                    str_error(rc));
    250                 fibril_mutex_lock(&user->guard);
     564                fibril_mutex_lock(&user->recv_lock);
    251565                user->task_finished = true;
    252566                user->srvs.aborted = true;
    253567                fibril_condvar_signal(&user->refcount_cv);
    254                 fibril_mutex_unlock(&user->guard);
     568                fibril_mutex_unlock(&user->recv_lock);
    255569                return EOK;
    256570        }
    257571
    258         fibril_mutex_lock(&user->guard);
     572        fibril_mutex_lock(&user->recv_lock);
    259573        user->task_id = task;
    260         fibril_mutex_unlock(&user->guard);
     574        fibril_mutex_unlock(&user->recv_lock);
    261575
    262576        task_exit_t task_exit;
     
    268582
    269583        /* Announce destruction. */
    270         fibril_mutex_lock(&user->guard);
     584        fibril_mutex_lock(&user->recv_lock);
    271585        user->task_finished = true;
    272586        user->srvs.aborted = true;
    273587        fibril_condvar_signal(&user->refcount_cv);
    274         fibril_mutex_unlock(&user->guard);
     588        fibril_mutex_unlock(&user->recv_lock);
    275589
    276590        return EOK;
     
    285599        return user->task_finished && user->socket_closed &&
    286600            (user->locsrv_connection_count == 0);
     601}
     602
     603static void remcons_vt_putchar(void *arg, char32_t c)
     604{
     605        remcons_t *remcons = (remcons_t *)arg;
     606        char buf[STR_BOUNDS(1)];
     607        size_t off;
     608        errno_t rc;
     609
     610        (void)arg;
     611
     612        off = 0;
     613        rc = chr_encode(c, buf, &off, sizeof(buf));
     614        if (rc != EOK)
     615                return;
     616
     617        (void)telnet_user_send_data(remcons->user, buf, off);
     618}
     619
     620static void remcons_vt_cputs(void *arg, const char *str)
     621{
     622        remcons_t *remcons = (remcons_t *)arg;
     623
     624        (void)telnet_user_send_raw(remcons->user, str, str_size(str));
     625}
     626
     627static void remcons_vt_flush(void *arg)
     628{
     629        remcons_t *remcons = (remcons_t *)arg;
     630        (void)telnet_user_flush(remcons->user);
     631}
     632
     633static void remcons_vt_key(void *arg, keymod_t mods, keycode_t key, char c)
     634{
     635        remcons_t *remcons = (remcons_t *)arg;
     636
     637        remcons_event_t *down = new_kbd_event(KEY_PRESS, mods, key, c);
     638        if (down == NULL)
     639                return;
     640
     641        remcons_event_t *up = new_kbd_event(KEY_RELEASE, mods, key, c);
     642        if (up == NULL) {
     643                free(down);
     644                return;
     645        }
     646
     647        list_append(&down->link, &remcons->in_events);
     648        list_append(&up->link, &remcons->in_events);
     649}
     650
     651static void remcons_vt_pos_event(void *arg, pos_event_t *ev)
     652{
     653        remcons_t *remcons = (remcons_t *)arg;
     654
     655        remcons_event_t *cev = new_pos_event(ev);
     656        if (cev == NULL)
     657                return;
     658
     659        list_append(&cev->link, &remcons->in_events);
     660}
     661
     662/** Window size update callback.
     663 *
     664 * @param arg Argument (remcons_t *)
     665 * @param cols New number of columns
     666 * @param rows New number of rows
     667 */
     668static void remcons_telnet_ws_update(void *arg, unsigned cols, unsigned rows)
     669{
     670        remcons_t *remcons = (remcons_t *)arg;
     671
     672        vt100_resize(remcons->vt, cols, rows);
     673        telnet_user_resize(remcons->user, cols, rows);
     674
     675        remcons_event_t *resize = new_resize_event();
     676        if (resize == NULL)
     677                return;
     678
     679        list_append(&resize->link, &remcons->in_events);
    287680}
    288681
     
    294687static void remcons_new_conn(tcp_listener_t *lst, tcp_conn_t *conn)
    295688{
    296         telnet_user_t *user = telnet_user_create(conn);
    297         assert(user);
     689        char_attrs_t attrs;
     690        remcons_t *remcons = NULL;
     691        telnet_user_t *user = NULL;
     692
     693        remcons = calloc(1, sizeof(remcons_t));
     694        if (remcons == NULL) {
     695                fprintf(stderr, "Out of memory.\n");
     696                goto error;
     697        }
     698
     699        user = telnet_user_create(conn, &remcons_telnet_cb,
     700            (void *)remcons);
     701        if (user == NULL) {
     702                fprintf(stderr, "Out of memory.\n");
     703                goto error;
     704        }
     705
     706        remcons->enable_ctl = !no_ctl;
     707        remcons->enable_rgb = !no_ctl && !no_rgb;
     708        remcons->user = user;
     709        list_initialize(&remcons->in_events);
     710
     711        if (remcons->enable_ctl) {
     712                user->cols = 80;
     713                user->rows = 25;
     714        } else {
     715                user->cols = 100;
     716                user->rows = 1;
     717        }
     718
     719        remcons->curs_visible = true;
     720
     721        remcons->vt = vt100_create((void *)remcons, 80, 25, &remcons_vt_cb);
     722        if (remcons->vt == NULL) {
     723                fprintf(stderr, "Error creating VT100 driver instance.\n");
     724                goto error;
     725        }
     726
     727        remcons->vt->enable_rgb = remcons->enable_rgb;
     728
     729        if (remcons->enable_ctl) {
     730                attrs.type = CHAR_ATTR_STYLE;
     731                attrs.val.style = STYLE_NORMAL;
     732                vt100_set_sgr(remcons->vt, attrs);
     733                vt100_cls(remcons->vt);
     734                vt100_set_pos(remcons->vt, 0, 0);
     735                vt100_set_button_reporting(remcons->vt, true);
     736        }
    298737
    299738        con_srvs_init(&user->srvs);
    300739        user->srvs.ops = &con_ops;
    301         user->srvs.sarg = user;
    302         user->srvs.abort_timeout = 1000;
     740        user->srvs.sarg = remcons;
     741        user->srvs.abort_timeout = 1000000;
    303742
    304743        telnet_user_add(user);
     
    309748                telnet_user_error(user, "Unable to register %s with loc: %s.",
    310749                    user->service_name, str_error(rc));
    311                 return;
     750                goto error;
    312751        }
    313752
     
    316755
    317756        fid_t spawn_fibril = fibril_create(spawn_task_fibril, user);
    318         assert(spawn_fibril);
     757        if (spawn_fibril == 0) {
     758                fprintf(stderr, "Failed creating fibril.\n");
     759                goto error;
     760        }
    319761        fibril_add_ready(spawn_fibril);
    320762
    321763        /* Wait for all clients to exit. */
    322         fibril_mutex_lock(&user->guard);
     764        fibril_mutex_lock(&user->recv_lock);
    323765        while (!user_can_be_destroyed_no_lock(user)) {
    324766                if (user->task_finished) {
    325                         user->conn = NULL;
    326767                        user->socket_closed = true;
    327768                        user->srvs.aborted = true;
    328                         continue;
    329769                } else if (user->socket_closed) {
    330770                        if (user->task_id != 0) {
     
    332772                        }
    333773                }
    334                 fibril_condvar_wait_timeout(&user->refcount_cv, &user->guard, 1000);
    335         }
    336         fibril_mutex_unlock(&user->guard);
     774                fibril_condvar_wait_timeout(&user->refcount_cv,
     775                    &user->recv_lock, 1000000);
     776        }
     777        fibril_mutex_unlock(&user->recv_lock);
    337778
    338779        rc = loc_service_unregister(remcons_srv, user->service_id);
     
    344785
    345786        telnet_user_log(user, "Destroying...");
     787
     788        if (remcons->enable_ctl) {
     789                /* Disable mouse tracking */
     790                vt100_set_button_reporting(remcons->vt, false);
     791
     792                /* Reset all character attributes and clear screen */
     793                vt100_sgr(remcons->vt, 0);
     794                vt100_cls(remcons->vt);
     795                vt100_set_pos(remcons->vt, 0, 0);
     796
     797                telnet_user_flush(user);
     798        }
     799
     800        tcp_conn_send_fin(user->conn);
     801        user->conn = NULL;
     802
    346803        telnet_user_destroy(user);
     804        vt100_destroy(remcons->vt);
     805        free(remcons);
     806        return;
     807error:
     808        if (user != NULL && user->service_id != 0)
     809                loc_service_unregister(remcons_srv, user->service_id);
     810        if (user != NULL)
     811                free(user);
     812        if (remcons != NULL && remcons->vt != NULL)
     813                vt100_destroy(remcons->vt);
     814        if (remcons != NULL)
     815                free(remcons);
     816}
     817
     818static void print_syntax(void)
     819{
     820        fprintf(stderr, "syntax: remcons [<options>]\n");
     821        fprintf(stderr, "\t--no-ctl      Disable all terminal control sequences\n");
     822        fprintf(stderr, "\t--no-rgb      Disable RGB colors\n");
     823        fprintf(stderr, "\t--port <port> Listening port (default: %u)\n",
     824            DEF_PORT);
    347825}
    348826
     
    353831        tcp_t *tcp;
    354832        inet_ep_t ep;
     833        uint16_t port;
     834        int i;
     835
     836        port = DEF_PORT;
     837
     838        i = 1;
     839        while (i < argc) {
     840                if (argv[i][0] == '-') {
     841                        if (str_cmp(argv[i], "--no-ctl") == 0) {
     842                                no_ctl = true;
     843                        } else if (str_cmp(argv[i], "--no-rgb") == 0) {
     844                                no_rgb = true;
     845                        } else if (str_cmp(argv[i], "--port") == 0) {
     846                                ++i;
     847                                if (i >= argc) {
     848                                        fprintf(stderr, "Option argument "
     849                                            "missing.\n");
     850                                        print_syntax();
     851                                        return EINVAL;
     852                                }
     853                                rc = str_uint16_t(argv[i], NULL, 10, true, &port);
     854                                if (rc != EOK) {
     855                                        fprintf(stderr, "Invalid port number "
     856                                            "'%s'.\n", argv[i]);
     857                                        print_syntax();
     858                                        return EINVAL;
     859                                }
     860                        } else {
     861                                fprintf(stderr, "Unknown option '%s'.\n",
     862                                    argv[i]);
     863                                print_syntax();
     864                                return EINVAL;
     865                        }
     866                } else {
     867                        fprintf(stderr, "Unexpected argument.\n");
     868                        print_syntax();
     869                        return EINVAL;
     870                }
     871
     872                ++i;
     873        }
    355874
    356875        async_set_fallback_port_handler(client_connection, NULL);
     
    368887
    369888        inet_ep_init(&ep);
    370         ep.port = 2223;
     889        ep.port = port;
    371890
    372891        rc = tcp_listener_create(tcp, &ep, &listen_cb, NULL, &conn_cb, NULL,
Note: See TracChangeset for help on using the changeset viewer.