Changeset 7bf29e5 in mainline for uspace/srv


Ignore:
Timestamp:
2025-01-09T11:29:38Z (9 months ago)
Author:
Miroslav Cimerman <mc@…>
Children:
a5c2960e
Parents:
bc3d695 (diff), 4e1221c (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.
Message:

Merge 'upstream/master' into helenraid-para

Location:
uspace/srv
Files:
7 added
3 deleted
44 edited
2 moved

Legend:

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

    rbc3d695 r7bf29e5  
    334334{
    335335        /* Got key press/release event */
    336         cons_event_t *event =
    337             (cons_event_t *) malloc(sizeof(cons_event_t));
     336        cons_qevent_t *event =
     337            (cons_qevent_t *) malloc(sizeof(cons_qevent_t));
    338338        if (event == NULL)
    339339                return;
    340340
    341         *event = *ev;
     341        event->ev = *ev;
    342342        link_initialize(&event->link);
    343343
     
    556556                if (pos < size) {
    557557                        link_t *link = prodcons_consume(&cons->input_pc);
    558                         cons_event_t *event = list_get_instance(link,
    559                             cons_event_t, link);
     558                        cons_qevent_t *qevent = list_get_instance(link,
     559                            cons_qevent_t, link);
     560                        cons_event_t *event = &qevent->ev;
    560561
    561562                        /* Accept key presses of printable chars only. */
     
    567568                        }
    568569
    569                         free(event);
     570                        free(qevent);
    570571                }
    571572        }
     
    703704        console_t *cons = srv_to_console(srv);
    704705        link_t *link = prodcons_consume(&cons->input_pc);
    705         cons_event_t *cevent = list_get_instance(link, cons_event_t, link);
    706 
    707         *event = *cevent;
    708         free(cevent);
     706        cons_qevent_t *qevent = list_get_instance(link, cons_qevent_t, link);
     707
     708        *event = qevent->ev;
     709        free(qevent);
    709710        return EOK;
    710711}
  • uspace/srv/hid/console/console.h

    rbc3d695 r7bf29e5  
    11/*
     2 * Copyright (c) 2024 Jiri Svoboda
    23 * Copyright (c) 2006 Josef Cejka
    34 * All rights reserved.
     
    3637#define CONSOLE_CONSOLE_H__
    3738
     39#include <adt/prodcons.h>
     40#include <io/cons_event.h>
     41
    3842#define CONSOLE_COUNT   11
     43
     44/** Console event queue entry */
     45typedef struct {
     46        /** Link to list of events */
     47        link_t link;
     48        /** Console event */
     49        cons_event_t ev;
     50} cons_qevent_t;
    3951
    4052#endif
  • uspace/srv/hid/display/display.c

    rbc3d695 r7bf29e5  
    105105        list_initialize(&disp->ddevs);
    106106        list_initialize(&disp->idevcfgs);
     107        list_initialize(&disp->ievents);
     108        fibril_condvar_initialize(&disp->ievent_cv);
    107109        list_initialize(&disp->seats);
    108110        list_initialize(&disp->windows);
     
    129131        assert(list_empty(&disp->ddevs));
    130132        assert(list_empty(&disp->idevcfgs));
     133        assert(list_empty(&disp->ievents));
    131134        assert(list_empty(&disp->seats));
    132135        assert(list_empty(&disp->windows));
     
    215218                }
    216219
     220                /*
     221                 * Load device configuration entry. If the device
     222                 * is not currently connected (ENOENT), skip it.
     223                 */
    217224                rc = ds_idevcfg_load(display, nidevcfg, &idevcfg);
    218                 if (rc != EOK)
     225                if (rc != EOK && rc != ENOENT)
    219226                        goto error;
    220227
  • uspace/srv/hid/display/idevcfg.c

    rbc3d695 r7bf29e5  
    9696        const char *sseat_id;
    9797        char *endptr;
    98         unsigned long svc_id;
     98        service_id_t svc_id;
    9999        unsigned long seat_id;
    100100        ds_seat_t *seat;
  • uspace/srv/hid/display/input.c

    rbc3d695 r7bf29e5  
    11/*
    2  * Copyright (c) 2022 Jiri Svoboda
     2 * Copyright (c) 2024 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    4040#include <str_error.h>
    4141#include "display.h"
     42#include "ievent.h"
    4243#include "input.h"
    4344#include "main.h"
     
    8788
    8889        ds_display_lock(disp);
    89         rc = ds_display_post_kbd_event(disp, &event);
     90        rc = ds_ievent_post_kbd(disp, &event);
    9091        ds_display_unlock(disp);
    9192        return rc;
     
    104105
    105106        ds_display_lock(disp);
    106         rc = ds_display_post_ptd_event(disp, &event);
     107        rc = ds_ievent_post_ptd(disp, &event);
    107108        ds_display_unlock(disp);
    108109        return rc;
     
    126127
    127128        ds_display_lock(disp);
    128         rc = ds_display_post_ptd_event(disp, &event);
     129        rc = ds_ievent_post_ptd(disp, &event);
    129130        ds_display_unlock(disp);
    130131        return rc;
     
    145146
    146147        ds_display_lock(disp);
    147         rc = ds_display_post_ptd_event(disp, &event);
     148        rc = ds_ievent_post_ptd(disp, &event);
    148149        ds_display_unlock(disp);
    149150        return rc;
     
    163164
    164165        ds_display_lock(disp);
    165         rc = ds_display_post_ptd_event(disp, &event);
     166        rc = ds_ievent_post_ptd(disp, &event);
    166167        ds_display_unlock(disp);
    167168        return rc;
  • uspace/srv/hid/display/main.c

    rbc3d695 r7bf29e5  
    5454#include "display.h"
    5555#include "dsops.h"
     56#include "ievent.h"
    5657#include "input.h"
    5758#include "main.h"
     
    156157        output->def_display = disp;
    157158        rc = ds_output_start_discovery(output);
     159        if (rc != EOK)
     160                goto error;
     161
     162        rc = ds_ievent_init(disp);
    158163        if (rc != EOK)
    159164                goto error;
     
    211216                ds_input_close(disp);
    212217#endif
     218        ds_ievent_fini(disp);
    213219        if (output != NULL)
    214220                ds_output_destroy(output);
  • uspace/srv/hid/display/meson.build

    rbc3d695 r7bf29e5  
    4141        'dsops.c',
    4242        'idevcfg.c',
     43        'ievent.c',
    4344        'input.c',
    4445        'main.c',
     
    5960        'display.c',
    6061        'idevcfg.c',
     62        'ievent.c',
    6163        'seat.c',
    6264        'window.c',
     
    6769        'test/cursor.c',
    6870        'test/display.c',
     71        'test/ievent.c',
    6972        'test/main.c',
    7073        'test/seat.c',
  • uspace/srv/hid/display/seat.c

    rbc3d695 r7bf29e5  
    492492        /* Focus window on button press */
    493493        if (event->type == PTD_PRESS && event->btn_num == 1) {
    494                 if (wnd != NULL && (wnd->flags & wndf_popup) == 0) {
     494                if (wnd != NULL && (wnd->flags & wndf_popup) == 0 &&
     495                    (wnd->flags & wndf_nofocus) == 0) {
    495496                        ds_seat_set_focus(seat, wnd);
    496497                }
  • uspace/srv/hid/display/test/main.c

    rbc3d695 r7bf29e5  
    11/*
    2  * Copyright (c) 2023 Jiri Svoboda
     2 * Copyright (c) 2024 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    3636PCUT_IMPORT(cursor);
    3737PCUT_IMPORT(display);
     38PCUT_IMPORT(ievent);
    3839PCUT_IMPORT(seat);
    3940PCUT_IMPORT(window);
  • uspace/srv/hid/display/types/display/display.h

    rbc3d695 r7bf29e5  
    11/*
    2  * Copyright (c) 2023 Jiri Svoboda
     2 * Copyright (c) 2024 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    3838
    3939#include <adt/list.h>
     40#include <fibril.h>
    4041#include <fibril_synch.h>
    4142#include <gfx/color.h>
     
    9394        list_t idevcfgs;
    9495
     96        /** Queue of input events */
     97        list_t ievents;
     98
     99        /** Input event processing fibril ID */
     100        fid_t ievent_fid;
     101        /** Input event condition variable */
     102        fibril_condvar_t ievent_cv;
     103        /** Signal input event fibril to quit */
     104        bool ievent_quit;
     105        /** Input event fibril terminated */
     106        bool ievent_done;
     107
    95108        /** Background color */
    96109        gfx_color_t *bg_color;
  • uspace/srv/hid/display/window.c

    rbc3d695 r7bf29e5  
    11/*
    2  * Copyright (c) 2023 Jiri Svoboda
     2 * Copyright (c) 2024 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    153153
    154154        /* Is this a popup window? */
    155         if ((params->flags & wndf_popup) != 0)
     155        if ((params->flags & wndf_popup) != 0) {
    156156                ds_seat_set_popup(seat, wnd);
    157         else
    158                 ds_seat_set_focus(seat, wnd);
     157        } else {
     158                if ((params->flags & wndf_nofocus) == 0)
     159                        ds_seat_set_focus(seat, wnd);
     160        }
    159161
    160162        /* Is this window a panel? */
  • uspace/srv/hid/output/ctl/serial.c

    rbc3d695 r7bf29e5  
    11/*
     2 * Copyright (c) 2024 Jiri Svoboda
    23 * Copyright (c) 2006 Ondrej Palkovsky
    34 * Copyright (c) 2008 Martin Decky
     
    3738#include <errno.h>
    3839#include <io/chargrid.h>
     40#include <vt/vt100.h>
    3941#include "../output.h"
    40 #include "../proto/vt100.h"
    4142#include "serial.h"
    4243
    4344#define SERIAL_COLS  80
    4445#define SERIAL_ROWS  24
     46
     47static serial_putuchar_t serial_putuchar_fn;
     48static serial_control_puts_t serial_control_puts_fn;
     49static serial_flush_t serial_flush_fn;
     50
     51static void serial_vt_putuchar(void *, char32_t);
     52static void serial_vt_control_puts(void *, const char *);
     53static void serial_vt_flush(void *);
     54
     55static vt100_cb_t serial_vt_cb = {
     56        .putuchar = serial_vt_putuchar,
     57        .control_puts = serial_vt_control_puts,
     58        .flush = serial_vt_flush
     59};
    4560
    4661/** Draw the character at the specified position.
     
    5267 *
    5368 */
    54 static void draw_char(vt100_state_t *state, charfield_t *field,
     69static void draw_char(vt100_t *state, charfield_t *field,
    5570    sysarg_t col, sysarg_t row)
    5671{
     
    6277static errno_t serial_yield(outdev_t *dev)
    6378{
    64         vt100_state_t *state = (vt100_state_t *) dev->data;
     79        vt100_t *state = (vt100_t *) dev->data;
    6580
    6681        return vt100_yield(state);
     
    6984static errno_t serial_claim(outdev_t *dev)
    7085{
    71         vt100_state_t *state = (vt100_state_t *) dev->data;
     86        vt100_t *state = (vt100_t *) dev->data;
    7287
    7388        return vt100_claim(state);
     
    7792    sysarg_t *rows)
    7893{
    79         vt100_state_t *state = (vt100_state_t *) dev->data;
     94        vt100_t *state = (vt100_t *) dev->data;
    8095
    8196        vt100_get_dimensions(state, cols, rows);
     
    8499static console_caps_t serial_get_caps(outdev_t *dev)
    85100{
    86         return (CONSOLE_CAP_STYLE | CONSOLE_CAP_INDEXED);
     101        return (CONSOLE_CAP_CURSORCTL | CONSOLE_CAP_STYLE |
     102            CONSOLE_CAP_INDEXED | CONSOLE_CAP_RGB);
    87103}
    88104
     
    90106    sysarg_t prev_row, sysarg_t col, sysarg_t row, bool visible)
    91107{
    92         vt100_state_t *state = (vt100_state_t *) dev->data;
     108        vt100_t *state = (vt100_t *) dev->data;
    93109
    94110        vt100_goto(state, col, row);
     
    98114static void serial_char_update(outdev_t *dev, sysarg_t col, sysarg_t row)
    99115{
    100         vt100_state_t *state = (vt100_state_t *) dev->data;
     116        vt100_t *state = (vt100_t *) dev->data;
    101117        charfield_t *field =
    102118            chargrid_charfield_at(dev->backbuf, col, row);
     
    107123static void serial_flush(outdev_t *dev)
    108124{
    109         vt100_state_t *state = (vt100_state_t *) dev->data;
     125        vt100_t *state = (vt100_t *) dev->data;
    110126
    111127        vt100_flush(state);
     
    122138};
    123139
    124 errno_t serial_init(vt100_putuchar_t putuchar_fn,
    125     vt100_control_puts_t control_puts_fn, vt100_flush_t flush_fn)
     140errno_t serial_init(serial_putuchar_t putuchar_fn,
     141    serial_control_puts_t control_puts_fn, serial_flush_t flush_fn)
    126142{
    127         vt100_state_t *state =
    128             vt100_state_create(SERIAL_COLS, SERIAL_ROWS, putuchar_fn,
    129             control_puts_fn, flush_fn);
    130         if (state == NULL)
     143        char_attrs_t attrs;
     144        vt100_t *vt100;
     145
     146        serial_putuchar_fn = putuchar_fn;
     147        serial_control_puts_fn = control_puts_fn;
     148        serial_flush_fn = flush_fn;
     149
     150        vt100 = vt100_create(NULL, SERIAL_COLS, SERIAL_ROWS, &serial_vt_cb);
     151        if (vt100 == NULL)
    131152                return ENOMEM;
     153        vt100->enable_rgb = true;
    132154
    133         outdev_t *dev = outdev_register(&serial_ops, state);
     155        vt100_cursor_visibility(vt100, false);
     156        attrs.type = CHAR_ATTR_STYLE;
     157        attrs.val.style = STYLE_NORMAL;
     158        vt100_set_attr(vt100, attrs);
     159        vt100_cls(vt100);
     160
     161        outdev_t *dev = outdev_register(&serial_ops, vt100);
    134162        if (dev == NULL) {
    135                 vt100_state_destroy(state);
     163                vt100_destroy(vt100);
    136164                return ENOMEM;
    137165        }
     
    140168}
    141169
     170static void serial_vt_putuchar(void *arg, char32_t c)
     171{
     172        (void)arg;
     173        serial_putuchar_fn(c);
     174}
     175
     176static void serial_vt_control_puts(void *arg, const char *str)
     177{
     178        (void)arg;
     179        serial_control_puts_fn(str);
     180}
     181
     182static void serial_vt_flush(void *arg)
     183{
     184        (void)arg;
     185        serial_flush_fn();
     186}
     187
    142188/** @}
    143189 */
  • uspace/srv/hid/output/ctl/serial.h

    rbc3d695 r7bf29e5  
    11/*
     2 * Copyright (c) 2024 Jiri Svoboda
    23 * Copyright (c) 2006 Ondrej Palkovsky
    34 * Copyright (c) 2008 Martin Decky
     
    3536#define OUTPUT_CTL_SERIAL_H_
    3637
    37 #include "../proto/vt100.h"
     38#include <vt/vt100.h>
    3839
    39 extern errno_t serial_init(vt100_putuchar_t, vt100_control_puts_t, vt100_flush_t);
     40typedef void (*serial_putuchar_t)(char32_t);
     41typedef void (*serial_control_puts_t)(const char *);
     42typedef void (*serial_flush_t)(void);
     43
     44extern errno_t serial_init(serial_putuchar_t, serial_control_puts_t,
     45    serial_flush_t);
    4046
    4147#endif
  • uspace/srv/hid/output/meson.build

    rbc3d695 r7bf29e5  
    11#
     2# Copyright (c) 2024 Jiri Svoboda
    23# Copyright (c) 2005 Martin Decky
    34# Copyright (c) 2007 Jakub Jermar
     
    2829#
    2930
    30 deps = [ 'codepage', 'console', 'drv', 'fbfont', 'pixconv', 'ddev', 'output' ]
     31deps = [ 'codepage', 'console', 'drv', 'fbfont', 'pixconv', 'ddev', 'output',
     32    'vt' ]
    3133src = files(
    3234        'ctl/serial.c',
     
    3436        'port/chardev.c',
    3537        'port/ddev.c',
    36         'proto/vt100.c',
    3738        'output.c',
    3839)
  • uspace/srv/hid/output/output.c

    rbc3d695 r7bf29e5  
    11/*
    2  * Copyright (c) 2023 Jiri Svoboda
     2 * Copyright (c) 2024 Jiri Svoboda
    33 * Copyright (c) 2011 Martin Decky
    44 * All rights reserved.
     
    4040#include <ipc/output.h>
    4141#include <config.h>
     42#include <vt/vt100.h>
    4243#include "port/ega.h"
    4344#include "port/chardev.h"
  • uspace/srv/hid/output/output.h

    rbc3d695 r7bf29e5  
    11/*
     2 * Copyright (c) 2024 Jiri Svoboda
    23 * Copyright (c) 2011 Martin Decky
    34 * All rights reserved.
     
    3435#define OUTPUT_OUTPUT_H_
    3536
     37#include <adt/list.h>
    3638#include <stdbool.h>
    3739#include <loc.h>
  • uspace/srv/hid/output/port/chardev.c

    rbc3d695 r7bf29e5  
    11/*
     2 * Copyright (c) 2024 Jiri Svoboda
    23 * Copyright (c) 2016 Jakub Jermar
    3  * Copyright (c) 2017 Jiri Svoboda
    44 * All rights reserved.
    55 *
  • uspace/srv/hid/output/port/ddev.c

    rbc3d695 r7bf29e5  
    11/*
    2  * Copyright (c) 2020 Jiri Svoboda
     2 * Copyright (c) 2024 Jiri Svoboda
    33 * Copyright (c) 2008 Martin Decky
    44 * Copyright (c) 2006 Jakub Vana
     
    198198static console_caps_t output_ddev_get_caps(outdev_t *dev)
    199199{
    200         return (CONSOLE_CAP_STYLE | CONSOLE_CAP_INDEXED | CONSOLE_CAP_RGB);
     200        return (CONSOLE_CAP_CURSORCTL | CONSOLE_CAP_STYLE |
     201            CONSOLE_CAP_INDEXED | CONSOLE_CAP_RGB);
    201202}
    202203
  • uspace/srv/hid/output/port/ega.c

    rbc3d695 r7bf29e5  
    143143static console_caps_t ega_get_caps(outdev_t *dev)
    144144{
    145         return (CONSOLE_CAP_STYLE | CONSOLE_CAP_INDEXED);
     145        return (CONSOLE_CAP_CURSORCTL | CONSOLE_CAP_STYLE |
     146            CONSOLE_CAP_INDEXED);
    146147}
    147148
  • uspace/srv/hid/remcons/meson.build

    rbc3d695 r7bf29e5  
    11#
    2 # Copyright (c) 2021 Jiri Svoboda
     2# Copyright (c) 2024 Jiri Svoboda
    33# Copyright (c) 2012 Vojtech Horky
    44# All rights reserved.
     
    2828#
    2929
    30 deps = [ 'inet', 'console' ]
     30deps = [ 'inet', 'console', 'vt' ]
    3131src = files('remcons.c', 'user.c')
  • uspace/srv/hid/remcons/remcons.c

    rbc3d695 r7bf29e5  
    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,
  • uspace/srv/hid/remcons/remcons.h

    rbc3d695 r7bf29e5  
    11/*
     2 * Copyright (c) 2024 Jiri Svoboda
    23 * Copyright (c) 2012 Vojtech Horky
    34 * All rights reserved.
     
    3637#define REMCONS_H_
    3738
     39#include <adt/list.h>
     40#include <io/cons_event.h>
     41#include <stdbool.h>
     42#include <vt/vt100.h>
     43#include "user.h"
     44
    3845#define NAME       "remcons"
    3946#define NAMESPACE  "term"
     47
     48/** Remote console */
     49typedef struct {
     50        telnet_user_t *user;    /**< telnet user */
     51        vt100_t *vt;            /**< virtual terminal driver */
     52        bool enable_ctl;        /**< enable escape control sequences */
     53        bool enable_rgb;        /**< enable RGB color setting */
     54        sysarg_t ucols;         /**< number of columns in user buffer */
     55        sysarg_t urows;         /**< number of rows in user buffer */
     56        charfield_t *ubuf;      /**< user buffer */
     57        bool curs_visible;      /**< cursor is visible */
     58
     59        /** List of remcons_event_t. */
     60        list_t in_events;
     61} remcons_t;
     62
     63/** Remote console event */
     64typedef struct {
     65        link_t link;            /**< link to list of events */
     66        cons_event_t cev;       /**< console event */
     67} remcons_event_t;
    4068
    4169#endif
  • uspace/srv/hid/remcons/telnet.h

    rbc3d695 r7bf29e5  
    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

    rbc3d695 r7bf29e5  
    11/*
     2 * Copyright (c) 2024 Jiri Svoboda
    23 * Copyright (c) 2012 Vojtech Horky
    34 * All rights reserved.
     
    3738#include <adt/prodcons.h>
    3839#include <errno.h>
     40#include <macros.h>
     41#include <mem.h>
    3942#include <str_error.h>
    4043#include <loc.h>
     
    4851#include <inttypes.h>
    4952#include <assert.h>
     53#include "remcons.h"
    5054#include "user.h"
    5155#include "telnet.h"
     
    5458static LIST_INITIALIZE(users);
    5559
     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
    5664/** Create new telnet user.
    5765 *
    5866 * @param conn Incoming connection.
     67 * @param cb Callback functions
     68 * @param arg Argument to callback functions
    5969 * @return New telnet user or NULL when out of memory.
    6070 */
    61 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)
    6272{
    6373        static int telnet_user_id_counter = 0;
     
    6878        }
    6979
     80        user->cb = cb;
     81        user->arg = arg;
    7082        user->id = ++telnet_user_id_counter;
    7183
    72         int rc = asprintf(&user->service_name, "%s/telnet%d", NAMESPACE, user->id);
     84        int rc = asprintf(&user->service_name, "%s/telnet%u.%d", NAMESPACE,
     85            (unsigned)task_get_id(), user->id);
    7386        if (rc < 0) {
    7487                free(user);
     
    7891        user->conn = conn;
    7992        user->service_id = (service_id_t) -1;
    80         prodcons_initialize(&user->in_events);
    8193        link_initialize(&user->link);
    8294        user->socket_buffer_len = 0;
    8395        user->socket_buffer_pos = 0;
     96        user->send_buf_used = 0;
    8497
    8598        fibril_condvar_initialize(&user->refcount_cv);
    86         fibril_mutex_initialize(&user->guard);
     99        fibril_mutex_initialize(&user->send_lock);
     100        fibril_mutex_initialize(&user->recv_lock);
    87101        user->task_finished = false;
    88102        user->socket_closed = false;
     
    90104
    91105        user->cursor_x = 0;
     106        user->cursor_y = 0;
    92107
    93108        return user;
     
    137152
    138153        telnet_user_t *tmp = user;
    139         fibril_mutex_lock(&tmp->guard);
     154        fibril_mutex_lock(&tmp->recv_lock);
    140155        user->locsrv_connection_count++;
    141156
     
    149164        }
    150165
    151         fibril_mutex_unlock(&tmp->guard);
     166        fibril_mutex_unlock(&tmp->recv_lock);
    152167
    153168        fibril_mutex_unlock(&users_guard);
     
    162177void telnet_user_notify_client_disconnected(telnet_user_t *user)
    163178{
    164         fibril_mutex_lock(&user->guard);
     179        fibril_mutex_lock(&user->recv_lock);
    165180        assert(user->locsrv_connection_count > 0);
    166181        user->locsrv_connection_count--;
    167182        fibril_condvar_signal(&user->refcount_cv);
    168         fibril_mutex_unlock(&user->guard);
     183        fibril_mutex_unlock(&user->recv_lock);
    169184}
    170185
     
    175190bool telnet_user_is_zombie(telnet_user_t *user)
    176191{
    177         fibril_mutex_lock(&user->guard);
     192        fibril_mutex_lock(&user->recv_lock);
    178193        bool zombie = user->socket_closed || user->task_finished;
    179         fibril_mutex_unlock(&user->guard);
     194        fibril_mutex_unlock(&user->recv_lock);
    180195
    181196        return zombie;
    182197}
    183198
    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  */
    188 static errno_t telnet_user_recv_next_byte_no_lock(telnet_user_t *user, char *byte)
    189 {
     199static 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 */
     227static errno_t telnet_user_recv_next_byte_locked(telnet_user_t *user,
     228    uint8_t *byte)
     229{
     230        errno_t rc;
     231
    190232        /* No more buffered data? */
    191233        if (user->socket_buffer_len <= user->socket_buffer_pos) {
    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);
     234                rc = telnet_user_fill_recv_buf(user);
    197235                if (rc != EOK)
    198236                        return rc;
    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 
     237        }
     238
     239        *byte = (uint8_t)user->socket_buffer[user->socket_buffer_pos++];
    212240        return EOK;
    213241}
    214242
    215 /** Creates new keyboard event from given char.
    216  *
    217  * @param type Event type (press / release).
    218  * @param c Pressed character.
    219  */
    220 static 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).
     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 */
     248static bool telnet_user_byte_avail(telnet_user_t *user)
     249{
     250        return user->socket_buffer_len > user->socket_buffer_pos;
     251}
     252
     253static 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 */
     270static 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 */
     283static 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 */
     334static 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 */
     352static 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.
    251366 *
    252367 * @param user Telnet user structure.
     
    257372    telnet_cmd_t option_code, telnet_cmd_t cmd)
    258373{
     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
    259383        if (option_code != 0) {
    260384                telnet_user_log(user, "Ignoring telnet command %u %u %u.",
     
    266390}
    267391
    268 /** Get next keyboard event.
     392/** Receive data from telnet connection.
    269393 *
    270394 * @param user Telnet user.
    271  * @param event Where to store the keyboard event.
    272  * @return Error code.
    273  */
    274 errno_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;
     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 */
     400errno_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;
    279411                bool inside_telnet_command = false;
    280412
     
    282414
    283415                /* Skip zeros, bail-out on error. */
    284                 while (next_byte == 0) {
    285                         errno_t rc = telnet_user_recv_next_byte_no_lock(user, &next_byte);
     416                do {
     417                        errno_t rc = telnet_user_recv_next_byte_locked(user,
     418                            &next_byte);
    286419                        if (rc != EOK) {
    287                                 fibril_mutex_unlock(&user->guard);
     420                                fibril_mutex_unlock(&user->recv_lock);
    288421                                return rc;
    289422                        }
    290                         uint8_t byte = (uint8_t) next_byte;
     423                        uint8_t byte = next_byte;
    291424
    292425                        /* Skip telnet commands. */
     
    294427                                inside_telnet_command = false;
    295428                                next_byte = 0;
    296                                 if (TELNET_IS_OPTION_CODE(byte)) {
     429                                if (TELNET_IS_OPTION_CODE(byte) ||
     430                                    byte == TELNET_SB) {
    297431                                        telnet_option_code = byte;
    298432                                        inside_telnet_command = true;
     
    306440                                next_byte = 0;
    307441                        }
    308                 }
     442                } while (next_byte == 0 && telnet_user_byte_avail(user));
    309443
    310444                /* CR-LF conversions. */
     
    313447                }
    314448
    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);
     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
     460static 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        }
    331486
    332487        return EOK;
     
    339494 * @param size Size of @p data buffer in bytes.
    340495 */
    341 static errno_t telnet_user_send_data_no_lock(telnet_user_t *user, uint8_t *data, size_t size)
     496static errno_t telnet_user_send_data_locked(telnet_user_t *user,
     497    const char *data, size_t size)
    342498{
    343499        uint8_t *converted = malloc(3 * size + 1);
     
    351507                        converted[converted_size++] = 10;
    352508                        user->cursor_x = 0;
     509                        if (user->cursor_y < (int)user->rows - 1)
     510                                ++user->cursor_y;
    353511                } else {
    354512                        converted[converted_size++] = data[i];
     
    361519        }
    362520
    363         errno_t rc = tcp_conn_send(user->conn, converted, converted_size);
     521        errno_t rc = telnet_user_send_raw_locked(user, converted,
     522            converted_size);
    364523        free(converted);
    365524
     
    373532 * @param size Size of @p data buffer in bytes.
    374533 */
    375 errno_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 
     534errno_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 */
     552errno_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
     564static 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
     576errno_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);
    383583        return rc;
    384584}
     
    393593void telnet_user_update_cursor_x(telnet_user_t *user, int new_x)
    394594{
    395         fibril_mutex_lock(&user->guard);
     595        fibril_mutex_lock(&user->send_lock);
    396596        if (user->cursor_x - 1 == new_x) {
    397                 uint8_t data = '\b';
     597                char data = '\b';
    398598                /* Ignore errors. */
    399                 telnet_user_send_data_no_lock(user, &data, 1);
     599                telnet_user_send_data_locked(user, &data, 1);
    400600        }
    401601        user->cursor_x = new_x;
    402         fibril_mutex_unlock(&user->guard);
    403 
     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 */
     612void 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;
    404620}
    405621
  • uspace/srv/hid/remcons/user.h

    rbc3d695 r7bf29e5  
    11/*
     2 * Copyright (c) 2024 Jiri Svoboda
    23 * Copyright (c) 2012 Vojtech Horky
    34 * All rights reserved.
     
    3637#define TELNET_USER_H_
    3738
    38 #include <adt/prodcons.h>
    3939#include <fibril_synch.h>
    4040#include <inet/tcp.h>
    4141#include <inttypes.h>
    4242#include <io/con_srv.h>
    43 #include "remcons.h"
    4443
    4544#define BUFFER_SIZE 32
     45#define SEND_BUF_SIZE 512
     46
     47/** Telnet callbacks */
     48typedef struct {
     49        void (*ws_update)(void *, unsigned, unsigned);
     50} telnet_cb_t;
    4651
    4752/** Representation of a connected (human) user. */
    4853typedef struct {
    49         /** Mutex guarding the whole structure. */
    50         fibril_mutex_t guard;
     54        /** Synchronize send operations */
     55        fibril_mutex_t send_lock;
     56        /** Synchronize receive operations */
     57        fibril_mutex_t recv_lock;
     58        /** Callback functions */
     59        telnet_cb_t *cb;
     60        /** Argument to callback functions */
     61        void *arg;
    5162
    5263        /** Internal id, used for creating locfs entries. */
     
    6172        con_srvs_t srvs;
    6273
    63         /** Producer-consumer of kbd_event_t. */
    64         prodcons_t in_events;
    6574        link_t link;
    6675        char socket_buffer[BUFFER_SIZE];
    6776        size_t socket_buffer_len;
    6877        size_t socket_buffer_pos;
     78        char send_buf[SEND_BUF_SIZE];
     79        size_t send_buf_used;
    6980
    7081        /** Task id of the launched application. */
     
    7990        /** X position of the cursor. */
    8091        int cursor_x;
     92        /** Y position of the cursor. */
     93        int cursor_y;
     94        /** Total number of columns */
     95        unsigned cols;
     96        /** Total number of rows */
     97        unsigned rows;
    8198} telnet_user_t;
    8299
    83 extern telnet_user_t *telnet_user_create(tcp_conn_t *);
     100extern telnet_user_t *telnet_user_create(tcp_conn_t *, telnet_cb_t *, void *);
    84101extern void telnet_user_add(telnet_user_t *);
    85102extern void telnet_user_destroy(telnet_user_t *);
     
    88105extern void telnet_user_notify_client_disconnected(telnet_user_t *);
    89106extern errno_t telnet_user_get_next_keyboard_event(telnet_user_t *, kbd_event_t *);
    90 extern errno_t telnet_user_send_data(telnet_user_t *, uint8_t *, size_t);
     107extern errno_t telnet_user_send_data(telnet_user_t *, const char *, size_t);
     108extern errno_t telnet_user_send_raw(telnet_user_t *, const char *, size_t);
     109extern errno_t telnet_user_flush(telnet_user_t *);
     110extern errno_t telnet_user_recv(telnet_user_t *, void *, size_t, size_t *);
    91111extern void telnet_user_update_cursor_x(telnet_user_t *, int);
     112extern void telnet_user_resize(telnet_user_t *, unsigned, unsigned);
    92113
    93114/** Print informational message about connected user. */
  • uspace/srv/meson.build

    rbc3d695 r7bf29e5  
    11#
     2# Copyright (c) 2024 Jiri Svoboda
    23# Copyright (c) 2019 Jiří Zárevúcky
    34# All rights reserved.
     
    6263        'net/inetsrv',
    6364        'net/loopip',
    64         'net/nconfsrv',
    6565        'net/slip',
    6666        'net/tcp',
    6767        'net/udp',
    6868        'ns',
     69        'system',
    6970        'taskmon',
    7071        'test/chardev-test',
  • uspace/srv/net/dhcp/dhcp.c

    rbc3d695 r7bf29e5  
    11/*
    2  * Copyright (c) 2022 Jiri Svoboda
     2 * Copyright (c) 2024 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    7171static list_t dhcp_links;
    7272
     73bool inetcfg_inited = false;
     74
    7375static void dhcpsrv_discover_timeout(void *);
    7476static void dhcpsrv_request_timeout(void *);
     
    468470        log_msg(LOG_DEFAULT, LVL_DEBUG, "dhcpsrv_link_add(%zu)", link_id);
    469471
     472        if (!inetcfg_inited) {
     473                rc = inetcfg_init();
     474                if (rc != EOK) {
     475                        log_msg(LOG_DEFAULT, LVL_ERROR, "Error contacting "
     476                            "inet configuration service.\n");
     477                        return EIO;
     478                }
     479
     480                inetcfg_inited = true;
     481        }
     482
    470483        if (dhcpsrv_link_find(link_id) != NULL) {
    471484                log_msg(LOG_DEFAULT, LVL_NOTE, "Link %zu already added",
  • uspace/srv/net/dhcp/main.c

    rbc3d695 r7bf29e5  
    11/*
    2  * Copyright (c) 2023 Jiri Svoboda
     2 * Copyright (c) 2024 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    3838#include <str_error.h>
    3939#include <io/log.h>
    40 #include <inet/inetcfg.h>
    4140#include <ipc/dhcp.h>
    4241#include <ipc/services.h>
     
    6059
    6160        dhcpsrv_links_init();
    62 
    63         rc = inetcfg_init();
    64         if (rc != EOK) {
    65                 log_msg(LOG_DEFAULT, LVL_ERROR, "Error contacting inet configuration service.\n");
    66                 return EIO;
    67         }
    6861
    6962        async_set_fallback_port_handler(dhcp_client_conn, NULL);
  • uspace/srv/net/doc/doxygroups.h

    rbc3d695 r7bf29e5  
    2020/**    @addtogroup slip slip
    2121 *     @brief SLIP service
    22  *     @ingroup net
    23  */
    24 
    25 /**    @addtogroup nconfsrv nconfsrv
    26  *     @brief Network configuration service
    2722 *     @ingroup net
    2823 */
  • uspace/srv/net/inetsrv/addrobj.c

    rbc3d695 r7bf29e5  
    11/*
    2  * Copyright (c) 2021 Jiri Svoboda
     2 * Copyright (c) 2024 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    4141#include <io/log.h>
    4242#include <ipc/loc.h>
     43#include <sif.h>
     44#include <stdio.h>
    4345#include <stdlib.h>
    4446#include <str.h>
     
    211213}
    212214
     215/** Count number of non-temporary address objects configured for link.
     216 *
     217 * @param ilink Inet link
     218 * @return Number of address objects configured for this link
     219 */
     220unsigned inet_addrobj_cnt_by_link(inet_link_t *ilink)
     221{
     222        unsigned cnt;
     223
     224        log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_addrobj_cnt_by_link()");
     225
     226        fibril_mutex_lock(&addr_list_lock);
     227
     228        cnt = 0;
     229        list_foreach(addr_list, addr_list, inet_addrobj_t, naddr) {
     230                if (naddr->ilink == ilink && naddr->temp == false)
     231                        ++cnt;
     232        }
     233
     234        fibril_mutex_unlock(&addr_list_lock);
     235        return cnt;
     236}
     237
    213238/** Send datagram from address object */
    214239errno_t inet_addrobj_send_dgram(inet_addrobj_t *addr, inet_addr_t *ldest,
     
    282307}
    283308
     309/** Load address object from SIF node.
     310 *
     311 * @param anode SIF node to load address object from
     312 * @return EOK on success or an error code
     313 */
     314static errno_t inet_addrobj_load(sif_node_t *anode)
     315{
     316        errno_t rc;
     317        const char *sid;
     318        const char *snaddr;
     319        const char *slink;
     320        const char *name;
     321        char *endptr;
     322        int id;
     323        inet_naddr_t naddr;
     324        inet_addrobj_t *addr;
     325        inet_link_t *link;
     326
     327        log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_addrobj_load()");
     328
     329        sid = sif_node_get_attr(anode, "id");
     330        if (sid == NULL)
     331                return EIO;
     332
     333        snaddr = sif_node_get_attr(anode, "naddr");
     334        if (snaddr == NULL)
     335                return EIO;
     336
     337        slink = sif_node_get_attr(anode, "link");
     338        if (slink == NULL)
     339                return EIO;
     340
     341        name = sif_node_get_attr(anode, "name");
     342        if (name == NULL)
     343                return EIO;
     344
     345        log_msg(LOG_DEFAULT, LVL_NOTE, "inet_addrobj_load(): id='%s' "
     346            "naddr='%s' link='%s' name='%s'", sid, snaddr, slink, name);
     347
     348        id = strtoul(sid, &endptr, 10);
     349        if (*endptr != '\0')
     350                return EIO;
     351
     352        rc = inet_naddr_parse(snaddr, &naddr, NULL);
     353        if (rc != EOK)
     354                return EIO;
     355
     356        link = inet_link_get_by_svc_name(slink);
     357        if (link == NULL) {
     358                log_msg(LOG_DEFAULT, LVL_ERROR, "Link '%s' not found",
     359                    slink);
     360                return EIO;
     361        }
     362
     363        addr = inet_addrobj_new();
     364        if (addr == NULL)
     365                return ENOMEM;
     366
     367        addr->id = id;
     368        addr->naddr = naddr;
     369        addr->ilink = link;
     370        addr->name = str_dup(name);
     371
     372        if (addr->name == NULL) {
     373                inet_addrobj_delete(addr);
     374                return ENOMEM;
     375        }
     376
     377        inet_addrobj_add(addr);
     378        return EOK;
     379}
     380
     381/** Load address objects from SIF node.
     382 *
     383 * @param naddrs SIF node to load address objects from
     384 * @return EOK on success or an error code
     385 */
     386errno_t inet_addrobjs_load(sif_node_t *naddrs)
     387{
     388        sif_node_t *naddr;
     389        const char *ntype;
     390        errno_t rc;
     391
     392        naddr = sif_node_first_child(naddrs);
     393        while (naddr != NULL) {
     394                ntype = sif_node_get_type(naddr);
     395                if (str_cmp(ntype, "address") != 0) {
     396                        rc = EIO;
     397                        goto error;
     398                }
     399
     400                rc = inet_addrobj_load(naddr);
     401                if (rc != EOK)
     402                        goto error;
     403
     404                naddr = sif_node_next_child(naddr);
     405        }
     406
     407        return EOK;
     408error:
     409        return rc;
     410
     411}
     412
     413/** Save address object to SIF node.
     414 *
     415 * @param addr Address object
     416 * @param naddr SIF node to save addres to
     417 * @return EOK on success or an error code
     418 */
     419static errno_t inet_addrobj_save(inet_addrobj_t *addr, sif_node_t *naddr)
     420{
     421        char *str = NULL;
     422        errno_t rc;
     423        int rv;
     424
     425        log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_addrobj_save(%p, %p)",
     426            addr, naddr);
     427
     428        /* id */
     429
     430        rv = asprintf(&str, "%zu", addr->id);
     431        if (rv < 0) {
     432                str = NULL;
     433                rc = ENOMEM;
     434                goto error;
     435        }
     436
     437        rc = sif_node_set_attr(naddr, "id", str);
     438        if (rc != EOK)
     439                goto error;
     440
     441        free(str);
     442        str = NULL;
     443
     444        /* dest */
     445
     446        rc = inet_naddr_format(&addr->naddr, &str);
     447        if (rc != EOK)
     448                goto error;
     449
     450        rc = sif_node_set_attr(naddr, "naddr", str);
     451        if (rc != EOK)
     452                goto error;
     453
     454        free(str);
     455        str = NULL;
     456
     457        /* link */
     458
     459        rc = sif_node_set_attr(naddr, "link", addr->ilink->svc_name);
     460        if (rc != EOK)
     461                goto error;
     462
     463        /* name */
     464
     465        rc = sif_node_set_attr(naddr, "name", addr->name);
     466        if (rc != EOK)
     467                goto error;
     468
     469        free(str);
     470
     471        return rc;
     472error:
     473        if (str != NULL)
     474                free(str);
     475        return rc;
     476}
     477
     478/** Save address objects to SIF node.
     479 *
     480 * @param cnode SIF node to save address objects to
     481 * @return EOK on success or an error code
     482 */
     483errno_t inet_addrobjs_save(sif_node_t *cnode)
     484{
     485        sif_node_t *naddr;
     486        errno_t rc;
     487
     488        log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_addrobjs_save()");
     489
     490        fibril_mutex_lock(&addr_list_lock);
     491
     492        list_foreach(addr_list, addr_list, inet_addrobj_t, addr) {
     493                if (addr->temp == false) {
     494                        rc = sif_node_append_child(cnode, "address", &naddr);
     495                        if (rc != EOK)
     496                                goto error;
     497
     498                        rc = inet_addrobj_save(addr, naddr);
     499                        if (rc != EOK)
     500                                goto error;
     501                }
     502        }
     503
     504        fibril_mutex_unlock(&addr_list_lock);
     505        return EOK;
     506error:
     507        fibril_mutex_unlock(&addr_list_lock);
     508        return rc;
     509}
     510
    284511/** @}
    285512 */
  • uspace/srv/net/inetsrv/addrobj.h

    rbc3d695 r7bf29e5  
    11/*
    2  * Copyright (c) 2012 Jiri Svoboda
     2 * Copyright (c) 2024 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    3838#define INET_ADDROBJ_H_
    3939
     40#include <sif.h>
    4041#include <stddef.h>
    4142#include <stdint.h>
     
    5657extern inet_addrobj_t *inet_addrobj_find_by_name(const char *, inet_link_t *);
    5758extern inet_addrobj_t *inet_addrobj_get_by_id(sysarg_t);
     59extern unsigned inet_addrobj_cnt_by_link(inet_link_t *);
    5860extern errno_t inet_addrobj_send_dgram(inet_addrobj_t *, inet_addr_t *,
    5961    inet_dgram_t *, uint8_t, uint8_t, int);
    6062extern errno_t inet_addrobj_get_id_list(sysarg_t **, size_t *);
     63extern errno_t inet_addrobjs_load(sif_node_t *);
     64extern errno_t inet_addrobjs_save(sif_node_t *);
    6165
    6266#endif
  • uspace/srv/net/inetsrv/inet_link.c

    rbc3d695 r7bf29e5  
    11/*
    2  * Copyright (c) 2021 Jiri Svoboda
     2 * Copyright (c) 2024 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    3737#include <errno.h>
    3838#include <fibril_synch.h>
     39#include <inet/dhcp.h>
    3940#include <inet/eth_addr.h>
    4041#include <inet/iplink.h>
     
    164165}
    165166
    166 errno_t inet_link_open(service_id_t sid)
     167/** Open new IP link while inet_links_lock is held.
     168 *
     169 * @param sid IP link service ID
     170 * @return EOK on success or an error code
     171 */
     172static errno_t inet_link_open_locked(service_id_t sid)
    167173{
    168174        inet_link_t *ilink;
     
    170176        errno_t rc;
    171177
    172         log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_link_open()");
     178        assert(fibril_mutex_is_locked(&inet_links_lock));
     179
     180        log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_link_open_locked()");
    173181        ilink = inet_link_new();
    174182        if (ilink == NULL)
     
    213221        log_msg(LOG_DEFAULT, LVL_DEBUG, "Opened IP link '%s'", ilink->svc_name);
    214222
    215         fibril_mutex_lock(&inet_links_lock);
    216 
    217223        if (inet_link_get_by_id_locked(sid) != NULL) {
    218                 fibril_mutex_unlock(&inet_links_lock);
    219224                log_msg(LOG_DEFAULT, LVL_DEBUG, "Link %zu already open",
    220225                    sid);
     
    224229
    225230        list_append(&ilink->link_list, &inet_links);
    226         fibril_mutex_unlock(&inet_links_lock);
    227231
    228232        inet_addrobj_t *addr = NULL;
     
    239243                addr->ilink = ilink;
    240244                addr->name = str_dup("v4a");
     245                addr->temp = true;
    241246
    242247                rc = inet_addrobj_add(addr);
     
    275280                addr6->ilink = ilink;
    276281                addr6->name = str_dup("v6a");
     282                addr6->temp = true;
    277283
    278284                rc = inet_addrobj_add(addr6);
     
    303309}
    304310
     311/** Open new IP link..
     312 *
     313 * @param sid IP link service ID
     314 * @return EOK on success or an error code
     315 */
     316errno_t inet_link_open(service_id_t sid)
     317{
     318        errno_t rc;
     319
     320        fibril_mutex_lock(&inet_links_lock);
     321        rc = inet_link_open_locked(sid);
     322        fibril_mutex_unlock(&inet_links_lock);
     323
     324        return rc;
     325}
     326
    305327/** Send IPv4 datagram over Internet link
    306328 *
     
    476498}
    477499
     500/** Find link by service name while inet_links_lock is held.
     501 *
     502 * @param svc_name Service name
     503 * @return Link or @c NULL if not found
     504 */
     505static inet_link_t *inet_link_get_by_svc_name_locked(const char *svc_name)
     506{
     507        assert(fibril_mutex_is_locked(&inet_links_lock));
     508
     509        list_foreach(inet_links, link_list, inet_link_t, ilink) {
     510                if (str_cmp(ilink->svc_name, svc_name) == 0)
     511                        return ilink;
     512        }
     513
     514        return NULL;
     515}
     516
     517/** Find link by service name.
     518 *
     519 * @param svc_name Service name
     520 * @return Link or @c NULL if not found
     521 */
     522inet_link_t *inet_link_get_by_svc_name(const char *svc_name)
     523{
     524        inet_link_t *ilink;
     525
     526        fibril_mutex_lock(&inet_links_lock);
     527        ilink = inet_link_get_by_svc_name_locked(svc_name);
     528        fibril_mutex_unlock(&inet_links_lock);
     529
     530        return ilink;
     531}
     532
    478533/** Get IDs of all links. */
    479534errno_t inet_link_get_id_list(sysarg_t **rid_list, size_t *rcount)
     
    504559}
    505560
     561/** Check for new IP links.
     562 *
     563 * @return EOK on success or an error code
     564 */
     565static errno_t inet_link_check_new(void)
     566{
     567        bool already_known;
     568        category_id_t iplink_cat;
     569        service_id_t *svcs;
     570        inet_link_cfg_info_t info;
     571        size_t count, i;
     572        errno_t rc;
     573
     574        fibril_mutex_lock(&inet_links_lock);
     575
     576        rc = loc_category_get_id("iplink", &iplink_cat, IPC_FLAG_BLOCKING);
     577        if (rc != EOK) {
     578                log_msg(LOG_DEFAULT, LVL_ERROR, "Failed resolving category "
     579                    "'iplink'.");
     580                fibril_mutex_unlock(&inet_links_lock);
     581                return ENOENT;
     582        }
     583
     584        rc = loc_category_get_svcs(iplink_cat, &svcs, &count);
     585        if (rc != EOK) {
     586                log_msg(LOG_DEFAULT, LVL_ERROR, "Failed getting list of IP "
     587                    "links.");
     588                fibril_mutex_unlock(&inet_links_lock);
     589                return EIO;
     590        }
     591
     592        for (i = 0; i < count; i++) {
     593                already_known = false;
     594
     595                list_foreach(inet_links, link_list, inet_link_t, ilink) {
     596                        if (ilink->svc_id == svcs[i]) {
     597                                already_known = true;
     598                                break;
     599                        }
     600                }
     601
     602                if (!already_known) {
     603                        log_msg(LOG_DEFAULT, LVL_NOTE, "Found IP link '%lu'",
     604                            (unsigned long) svcs[i]);
     605                        rc = inet_link_open_locked(svcs[i]);
     606                        if (rc != EOK) {
     607                                log_msg(LOG_DEFAULT, LVL_ERROR, "Could not "
     608                                    "add IP link.");
     609                        }
     610                } else {
     611                        /* Clear so it won't be autoconfigured below */
     612                        svcs[i] = 0;
     613                }
     614        }
     615
     616        fibril_mutex_unlock(&inet_links_lock);
     617
     618        /*
     619         * Auto-configure new links. Note that newly discovered links
     620         * cannot have any configured address objects, because we only
     621         * retain configuration for present links.
     622         */
     623        for (i = 0; i < count; i++) {
     624                if (svcs[i] != 0) {
     625                        info.svc_id = svcs[i];
     626                        rc = loc_service_get_name(info.svc_id, &info.svc_name);
     627                        if (rc != EOK) {
     628                                log_msg(LOG_DEFAULT, LVL_ERROR, "Failed "
     629                                    "getting service name.");
     630                                return rc;
     631                        }
     632
     633                        inet_link_autoconf_link(&info);
     634                        free(info.svc_name);
     635                        info.svc_name = NULL;
     636                }
     637        }
     638
     639        return EOK;
     640}
     641
     642/** IP link category change callback.
     643 *
     644 * @param arg Not used
     645 */
     646static void inet_link_cat_change_cb(void *arg)
     647{
     648        (void) inet_link_check_new();
     649}
     650
     651/** Start IP link discovery.
     652 *
     653 * @return EOK on success or an error code
     654 */
     655errno_t inet_link_discovery_start(void)
     656{
     657        errno_t rc;
     658
     659        rc = loc_register_cat_change_cb(inet_link_cat_change_cb, NULL);
     660        if (rc != EOK) {
     661                log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering callback "
     662                    "for IP link discovery: %s.", str_error(rc));
     663                return rc;
     664        }
     665
     666        return inet_link_check_new();
     667}
     668
     669/** Start DHCP autoconfiguration on IP link.
     670 *
     671 * @param info Link information
     672 */
     673void inet_link_autoconf_link(inet_link_cfg_info_t *info)
     674{
     675        errno_t rc;
     676
     677        log_msg(LOG_DEFAULT, LVL_NOTE, "inet_link_autoconf_link");
     678
     679        if (str_lcmp(info->svc_name, "net/eth", str_length("net/eth")) == 0) {
     680                log_msg(LOG_DEFAULT, LVL_NOTE, "inet_link_autoconf_link : dhcp link add for link '%s' (%u)",
     681                    info->svc_name, (unsigned)info->svc_id);
     682                rc = dhcp_link_add(info->svc_id);
     683                log_msg(LOG_DEFAULT, LVL_NOTE, "inet_link_autoconf_link : dhcp link add for link '%s' (%u) DONE",
     684                    info->svc_name, (unsigned)info->svc_id);
     685                if (rc != EOK) {
     686                        log_msg(LOG_DEFAULT, LVL_WARN, "Failed configuring "
     687                            "DHCP on  link '%s'.\n", info->svc_name);
     688                }
     689        }
     690}
     691
     692/** Start DHCP autoconfiguration on IP links. */
     693errno_t inet_link_autoconf(void)
     694{
     695        inet_link_cfg_info_t *link_info;
     696        size_t link_cnt;
     697        size_t acnt;
     698        size_t i;
     699        errno_t rc;
     700
     701        log_msg(LOG_DEFAULT, LVL_NOTE, "inet_link_autoconf : initialize DHCP");
     702        rc = dhcp_init();
     703        if (rc != EOK) {
     704                log_msg(LOG_DEFAULT, LVL_WARN, "Failed initializing DHCP "
     705                    "service.");
     706                return rc;
     707        }
     708
     709        log_msg(LOG_DEFAULT, LVL_NOTE, "inet_link_autoconf : initialize DHCP done");
     710
     711        fibril_mutex_lock(&inet_links_lock);
     712        link_cnt = list_count(&inet_links);
     713
     714        link_info = calloc(link_cnt, sizeof(inet_link_cfg_info_t));
     715        if (link_info == NULL) {
     716                fibril_mutex_unlock(&inet_links_lock);
     717                return ENOMEM;
     718        }
     719
     720        i = 0;
     721        list_foreach(inet_links, link_list, inet_link_t, ilink) {
     722                assert(i < link_cnt);
     723
     724                acnt = inet_addrobj_cnt_by_link(ilink);
     725                if (acnt != 0) {
     726                        /*
     727                         * No autoconfiguration if link has configured
     728                         * addresses.
     729                         */
     730                        continue;
     731                }
     732
     733                link_info[i].svc_id = ilink->svc_id;
     734                link_info[i].svc_name = str_dup(ilink->svc_name);
     735                if (link_info[i].svc_name == NULL) {
     736                        fibril_mutex_unlock(&inet_links_lock);
     737                        goto error;
     738                }
     739
     740                ++i;
     741        }
     742
     743        fibril_mutex_unlock(&inet_links_lock);
     744
     745        /* Update link_cnt to include only links slated for autoconfig. */
     746        link_cnt = i;
     747
     748        log_msg(LOG_DEFAULT, LVL_NOTE, "inet_link_autoconf : autoconf links...");
     749
     750        for (i = 0; i < link_cnt; i++)
     751                inet_link_autoconf_link(&link_info[i]);
     752
     753        for (i = 0; i < link_cnt; i++) {
     754                if (link_info[i].svc_name != NULL)
     755                        free(link_info[i].svc_name);
     756        }
     757
     758        log_msg(LOG_DEFAULT, LVL_NOTE, "inet_link_autoconf : autoconf links done");
     759        return EOK;
     760error:
     761        for (i = 0; i < link_cnt; i++) {
     762                if (link_info[i].svc_name != NULL)
     763                        free(link_info[i].svc_name);
     764        }
     765        free(link_info);
     766        return ENOMEM;
     767}
     768
    506769/** @}
    507770 */
  • uspace/srv/net/inetsrv/inet_link.h

    rbc3d695 r7bf29e5  
    11/*
    2  * Copyright (c) 2021 Jiri Svoboda
     2 * Copyright (c) 2024 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    4949    uint8_t, uint8_t, int);
    5050extern inet_link_t *inet_link_get_by_id(sysarg_t);
     51extern inet_link_t *inet_link_get_by_svc_name(const char *);
    5152extern errno_t inet_link_get_id_list(sysarg_t **, size_t *);
     53extern errno_t inet_link_discovery_start(void);
     54extern errno_t inet_link_autoconf(void);
     55extern void inet_link_autoconf_link(inet_link_cfg_info_t *);
    5256
    5357#endif
  • uspace/srv/net/inetsrv/inetcfg.c

    rbc3d695 r7bf29e5  
    11/*
    2  * Copyright (c) 2021 Jiri Svoboda
     2 * Copyright (c) 2024 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    9292        }
    9393
     94        rc = inet_cfg_sync(cfg);
     95        if (rc != EOK) {
     96                log_msg(LOG_DEFAULT, LVL_ERROR, "Error saving configuration.");
     97                return rc;
     98        }
     99
    94100        return EOK;
    95101}
     
    98104{
    99105        inet_addrobj_t *addr;
     106        inet_link_cfg_info_t info;
     107        unsigned acnt;
     108        inet_link_t *ilink;
     109        errno_t rc;
     110
     111        log_msg(LOG_DEFAULT, LVL_NOTE, "inetcfg_addr_delete()");
    100112
    101113        addr = inet_addrobj_get_by_id(addr_id);
     
    103115                return ENOENT;
    104116
     117        info.svc_id = addr->ilink->svc_id;
     118        info.svc_name = str_dup(addr->ilink->svc_name);
     119        if (info.svc_name == NULL)
     120                return ENOMEM;
     121
    105122        inet_addrobj_remove(addr);
    106123        inet_addrobj_delete(addr);
    107124
     125        log_msg(LOG_DEFAULT, LVL_NOTE, "inetcfg_addr_delete(): sync");
     126
     127        rc = inet_cfg_sync(cfg);
     128        if (rc != EOK) {
     129                log_msg(LOG_DEFAULT, LVL_ERROR, "Error saving configuration.");
     130                free(info.svc_name);
     131                return rc;
     132        }
     133
     134        log_msg(LOG_DEFAULT, LVL_NOTE, "inetcfg_addr_delete(): get link by ID");
     135
     136        ilink = inet_link_get_by_id(info.svc_id);
     137        if (ilink == NULL) {
     138                log_msg(LOG_DEFAULT, LVL_ERROR, "Error finding link.");
     139                return ENOENT;
     140        }
     141
     142        log_msg(LOG_DEFAULT, LVL_NOTE, "inetcfg_addr_delete(): check addrobj count");
     143
     144        /* If there are no configured addresses left, autoconfigure link */
     145        acnt = inet_addrobj_cnt_by_link(ilink);
     146        log_msg(LOG_DEFAULT, LVL_NOTE, "inetcfg_addr_delete(): acnt=%u", acnt);
     147        if (acnt == 0)
     148                inet_link_autoconf_link(&info);
     149
     150        log_msg(LOG_DEFAULT, LVL_NOTE, "inetcfg_addr_delete(): DONE");
    108151        return EOK;
    109152}
     
    193236    inet_addr_t *router, sysarg_t *sroute_id)
    194237{
     238        errno_t rc;
    195239        inet_sroute_t *sroute;
    196240
     
    207251
    208252        *sroute_id = sroute->id;
     253
     254        rc = inet_cfg_sync(cfg);
     255        if (rc != EOK) {
     256                log_msg(LOG_DEFAULT, LVL_ERROR, "Error saving configuration.");
     257                return rc;
     258        }
     259
    209260        return EOK;
    210261}
     
    212263static errno_t inetcfg_sroute_delete(sysarg_t sroute_id)
    213264{
     265        errno_t rc;
    214266        inet_sroute_t *sroute;
    215267
     
    220272        inet_sroute_remove(sroute);
    221273        inet_sroute_delete(sroute);
     274
     275        rc = inet_cfg_sync(cfg);
     276        if (rc != EOK) {
     277                log_msg(LOG_DEFAULT, LVL_ERROR, "Error saving configuration.");
     278                return rc;
     279        }
    222280
    223281        return EOK;
     
    805863}
    806864
     865static errno_t inet_cfg_load(const char *cfg_path)
     866{
     867        sif_doc_t *doc = NULL;
     868        sif_node_t *rnode;
     869        sif_node_t *naddrs;
     870        sif_node_t *nroutes;
     871        const char *ntype;
     872        errno_t rc;
     873
     874        rc = sif_load(cfg_path, &doc);
     875        if (rc != EOK)
     876                goto error;
     877
     878        rnode = sif_get_root(doc);
     879        naddrs = sif_node_first_child(rnode);
     880        ntype = sif_node_get_type(naddrs);
     881        if (str_cmp(ntype, "addresses") != 0) {
     882                rc = EIO;
     883                goto error;
     884        }
     885
     886        rc = inet_addrobjs_load(naddrs);
     887        if (rc != EOK)
     888                goto error;
     889
     890        nroutes = sif_node_next_child(naddrs);
     891        ntype = sif_node_get_type(nroutes);
     892        if (str_cmp(ntype, "static-routes") != 0) {
     893                rc = EIO;
     894                goto error;
     895        }
     896
     897        rc = inet_sroutes_load(nroutes);
     898        if (rc != EOK)
     899                goto error;
     900
     901        sif_delete(doc);
     902        return EOK;
     903error:
     904        if (doc != NULL)
     905                sif_delete(doc);
     906        return rc;
     907
     908}
     909
     910static errno_t inet_cfg_save(const char *cfg_path)
     911{
     912        sif_doc_t *doc = NULL;
     913        sif_node_t *rnode;
     914        sif_node_t *nsroutes;
     915        sif_node_t *naddrobjs;
     916        errno_t rc;
     917
     918        log_msg(LOG_DEFAULT, LVL_NOTE, "inet_cfg_save(%s)", cfg_path);
     919
     920        rc = sif_new(&doc);
     921        if (rc != EOK)
     922                goto error;
     923
     924        rnode = sif_get_root(doc);
     925
     926        /* Address objects */
     927
     928        rc = sif_node_append_child(rnode, "addresses", &naddrobjs);
     929        if (rc != EOK)
     930                goto error;
     931
     932        rc = inet_addrobjs_save(naddrobjs);
     933        if (rc != EOK)
     934                goto error;
     935
     936        /* Static routes */
     937
     938        rc = sif_node_append_child(rnode, "static-routes", &nsroutes);
     939        if (rc != EOK)
     940                goto error;
     941
     942        rc = inet_sroutes_save(nsroutes);
     943        if (rc != EOK)
     944                goto error;
     945
     946        /* Save */
     947
     948        rc = sif_save(doc, cfg_path);
     949        if (rc != EOK)
     950                goto error;
     951
     952        sif_delete(doc);
     953        return EOK;
     954error:
     955        if (doc != NULL)
     956                sif_delete(doc);
     957        return rc;
     958}
     959
     960/** Open internet server configuration.
     961 *
     962 * @param cfg_path Configuration file path
     963 * @param rcfg Place to store pointer to configuration object
     964 * @return EOK on success or an error code
     965 */
     966errno_t inet_cfg_open(const char *cfg_path, inet_cfg_t **rcfg)
     967{
     968        inet_cfg_t *cfg;
     969        errno_t rc;
     970
     971        log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_cfg_open(%s)", cfg_path);
     972
     973        rc = inet_cfg_load(cfg_path);
     974        if (rc != EOK) {
     975                log_msg(LOG_DEFAULT, LVL_WARN, "inet_cfg_open(%s) :"
     976                    "could not load configuration.", cfg_path);
     977        }
     978
     979        cfg = calloc(1, sizeof(inet_cfg_t));
     980        if (cfg == NULL)
     981                return ENOMEM;
     982
     983        cfg->cfg_path = str_dup(cfg_path);
     984        if (cfg->cfg_path == NULL) {
     985                free(cfg);
     986                return ENOMEM;
     987        }
     988
     989        *rcfg = cfg;
     990        return EOK;
     991}
     992
     993errno_t inet_cfg_sync(inet_cfg_t *cfg)
     994{
     995        log_msg(LOG_DEFAULT, LVL_NOTE, "inet_cfg_sync(cfg=%p)", cfg);
     996        return inet_cfg_save(cfg->cfg_path);
     997}
     998
     999void inet_cfg_close(inet_cfg_t *cfg)
     1000{
     1001        free(cfg);
     1002}
     1003
    8071004/** @}
    8081005 */
  • uspace/srv/net/inetsrv/inetcfg.h

    rbc3d695 r7bf29e5  
    11/*
    2  * Copyright (c) 2012 Jiri Svoboda
     2 * Copyright (c) 2024 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    3838#define INETCFG_H_
    3939
     40#include <errno.h>
     41#include "inetsrv.h"
     42
    4043extern void inet_cfg_conn(ipc_call_t *, void *);
     44extern errno_t inet_cfg_open(const char *, inet_cfg_t **);
     45extern errno_t inet_cfg_sync(inet_cfg_t *);
     46extern void inet_cfg_close(inet_cfg_t *);
    4147
    4248#endif
  • uspace/srv/net/inetsrv/inetsrv.c

    rbc3d695 r7bf29e5  
    11/*
    2  * Copyright (c) 2023 Jiri Svoboda
     2 * Copyright (c) 2024 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    7979};
    8080
     81static const char *inet_cfg_path = "/w/cfg/inetsrv.sif";
     82
    8183static FIBRIL_MUTEX_INITIALIZE(client_list_lock);
    8284static LIST_INITIALIZE(client_list);
     85inet_cfg_t *cfg;
    8386
    8487static void inet_default_conn(ipc_call_t *, void *);
     
    8689static errno_t inet_init(void)
    8790{
     91        port_id_t port;
     92        errno_t rc;
    8893        loc_srv_t *srv;
    8994
    9095        log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_init()");
    9196
    92         port_id_t port;
    93         errno_t rc = async_create_port(INTERFACE_INET,
     97        rc = inet_link_discovery_start();
     98        if (rc != EOK)
     99                return rc;
     100
     101        rc = inet_cfg_open(inet_cfg_path, &cfg);
     102        if (rc != EOK)
     103                return rc;
     104
     105        rc = async_create_port(INTERFACE_INET,
    94106            inet_default_conn, NULL, &port);
    95107        if (rc != EOK)
     
    556568
    557569        printf(NAME ": Accepting connections.\n");
     570
    558571        task_retval(0);
     572
     573        (void)inet_link_autoconf();
    559574        async_manager();
    560575
  • uspace/srv/net/inetsrv/inetsrv.h

    rbc3d695 r7bf29e5  
    11/*
    2  * Copyright (c) 2021 Jiri Svoboda
     2 * Copyright (c) 2024 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    4444#include <inet/iplink.h>
    4545#include <ipc/loc.h>
     46#include <sif.h>
    4647#include <stddef.h>
    4748#include <stdint.h>
     
    114115} inet_link_t;
    115116
     117/** Link information needed for autoconfiguration */
    116118typedef struct {
     119        service_id_t svc_id;
     120        char *svc_name;
     121} inet_link_cfg_info_t;
     122
     123/** Address object */
     124typedef struct {
     125        /** Link to list of addresses */
    117126        link_t addr_list;
     127        /** Address object ID */
    118128        sysarg_t id;
     129        /** Network address */
    119130        inet_naddr_t naddr;
     131        /** Underlying IP link */
    120132        inet_link_t *ilink;
     133        /** Address name */
    121134        char *name;
     135        /** Temporary object */
     136        bool temp;
    122137} inet_addrobj_t;
    123138
     
    125140typedef struct {
    126141        link_t sroute_list;
     142        /** ID */
    127143        sysarg_t id;
    128144        /** Destination network */
     
    130146        /** Router via which to route packets */
    131147        inet_addr_t router;
     148        /** Route name */
    132149        char *name;
     150        /** Temporary route */
     151        bool temp;
    133152} inet_sroute_t;
    134153
     
    152171} inet_dir_t;
    153172
     173/** Internet server configuration */
     174typedef struct {
     175        /** Configuration file path */
     176        char *cfg_path;
     177} inet_cfg_t;
     178
     179extern inet_cfg_t *cfg;
     180
    154181extern errno_t inet_ev_recv(inet_client_t *, inet_dgram_t *);
    155182extern errno_t inet_recv_packet(inet_packet_t *);
  • uspace/srv/net/inetsrv/meson.build

    rbc3d695 r7bf29e5  
    11#
    2 # Copyright (c) 2021 Jiri Svoboda
     2# Copyright (c) 2024 Jiri Svoboda
    33# All rights reserved.
    44#
     
    2727#
    2828
    29 deps = [ 'inet' ]
     29deps = [ 'inet', 'sif' ]
    3030src = files(
    3131        'addrobj.c',
  • uspace/srv/net/inetsrv/sroute.c

    rbc3d695 r7bf29e5  
    11/*
    2  * Copyright (c) 2012 Jiri Svoboda
     2 * Copyright (c) 2024 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    4040#include <io/log.h>
    4141#include <ipc/loc.h>
     42#include <sif.h>
     43#include <stdio.h>
    4244#include <stdlib.h>
    4345#include <str.h>
     
    210212}
    211213
     214/** Load static route from SIF node.
     215 *
     216 * @param nroute SIF node to load static route from
     217 * @return EOK on success or an error code
     218 */
     219static errno_t inet_sroute_load(sif_node_t *nroute)
     220{
     221        errno_t rc;
     222        const char *sid;
     223        const char *sdest;
     224        const char *srouter;
     225        const char *name;
     226        char *endptr;
     227        int id;
     228        inet_naddr_t dest;
     229        inet_addr_t router;
     230        inet_sroute_t *sroute;
     231
     232        sid = sif_node_get_attr(nroute, "id");
     233        if (sid == NULL)
     234                return EIO;
     235
     236        sdest = sif_node_get_attr(nroute, "dest");
     237        if (sdest == NULL)
     238                return EIO;
     239
     240        srouter = sif_node_get_attr(nroute, "router");
     241        if (srouter == NULL)
     242                return EIO;
     243
     244        name = sif_node_get_attr(nroute, "name");
     245        if (name == NULL)
     246                return EIO;
     247
     248        id = strtoul(sid, &endptr, 10);
     249        if (*endptr != '\0')
     250                return EIO;
     251
     252        rc = inet_naddr_parse(sdest, &dest, NULL);
     253        if (rc != EOK)
     254                return EIO;
     255
     256        rc = inet_addr_parse(srouter, &router, NULL);
     257        if (rc != EOK)
     258                return EIO;
     259
     260        sroute = inet_sroute_new();
     261        if (sroute == NULL)
     262                return ENOMEM;
     263
     264        sroute->id = id;
     265        sroute->dest = dest;
     266        sroute->router = router;
     267        sroute->name = str_dup(name);
     268
     269        if (sroute->name == NULL) {
     270                inet_sroute_delete(sroute);
     271                return ENOMEM;
     272        }
     273
     274        inet_sroute_add(sroute);
     275        return EOK;
     276}
     277
     278/** Load static routes from SIF node.
     279 *
     280 * @param nroutes SIF node to load static routes from
     281 * @return EOK on success or an error code
     282 */
     283errno_t inet_sroutes_load(sif_node_t *nroutes)
     284{
     285        sif_node_t *nroute;
     286        const char *ntype;
     287        errno_t rc;
     288
     289        nroute = sif_node_first_child(nroutes);
     290        while (nroute != NULL) {
     291                ntype = sif_node_get_type(nroute);
     292                if (str_cmp(ntype, "route") != 0) {
     293                        rc = EIO;
     294                        goto error;
     295                }
     296
     297                rc = inet_sroute_load(nroute);
     298                if (rc != EOK)
     299                        goto error;
     300
     301                nroute = sif_node_next_child(nroute);
     302        }
     303
     304        return EOK;
     305error:
     306        return rc;
     307}
     308
     309/** Save static route to SIF node.
     310 *
     311 * @param sroute Static route
     312 * @param nroute SIF node to save static route to
     313 * @return EOK on success or an error code
     314 */
     315static errno_t inet_sroute_save(inet_sroute_t *sroute, sif_node_t *nroute)
     316{
     317        char *str = NULL;
     318        errno_t rc;
     319        int rv;
     320
     321        log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_sroute_save(%p, %p)",
     322            sroute, nroute);
     323
     324        /* id */
     325
     326        rv = asprintf(&str, "%zu", sroute->id);
     327        if (rv < 0) {
     328                str = NULL;
     329                rc = ENOMEM;
     330                goto error;
     331        }
     332
     333        rc = sif_node_set_attr(nroute, "id", str);
     334        if (rc != EOK)
     335                goto error;
     336
     337        free(str);
     338        str = NULL;
     339
     340        /* dest */
     341
     342        rc = inet_naddr_format(&sroute->dest, &str);
     343        if (rc != EOK)
     344                goto error;
     345
     346        rc = sif_node_set_attr(nroute, "dest", str);
     347        if (rc != EOK)
     348                goto error;
     349
     350        free(str);
     351        str = NULL;
     352
     353        /* router */
     354
     355        rc = inet_addr_format(&sroute->router, &str);
     356        if (rc != EOK)
     357                goto error;
     358
     359        rc = sif_node_set_attr(nroute, "router", str);
     360        if (rc != EOK)
     361                goto error;
     362
     363        /* name */
     364
     365        rc = sif_node_set_attr(nroute, "name", sroute->name);
     366        if (rc != EOK)
     367                goto error;
     368
     369        free(str);
     370
     371        return rc;
     372error:
     373        if (str != NULL)
     374                free(str);
     375        return rc;
     376}
     377
     378/** Save static routes to SIF node.
     379 *
     380 * @param nroutes SIF node to save static routes to
     381 * @return EOK on success or an error code
     382 */
     383errno_t inet_sroutes_save(sif_node_t *nroutes)
     384{
     385        sif_node_t *nroute;
     386        errno_t rc;
     387
     388        log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_sroutes_save()");
     389
     390        fibril_mutex_lock(&sroute_list_lock);
     391
     392        list_foreach(sroute_list, sroute_list, inet_sroute_t, sroute) {
     393                if (sroute->temp == false) {
     394                        rc = sif_node_append_child(nroutes, "route", &nroute);
     395                        if (rc != EOK)
     396                                goto error;
     397
     398                        rc = inet_sroute_save(sroute, nroute);
     399                        if (rc != EOK)
     400                                goto error;
     401                }
     402        }
     403
     404        fibril_mutex_unlock(&sroute_list_lock);
     405        return EOK;
     406error:
     407        fibril_mutex_unlock(&sroute_list_lock);
     408        return rc;
     409}
     410
    212411/** @}
    213412 */
  • uspace/srv/net/inetsrv/sroute.h

    rbc3d695 r7bf29e5  
    11/*
    2  * Copyright (c) 2012 Jiri Svoboda
     2 * Copyright (c) 2024 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    3838#define INET_SROUTE_H_
    3939
     40#include <sif.h>
    4041#include <stddef.h>
    4142#include <stdint.h>
     
    5253    inet_dgram_t *, uint8_t, uint8_t, int);
    5354extern errno_t inet_sroute_get_id_list(sysarg_t **, size_t *);
     55extern errno_t inet_sroutes_load(sif_node_t *);
     56extern errno_t inet_sroutes_save(sif_node_t *);
    5457
    5558#endif
  • uspace/srv/system/system.h

    rbc3d695 r7bf29e5  
    11/*
    2  * Copyright (c) 2013 Jiri Svoboda
     2 * Copyright (c) 2024 Jiri Svoboda
     3 * Copyright (c) 2006 Martin Decky
    34 * All rights reserved.
    45 *
     
    2728 */
    2829
    29 /** @addtogroup inetsrv
     30/** @addtogroup system
    3031 * @{
    3132 */
    3233/**
    3334 * @file
    34  * @brief
    3535 */
    3636
    37 #ifndef INETSRV_H_
    38 #define INETSRV_H_
     37#ifndef SYSTEM_H
     38#define SYSTEM_H
    3939
    40 #include <adt/list.h>
    41 #include <ipc/loc.h>
     40#include <system_srv.h>
     41
     42#define NAME  "system"
    4243
    4344typedef struct {
    44         link_t link_list;
    45         service_id_t svc_id;
    46         char *svc_name;
    47 } ncs_link_t;
     45        system_srv_t srv;
     46} sys_srv_t;
    4847
    4948#endif
  • uspace/srv/volsrv/part.c

    rbc3d695 r7bf29e5  
    5252#include "types/part.h"
    5353#include "volume.h"
     54#include "volsrv.h"
    5455
    5556static errno_t vol_part_add_locked(vol_parts_t *, service_id_t);
     
    403404        part->cur_mp_auto = mp_auto;
    404405
     406        if (str_cmp(mp, "/w") == 0) {
     407                log_msg(LOG_DEFAULT, LVL_NOTE, "Mounted system volume - "
     408                    "loading additional configuration.");
     409                rc = vol_volumes_merge_to(part->parts->volumes,
     410                    vol_cfg_file);
     411                if (rc != EOK) {
     412                        log_msg(LOG_DEFAULT, LVL_ERROR, "Error loading "
     413                            "additional configuration.");
     414                        return rc;
     415                }
     416        }
     417
    405418        return rc;
    406419}
  • uspace/srv/volsrv/volsrv.c

    rbc3d695 r7bf29e5  
    11/*
    2  * Copyright (c) 2023 Jiri Svoboda
     2 * Copyright (c) 2024 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    5353#define NAME  "volsrv"
    5454
    55 const char *vol_cfg_file = "/cfg/volsrv.sif";
     55const char *vol_icfg_file = "/cfg/initvol.sif";
     56const char *vol_cfg_file = "/w/cfg/volsrv.sif";
    5657
    5758static void vol_client_conn(ipc_call_t *, void *);
     
    6667        log_msg(LOG_DEFAULT, LVL_DEBUG, "vol_init()");
    6768
    68         rc = vol_volumes_create(vol_cfg_file, &volumes);
     69        rc = vol_volumes_create(vol_icfg_file, &volumes);
    6970        if (rc != EOK)
    7071                goto error;
  • uspace/srv/volsrv/volsrv.h

    rbc3d695 r7bf29e5  
    11/*
    2  * Copyright (c) 2013 Jiri Svoboda
     2 * Copyright (c) 2024 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    2727 */
    2828
    29 /** @addtogroup nconfsrv
     29/** @addtogroup volsrv
    3030 * @{
    3131 */
    3232/**
    33  * @file
    34  * @brief
     33 * @file Volume service
    3534 */
    3635
    37 #ifndef NCONFSRV_IPLINK_H_
    38 #define NCONFSRV_IPLINK_H_
     36#ifndef VOLSRV_H
     37#define VOLSRV_H
    3938
    40 #include <stddef.h>
    41 #include "nconfsrv.h"
    42 
    43 extern errno_t ncs_link_discovery_start(void);
    44 extern ncs_link_t *ncs_link_get_by_id(sysarg_t);
    45 extern errno_t ncs_link_get_id_list(sysarg_t **, size_t *);
     39extern const char *vol_cfg_file;
    4640
    4741#endif
  • uspace/srv/volsrv/volume.c

    rbc3d695 r7bf29e5  
    185185                free(volumes);
    186186
     187        return rc;
     188}
     189
     190/** Merge list of volumes into new file.
     191 *
     192 * @param volumes List of volumes
     193 * @param cfg_path Path to file containing configuration repository in SIF
     194 * @return EOK on success, ENOMEM if out of memory
     195 */
     196errno_t vol_volumes_merge_to(vol_volumes_t *volumes, const char *cfg_path)
     197{
     198        sif_doc_t *doc = NULL;
     199        sif_node_t *node;
     200        const char *ntype;
     201        char *dcfg_path;
     202        errno_t rc;
     203
     204        dcfg_path = str_dup(cfg_path);
     205        if (dcfg_path == NULL) {
     206                rc = ENOMEM;
     207                goto error;
     208        }
     209
     210        free(volumes->cfg_path);
     211        volumes->cfg_path = dcfg_path;
     212
     213        /* Try opening existing repository */
     214        rc = sif_load(cfg_path, &doc);
     215        if (rc != EOK) {
     216                /* Failed to open existing, create new repository */
     217                rc = vol_volumes_sync(volumes);
     218                if (rc != EOK)
     219                        goto error;
     220        } else {
     221                /*
     222                 * Loaded existing configuration. Find 'volumes' node, should
     223                 * be the first child of the root node.
     224                 */
     225                node = sif_node_first_child(sif_get_root(doc));
     226
     227                /* Verify it's the correct node type */
     228                ntype = sif_node_get_type(node);
     229                if (str_cmp(ntype, "volumes") != 0) {
     230                        rc = EIO;
     231                        goto error;
     232                }
     233
     234                rc = vol_volumes_load(node, volumes);
     235                if (rc != EOK)
     236                        goto error;
     237
     238                sif_delete(doc);
     239        }
     240
     241        return EOK;
     242error:
     243        if (doc != NULL)
     244                (void) sif_delete(doc);
    187245        return rc;
    188246}
  • uspace/srv/volsrv/volume.h

    rbc3d695 r7bf29e5  
    4242
    4343extern errno_t vol_volumes_create(const char *, vol_volumes_t **);
     44extern errno_t vol_volumes_merge_to(vol_volumes_t *, const char *);
    4445extern errno_t vol_volumes_sync(vol_volumes_t *);
    4546extern void vol_volumes_destroy(vol_volumes_t *);
Note: See TracChangeset for help on using the changeset viewer.