Ignore:
File:
1 edited

Legend:

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

    r4c6fd56 r9d5cea6  
    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);
     97static errno_t remcons_set_caption(con_srv_t *, const char *);
    8398static errno_t remcons_get_event(con_srv_t *, cons_event_t *);
     99static errno_t remcons_map(con_srv_t *, sysarg_t, sysarg_t, charfield_t **);
     100static void remcons_unmap(con_srv_t *);
     101static void remcons_update(con_srv_t *, sysarg_t, sysarg_t, sysarg_t,
     102    sysarg_t);
    84103
    85104static con_ops_t con_ops = {
    86105        .open = remcons_open,
    87106        .close = remcons_close,
    88         .read = NULL,
     107        .read = remcons_read,
    89108        .write = remcons_write,
    90109        .sync = remcons_sync,
     
    94113        .get_size = remcons_get_size,
    95114        .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
     115        .set_style = remcons_set_style,
     116        .set_color = remcons_set_color,
     117        .set_rgb_color = remcons_set_rgb_color,
     118        .set_cursor_visibility = remcons_cursor_visibility,
     119        .set_caption = remcons_set_caption,
     120        .get_event = remcons_get_event,
     121        .map = remcons_map,
     122        .unmap = remcons_unmap,
     123        .update = remcons_update
     124};
     125
     126static void remcons_vt_putchar(void *, char32_t);
     127static void remcons_vt_cputs(void *, const char *);
     128static void remcons_vt_flush(void *);
     129static void remcons_vt_key(void *, keymod_t, keycode_t, char);
     130static void remcons_vt_pos_event(void *, pos_event_t *);
     131
     132static vt100_cb_t remcons_vt_cb = {
     133        .putuchar = remcons_vt_putchar,
     134        .control_puts = remcons_vt_cputs,
     135        .flush = remcons_vt_flush,
     136        .key = remcons_vt_key,
     137        .pos_event = remcons_vt_pos_event
    101138};
    102139
     
    111148};
    112149
     150static void remcons_telnet_ws_update(void *, unsigned, unsigned);
     151
     152static telnet_cb_t remcons_telnet_cb = {
     153        .ws_update = remcons_telnet_ws_update
     154};
     155
    113156static loc_srv_t *remcons_srv;
     157static bool no_ctl;
     158static bool no_rgb;
    114159
    115160static telnet_user_t *srv_to_user(con_srv_t *srv)
    116161{
    117         return srv->srvs->sarg;
     162        remcons_t *remcons = (remcons_t *)srv->srvs->sarg;
     163        return remcons->user;
     164}
     165
     166static remcons_t *srv_to_remcons(con_srv_t *srv)
     167{
     168        remcons_t *remcons = (remcons_t *)srv->srvs->sarg;
     169        return remcons;
    118170}
    119171
     
    141193}
    142194
    143 static errno_t remcons_write(con_srv_t *srv, void *data, size_t size, size_t *nwritten)
     195static errno_t remcons_read(con_srv_t *srv, void *data, size_t size,
     196    size_t *nread)
    144197{
    145198        telnet_user_t *user = srv_to_user(srv);
    146199        errno_t rc;
    147200
    148         rc = telnet_user_send_data(user, data, size);
     201        rc = telnet_user_recv(user, data, size, nread);
    149202        if (rc != EOK)
    150203                return rc;
    151204
     205        return EOK;
     206}
     207
     208static errno_t remcons_write(con_srv_t *srv, void *data, size_t size, size_t *nwritten)
     209{
     210        remcons_t *remcons = srv_to_remcons(srv);
     211        errno_t rc;
     212
     213        rc = telnet_user_send_data(remcons->user, data, size);
     214        if (rc != EOK)
     215                return rc;
     216
     217        rc = telnet_user_flush(remcons->user);
     218        if (rc != EOK)
     219                return rc;
     220
    152221        *nwritten = size;
    153222        return EOK;
     
    161230static void remcons_clear(con_srv_t *srv)
    162231{
    163         (void) srv;
     232        remcons_t *remcons = srv_to_remcons(srv);
     233
     234        if (remcons->enable_ctl) {
     235                vt100_cls(remcons->vt);
     236                vt100_set_pos(remcons->vt, 0, 0);
     237                remcons->user->cursor_x = 0;
     238                remcons->user->cursor_y = 0;
     239        }
    164240}
    165241
    166242static void remcons_set_pos(con_srv_t *srv, sysarg_t col, sysarg_t row)
    167243{
     244        remcons_t *remcons = srv_to_remcons(srv);
    168245        telnet_user_t *user = srv_to_user(srv);
    169246
    170         telnet_user_update_cursor_x(user, col);
     247        if (remcons->enable_ctl) {
     248                vt100_set_pos(remcons->vt, col, row);
     249                remcons->user->cursor_x = col;
     250                remcons->user->cursor_y = row;
     251                (void)telnet_user_flush(remcons->user);
     252        } else {
     253                telnet_user_update_cursor_x(user, col);
     254        }
    171255}
    172256
     
    176260
    177261        *col = user->cursor_x;
    178         *row = 0;
     262        *row = user->cursor_y;
    179263
    180264        return EOK;
     
    183267static errno_t remcons_get_size(con_srv_t *srv, sysarg_t *cols, sysarg_t *rows)
    184268{
    185         (void) srv;
    186 
    187         *cols = 100;
    188         *rows = 1;
     269        remcons_t *remcons = srv_to_remcons(srv);
     270
     271        if (remcons->enable_ctl) {
     272                *cols = remcons->vt->cols;
     273                *rows = remcons->vt->rows;
     274        } else {
     275                *cols = 100;
     276                *rows = 1;
     277        }
    189278
    190279        return EOK;
     
    193282static errno_t remcons_get_color_cap(con_srv_t *srv, console_caps_t *ccaps)
    194283{
    195         (void) srv;
    196         *ccaps = CONSOLE_CAP_NONE;
    197 
    198         return EOK;
     284        remcons_t *remcons = srv_to_remcons(srv);
     285
     286        *ccaps = 0;
     287
     288        if (remcons->enable_ctl) {
     289                *ccaps |= CONSOLE_CAP_CURSORCTL | CONSOLE_CAP_STYLE |
     290                    CONSOLE_CAP_INDEXED;
     291        }
     292
     293        if (remcons->enable_rgb)
     294                *ccaps |= CONSOLE_CAP_RGB;
     295
     296        return EOK;
     297}
     298
     299static void remcons_set_style(con_srv_t *srv, console_style_t style)
     300{
     301        remcons_t *remcons = srv_to_remcons(srv);
     302        char_attrs_t attrs;
     303
     304        if (remcons->enable_ctl) {
     305                attrs.type = CHAR_ATTR_STYLE;
     306                attrs.val.style = style;
     307                vt100_set_attr(remcons->vt, attrs);
     308        }
     309}
     310
     311static void remcons_set_color(con_srv_t *srv, console_color_t bgcolor,
     312    console_color_t fgcolor, console_color_attr_t flags)
     313{
     314        remcons_t *remcons = srv_to_remcons(srv);
     315        char_attrs_t attrs;
     316
     317        if (remcons->enable_ctl) {
     318                attrs.type = CHAR_ATTR_INDEX;
     319                attrs.val.index.bgcolor = bgcolor;
     320                attrs.val.index.fgcolor = fgcolor;
     321                attrs.val.index.attr = flags;
     322                vt100_set_attr(remcons->vt, attrs);
     323        }
     324}
     325
     326static void remcons_set_rgb_color(con_srv_t *srv, pixel_t bgcolor,
     327    pixel_t fgcolor)
     328{
     329        remcons_t *remcons = srv_to_remcons(srv);
     330        char_attrs_t attrs;
     331
     332        if (remcons->enable_ctl) {
     333                attrs.type = CHAR_ATTR_RGB;
     334                attrs.val.rgb.bgcolor = bgcolor;
     335                attrs.val.rgb.fgcolor = fgcolor;
     336                vt100_set_attr(remcons->vt, attrs);
     337        }
     338}
     339
     340static void remcons_cursor_visibility(con_srv_t *srv, bool visible)
     341{
     342        remcons_t *remcons = srv_to_remcons(srv);
     343
     344        if (remcons->enable_ctl) {
     345                if (!remcons->curs_visible && visible) {
     346                        vt100_set_pos(remcons->vt, remcons->user->cursor_x,
     347                            remcons->user->cursor_y);
     348                }
     349                vt100_cursor_visibility(remcons->vt, visible);
     350        }
     351
     352        remcons->curs_visible = visible;
     353}
     354
     355static errno_t remcons_set_caption(con_srv_t *srv, const char *caption)
     356{
     357        remcons_t *remcons = srv_to_remcons(srv);
     358
     359        if (remcons->enable_ctl) {
     360                vt100_set_title(remcons->vt, caption);
     361        }
     362
     363        return EOK;
     364}
     365
     366/** Creates new keyboard event from given char.
     367 *
     368 * @param type Event type (press / release).
     369 * @param c Pressed character.
     370 */
     371static remcons_event_t *new_kbd_event(kbd_event_type_t type, keymod_t mods,
     372    keycode_t key, char c)
     373{
     374        remcons_event_t *event = malloc(sizeof(remcons_event_t));
     375        if (event == NULL) {
     376                fprintf(stderr, "Out of memory.\n");
     377                return NULL;
     378        }
     379
     380        link_initialize(&event->link);
     381        event->cev.type = CEV_KEY;
     382        event->cev.ev.key.type = type;
     383        event->cev.ev.key.mods = mods;
     384        event->cev.ev.key.key = key;
     385        event->cev.ev.key.c = c;
     386
     387        return event;
     388}
     389
     390/** Creates new position event.
     391 *
     392 * @param ev Position event.
     393 * @param c Pressed character.
     394 */
     395static remcons_event_t *new_pos_event(pos_event_t *ev)
     396{
     397        remcons_event_t *event = malloc(sizeof(remcons_event_t));
     398        if (event == NULL) {
     399                fprintf(stderr, "Out of memory.\n");
     400                return NULL;
     401        }
     402
     403        link_initialize(&event->link);
     404        event->cev.type = CEV_POS;
     405        event->cev.ev.pos = *ev;
     406
     407        return event;
     408}
     409
     410/** Creates new console resize event.
     411 */
     412static remcons_event_t *new_resize_event(void)
     413{
     414        remcons_event_t *event = malloc(sizeof(remcons_event_t));
     415        if (event == NULL) {
     416                fprintf(stderr, "Out of memory.\n");
     417                return NULL;
     418        }
     419
     420        link_initialize(&event->link);
     421        event->cev.type = CEV_RESIZE;
     422
     423        return event;
    199424}
    200425
    201426static errno_t remcons_get_event(con_srv_t *srv, cons_event_t *event)
    202427{
     428        remcons_t *remcons = srv_to_remcons(srv);
    203429        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;
    216 
    217         return EOK;
     430        size_t nread;
     431
     432        while (list_empty(&remcons->in_events)) {
     433                char next_byte = 0;
     434
     435                errno_t rc = telnet_user_recv(user, &next_byte, 1,
     436                    &nread);
     437                if (rc != EOK)
     438                        return rc;
     439
     440                vt100_rcvd_char(remcons->vt, next_byte);
     441        }
     442
     443        link_t *link = list_first(&remcons->in_events);
     444        list_remove(link);
     445
     446        remcons_event_t *tmp = list_get_instance(link, remcons_event_t, link);
     447
     448        *event = tmp->cev;
     449        free(tmp);
     450
     451        return EOK;
     452}
     453
     454static errno_t remcons_map(con_srv_t *srv, sysarg_t cols, sysarg_t rows,
     455    charfield_t **rbuf)
     456{
     457        remcons_t *remcons = srv_to_remcons(srv);
     458        void *buf;
     459
     460        if (!remcons->enable_ctl)
     461                return ENOTSUP;
     462
     463        if (remcons->ubuf != NULL)
     464                return EBUSY;
     465
     466        buf = as_area_create(AS_AREA_ANY, cols * rows * sizeof(charfield_t),
     467            AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE, AS_AREA_UNPAGED);
     468        if (buf == AS_MAP_FAILED)
     469                return ENOMEM;
     470
     471        remcons->ucols = cols;
     472        remcons->urows = rows;
     473        remcons->ubuf = buf;
     474
     475        *rbuf = buf;
     476        return EOK;
     477
     478}
     479
     480static void remcons_unmap(con_srv_t *srv)
     481{
     482        remcons_t *remcons = srv_to_remcons(srv);
     483        void *buf;
     484
     485        buf = remcons->ubuf;
     486        remcons->ubuf = NULL;
     487
     488        if (buf != NULL)
     489                as_area_destroy(buf);
     490}
     491
     492static void remcons_update(con_srv_t *srv, sysarg_t c0, sysarg_t r0,
     493    sysarg_t c1, sysarg_t r1)
     494{
     495        remcons_t *remcons = srv_to_remcons(srv);
     496        charfield_t *ch;
     497        sysarg_t col, row;
     498        sysarg_t old_x, old_y;
     499
     500        if (remcons->ubuf == NULL)
     501                return;
     502
     503        /* Make sure we have meaningful coordinates, within bounds */
     504
     505        if (c1 > remcons->ucols)
     506                c1 = remcons->ucols;
     507        if (c1 > remcons->user->cols)
     508                c1 = remcons->user->cols;
     509        if (c0 >= c1)
     510                return;
     511
     512        if (r1 > remcons->urows)
     513                r1 = remcons->urows;
     514        if (r1 > remcons->user->rows)
     515                r1 = remcons->user->rows;
     516        if (r0 >= r1)
     517                return;
     518
     519        /* Update screen from user buffer */
     520
     521        old_x = remcons->user->cursor_x;
     522        old_y = remcons->user->cursor_y;
     523
     524        if (remcons->curs_visible)
     525                vt100_cursor_visibility(remcons->vt, false);
     526
     527        for (row = r0; row < r1; row++) {
     528                for (col = c0; col < c1; col++) {
     529                        vt100_set_pos(remcons->vt, col, row);
     530                        ch = &remcons->ubuf[row * remcons->ucols + col];
     531                        vt100_set_attr(remcons->vt, ch->attrs);
     532                        vt100_putuchar(remcons->vt, ch->ch);
     533                }
     534        }
     535
     536        if (remcons->curs_visible) {
     537                old_x = remcons->user->cursor_x = old_x;
     538                remcons->user->cursor_y = old_y;
     539                vt100_set_pos(remcons->vt, old_x, old_y);
     540                vt100_cursor_visibility(remcons->vt, true);
     541        }
     542
     543        /* Flush data */
     544        (void)telnet_user_flush(remcons->user);
    218545}
    219546
     
    248575                    "failed: %s.", APP_GETTERM, user->service_name, APP_SHELL,
    249576                    str_error(rc));
    250                 fibril_mutex_lock(&user->guard);
     577                fibril_mutex_lock(&user->recv_lock);
    251578                user->task_finished = true;
    252579                user->srvs.aborted = true;
    253580                fibril_condvar_signal(&user->refcount_cv);
    254                 fibril_mutex_unlock(&user->guard);
     581                fibril_mutex_unlock(&user->recv_lock);
    255582                return EOK;
    256583        }
    257584
    258         fibril_mutex_lock(&user->guard);
     585        fibril_mutex_lock(&user->recv_lock);
    259586        user->task_id = task;
    260         fibril_mutex_unlock(&user->guard);
     587        fibril_mutex_unlock(&user->recv_lock);
    261588
    262589        task_exit_t task_exit;
     
    268595
    269596        /* Announce destruction. */
    270         fibril_mutex_lock(&user->guard);
     597        fibril_mutex_lock(&user->recv_lock);
    271598        user->task_finished = true;
    272599        user->srvs.aborted = true;
    273600        fibril_condvar_signal(&user->refcount_cv);
    274         fibril_mutex_unlock(&user->guard);
     601        fibril_mutex_unlock(&user->recv_lock);
    275602
    276603        return EOK;
     
    285612        return user->task_finished && user->socket_closed &&
    286613            (user->locsrv_connection_count == 0);
     614}
     615
     616static void remcons_vt_putchar(void *arg, char32_t c)
     617{
     618        remcons_t *remcons = (remcons_t *)arg;
     619        char buf[STR_BOUNDS(1)];
     620        size_t off;
     621        errno_t rc;
     622
     623        (void)arg;
     624
     625        off = 0;
     626        rc = chr_encode(c, buf, &off, sizeof(buf));
     627        if (rc != EOK)
     628                return;
     629
     630        (void)telnet_user_send_data(remcons->user, buf, off);
     631}
     632
     633static void remcons_vt_cputs(void *arg, const char *str)
     634{
     635        remcons_t *remcons = (remcons_t *)arg;
     636
     637        (void)telnet_user_send_raw(remcons->user, str, str_size(str));
     638}
     639
     640static void remcons_vt_flush(void *arg)
     641{
     642        remcons_t *remcons = (remcons_t *)arg;
     643        (void)telnet_user_flush(remcons->user);
     644}
     645
     646static void remcons_vt_key(void *arg, keymod_t mods, keycode_t key, char c)
     647{
     648        remcons_t *remcons = (remcons_t *)arg;
     649
     650        remcons_event_t *down = new_kbd_event(KEY_PRESS, mods, key, c);
     651        if (down == NULL)
     652                return;
     653
     654        remcons_event_t *up = new_kbd_event(KEY_RELEASE, mods, key, c);
     655        if (up == NULL) {
     656                free(down);
     657                return;
     658        }
     659
     660        list_append(&down->link, &remcons->in_events);
     661        list_append(&up->link, &remcons->in_events);
     662}
     663
     664static void remcons_vt_pos_event(void *arg, pos_event_t *ev)
     665{
     666        remcons_t *remcons = (remcons_t *)arg;
     667
     668        remcons_event_t *cev = new_pos_event(ev);
     669        if (cev == NULL)
     670                return;
     671
     672        list_append(&cev->link, &remcons->in_events);
     673}
     674
     675/** Window size update callback.
     676 *
     677 * @param arg Argument (remcons_t *)
     678 * @param cols New number of columns
     679 * @param rows New number of rows
     680 */
     681static void remcons_telnet_ws_update(void *arg, unsigned cols, unsigned rows)
     682{
     683        remcons_t *remcons = (remcons_t *)arg;
     684
     685        vt100_resize(remcons->vt, cols, rows);
     686        telnet_user_resize(remcons->user, cols, rows);
     687
     688        remcons_event_t *resize = new_resize_event();
     689        if (resize == NULL)
     690                return;
     691
     692        list_append(&resize->link, &remcons->in_events);
    287693}
    288694
     
    294700static void remcons_new_conn(tcp_listener_t *lst, tcp_conn_t *conn)
    295701{
    296         telnet_user_t *user = telnet_user_create(conn);
    297         assert(user);
     702        char_attrs_t attrs;
     703        remcons_t *remcons = NULL;
     704        telnet_user_t *user = NULL;
     705
     706        remcons = calloc(1, sizeof(remcons_t));
     707        if (remcons == NULL) {
     708                fprintf(stderr, "Out of memory.\n");
     709                goto error;
     710        }
     711
     712        user = telnet_user_create(conn, &remcons_telnet_cb,
     713            (void *)remcons);
     714        if (user == NULL) {
     715                fprintf(stderr, "Out of memory.\n");
     716                goto error;
     717        }
     718
     719        remcons->enable_ctl = !no_ctl;
     720        remcons->enable_rgb = !no_ctl && !no_rgb;
     721        remcons->user = user;
     722        list_initialize(&remcons->in_events);
     723
     724        if (remcons->enable_ctl) {
     725                user->cols = 80;
     726                user->rows = 25;
     727        } else {
     728                user->cols = 100;
     729                user->rows = 1;
     730        }
     731
     732        remcons->curs_visible = true;
     733
     734        remcons->vt = vt100_create((void *)remcons, 80, 25, &remcons_vt_cb);
     735        if (remcons->vt == NULL) {
     736                fprintf(stderr, "Error creating VT100 driver instance.\n");
     737                goto error;
     738        }
     739
     740        remcons->vt->enable_rgb = remcons->enable_rgb;
     741
     742        if (remcons->enable_ctl) {
     743                attrs.type = CHAR_ATTR_STYLE;
     744                attrs.val.style = STYLE_NORMAL;
     745                vt100_set_sgr(remcons->vt, attrs);
     746                vt100_cls(remcons->vt);
     747                vt100_set_pos(remcons->vt, 0, 0);
     748                vt100_set_button_reporting(remcons->vt, true);
     749        }
    298750
    299751        con_srvs_init(&user->srvs);
    300752        user->srvs.ops = &con_ops;
    301         user->srvs.sarg = user;
    302         user->srvs.abort_timeout = 1000;
     753        user->srvs.sarg = remcons;
     754        user->srvs.abort_timeout = 1000000;
    303755
    304756        telnet_user_add(user);
     
    309761                telnet_user_error(user, "Unable to register %s with loc: %s.",
    310762                    user->service_name, str_error(rc));
    311                 return;
     763                goto error;
    312764        }
    313765
     
    316768
    317769        fid_t spawn_fibril = fibril_create(spawn_task_fibril, user);
    318         assert(spawn_fibril);
     770        if (spawn_fibril == 0) {
     771                fprintf(stderr, "Failed creating fibril.\n");
     772                goto error;
     773        }
    319774        fibril_add_ready(spawn_fibril);
    320775
    321776        /* Wait for all clients to exit. */
    322         fibril_mutex_lock(&user->guard);
     777        fibril_mutex_lock(&user->recv_lock);
    323778        while (!user_can_be_destroyed_no_lock(user)) {
    324779                if (user->task_finished) {
    325                         user->conn = NULL;
    326780                        user->socket_closed = true;
    327781                        user->srvs.aborted = true;
    328                         continue;
    329782                } else if (user->socket_closed) {
    330783                        if (user->task_id != 0) {
     
    332785                        }
    333786                }
    334                 fibril_condvar_wait_timeout(&user->refcount_cv, &user->guard, 1000);
    335         }
    336         fibril_mutex_unlock(&user->guard);
     787                fibril_condvar_wait_timeout(&user->refcount_cv,
     788                    &user->recv_lock, 1000000);
     789        }
     790        fibril_mutex_unlock(&user->recv_lock);
    337791
    338792        rc = loc_service_unregister(remcons_srv, user->service_id);
     
    344798
    345799        telnet_user_log(user, "Destroying...");
     800
     801        if (remcons->enable_ctl) {
     802                /* Disable mouse tracking */
     803                vt100_set_button_reporting(remcons->vt, false);
     804
     805                /* Reset all character attributes and clear screen */
     806                vt100_sgr(remcons->vt, 0);
     807                vt100_cls(remcons->vt);
     808                vt100_set_pos(remcons->vt, 0, 0);
     809
     810                telnet_user_flush(user);
     811        }
     812
     813        tcp_conn_send_fin(user->conn);
     814        user->conn = NULL;
     815
    346816        telnet_user_destroy(user);
     817        vt100_destroy(remcons->vt);
     818        free(remcons);
     819        return;
     820error:
     821        if (user != NULL && user->service_id != 0)
     822                loc_service_unregister(remcons_srv, user->service_id);
     823        if (user != NULL)
     824                free(user);
     825        if (remcons != NULL && remcons->vt != NULL)
     826                vt100_destroy(remcons->vt);
     827        if (remcons != NULL)
     828                free(remcons);
     829}
     830
     831static void print_syntax(void)
     832{
     833        fprintf(stderr, "syntax: remcons [<options>]\n");
     834        fprintf(stderr, "\t--no-ctl      Disable all terminal control sequences\n");
     835        fprintf(stderr, "\t--no-rgb      Disable RGB colors\n");
     836        fprintf(stderr, "\t--port <port> Listening port (default: %u)\n",
     837            DEF_PORT);
    347838}
    348839
     
    353844        tcp_t *tcp;
    354845        inet_ep_t ep;
     846        uint16_t port;
     847        int i;
     848
     849        port = DEF_PORT;
     850
     851        i = 1;
     852        while (i < argc) {
     853                if (argv[i][0] == '-') {
     854                        if (str_cmp(argv[i], "--no-ctl") == 0) {
     855                                no_ctl = true;
     856                        } else if (str_cmp(argv[i], "--no-rgb") == 0) {
     857                                no_rgb = true;
     858                        } else if (str_cmp(argv[i], "--port") == 0) {
     859                                ++i;
     860                                if (i >= argc) {
     861                                        fprintf(stderr, "Option argument "
     862                                            "missing.\n");
     863                                        print_syntax();
     864                                        return EINVAL;
     865                                }
     866                                rc = str_uint16_t(argv[i], NULL, 10, true, &port);
     867                                if (rc != EOK) {
     868                                        fprintf(stderr, "Invalid port number "
     869                                            "'%s'.\n", argv[i]);
     870                                        print_syntax();
     871                                        return EINVAL;
     872                                }
     873                        } else {
     874                                fprintf(stderr, "Unknown option '%s'.\n",
     875                                    argv[i]);
     876                                print_syntax();
     877                                return EINVAL;
     878                        }
     879                } else {
     880                        fprintf(stderr, "Unexpected argument.\n");
     881                        print_syntax();
     882                        return EINVAL;
     883                }
     884
     885                ++i;
     886        }
    355887
    356888        async_set_fallback_port_handler(client_connection, NULL);
     
    368900
    369901        inet_ep_init(&ep);
    370         ep.port = 2223;
     902        ep.port = port;
    371903
    372904        rc = tcp_listener_create(tcp, &ep, &listen_cb, NULL, &conn_cb, NULL,
Note: See TracChangeset for help on using the changeset viewer.