Ignore:
File:
1 edited

Legend:

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

    r902f0906 r03e0a244  
    3434
    3535#include <async.h>
     36#include <stdio.h>
     37#include <adt/prodcons.h>
     38#include <ipc/input.h>
     39#include <ipc/console.h>
     40#include <ipc/vfs.h>
    3641#include <errno.h>
    37 #include <io/con_srv.h>
    38 #include <stdio.h>
    39 #include <stdlib.h>
    4042#include <str_error.h>
    4143#include <loc.h>
     
    4345#include <io/keycode.h>
    4446#include <align.h>
     47#include <malloc.h>
     48#include <as.h>
    4549#include <fibril_synch.h>
    4650#include <task.h>
     
    6771        TELNET_IAC, TELNET_WONT, TELNET_LINEMODE
    6872};
    69 
    7073static const size_t telnet_force_character_mode_command_count =
    7174    sizeof(telnet_force_character_mode_command) / sizeof(telnet_cmd_t);
    7275
    73 static int remcons_open(con_srvs_t *, con_srv_t *);
    74 static int remcons_close(con_srv_t *);
    75 static int remcons_write(con_srv_t *, void *, size_t);
    76 static void remcons_sync(con_srv_t *);
    77 static void remcons_clear(con_srv_t *);
    78 static void remcons_set_pos(con_srv_t *, sysarg_t col, sysarg_t row);
    79 static int remcons_get_pos(con_srv_t *, sysarg_t *, sysarg_t *);
    80 static int remcons_get_size(con_srv_t *, sysarg_t *, sysarg_t *);
    81 static int remcons_get_color_cap(con_srv_t *, console_caps_t *);
    82 static int remcons_get_event(con_srv_t *, cons_event_t *);
    83 
    84 static con_ops_t con_ops = {
    85         .open = remcons_open,
    86         .close = remcons_close,
    87         .read = NULL,
    88         .write = remcons_write,
    89         .sync = remcons_sync,
    90         .clear = remcons_clear,
    91         .set_pos = remcons_set_pos,
    92         .get_pos = remcons_get_pos,
    93         .get_size = remcons_get_size,
    94         .get_color_cap = remcons_get_color_cap,
    95         .set_style = NULL,
    96         .set_color = NULL,
    97         .set_rgb_color = NULL,
    98         .set_cursor_visibility = NULL,
    99         .get_event = remcons_get_event
    100 };
    101 
    102 static telnet_user_t *srv_to_user(con_srv_t *srv)
    103 {
    104         return srv->srvs->sarg;
    105 }
    106 
    107 static int remcons_open(con_srvs_t *srvs, con_srv_t *srv)
    108 {
    109         telnet_user_t *user = srv_to_user(srv);
    110 
    111         telnet_user_log(user, "New client connected (%p).", srv);
    112 
    113         /* Force character mode. */
    114         send(user->socket, (void *)telnet_force_character_mode_command,
    115             telnet_force_character_mode_command_count, 0);
    116 
    117         return EOK;
    118 }
    119 
    120 static int remcons_close(con_srv_t *srv)
    121 {
    122         telnet_user_t *user = srv_to_user(srv);
    123 
    124         telnet_user_notify_client_disconnected(user);
    125         telnet_user_log(user, "Client disconnected (%p).", srv);
    126 
    127         return EOK;
    128 }
    129 
    130 static int remcons_write(con_srv_t *srv, void *data, size_t size)
    131 {
    132         telnet_user_t *user = srv_to_user(srv);
    133         int rc;
    134 
    135         rc = telnet_user_send_data(user, data, size);
    136         if (rc != EOK)
    137                 return rc;
    138 
    139         return size;
    140 }
    141 
    142 static void remcons_sync(con_srv_t *srv)
    143 {
    144         (void) srv;
    145 }
    146 
    147 static void remcons_clear(con_srv_t *srv)
    148 {
    149         (void) srv;
    150 }
    151 
    152 static void remcons_set_pos(con_srv_t *srv, sysarg_t col, sysarg_t row)
    153 {
    154         telnet_user_t *user = srv_to_user(srv);
    155 
    156         telnet_user_update_cursor_x(user, col);
    157 }
    158 
    159 static int remcons_get_pos(con_srv_t *srv, sysarg_t *col, sysarg_t *row)
    160 {
    161         telnet_user_t *user = srv_to_user(srv);
    162 
    163         *col = user->cursor_x;
    164         *row = 0;
    165 
    166         return EOK;
    167 }
    168 
    169 static int remcons_get_size(con_srv_t *srv, sysarg_t *cols, sysarg_t *rows)
    170 {
    171         (void) srv;
    172 
    173         *cols = 100;
    174         *rows = 1;
    175 
    176         return EOK;
    177 }
    178 
    179 static int remcons_get_color_cap(con_srv_t *srv, console_caps_t *ccaps)
    180 {
    181         (void) srv;
    182         *ccaps = CONSOLE_CAP_NONE;
    183 
    184         return EOK;
    185 }
    186 
    187 static int remcons_get_event(con_srv_t *srv, cons_event_t *event)
    188 {
    189         telnet_user_t *user = srv_to_user(srv);
    190         kbd_event_t kevent;
    191         int rc;
    192 
    193         rc = telnet_user_get_next_keyboard_event(user, &kevent);
    194         if (rc != EOK) {
    195                 /* XXX What? */
    196                 memset(event, 0, sizeof(*event));
    197                 return EOK;
    198         }
    199 
    200         event->type = CEV_KEY;
    201         event->ev.key = kevent;
    202 
    203         return EOK;
     76
     77/** Handling client requests (VFS and console interface).
     78 *
     79 * @param user Telnet user the requests belong to.
     80 */
     81static void client_connection_message_loop(telnet_user_t *user)
     82{
     83        while (true) {
     84                ipc_call_t call;
     85                ipc_callid_t callid = 0;
     86
     87                /*
     88                 * The getterm task might terminate while we are here,
     89                 * waiting for a call. Also, the socket might be closed
     90                 * meanwhile.
     91                 * We want to detect this situation early, so we use a
     92                 * timeout variant of async_get_call().
     93                 */
     94                while (callid == 0) {
     95                        callid = async_get_call_timeout(&call, 1000);
     96
     97                        if (telnet_user_is_zombie(user)) {
     98                                if (callid != 0) {
     99                                        async_answer_0(callid, EINTR);
     100                                }
     101                                return;
     102                        }
     103                }
     104               
     105                if (!IPC_GET_IMETHOD(call)) {
     106                        return;
     107                }
     108
     109                switch (IPC_GET_IMETHOD(call)) {
     110                case CONSOLE_GET_SIZE:
     111                        async_answer_2(callid, EOK, 100, 1);
     112                        break;
     113                case CONSOLE_GET_POS:
     114                        fibril_mutex_lock(&user->guard);
     115                        async_answer_2(callid, EOK, user->cursor_x, 0);
     116                        fibril_mutex_unlock(&user->guard);
     117                        break;
     118                case CONSOLE_GET_EVENT: {
     119                        kbd_event_t event;
     120                        int rc = telnet_user_get_next_keyboard_event(user, &event);
     121                        if (rc != EOK) {
     122                                /* Silently ignore. */
     123                                async_answer_0(callid, EOK);
     124                                break;
     125                        }
     126                        async_answer_4(callid, EOK, event.type, event.key, event.mods, event.c);
     127                        break;
     128                }
     129                case CONSOLE_GOTO: {
     130                        int new_x = IPC_GET_ARG1(call);
     131                        telnet_user_update_cursor_x(user, new_x);
     132                        async_answer_0(callid, ENOTSUP);
     133                        break;
     134                }
     135                case VFS_OUT_READ:
     136                        async_answer_0(callid, ENOTSUP);
     137                        break;
     138                case VFS_OUT_WRITE: {
     139                        uint8_t *buf;
     140                        size_t size;
     141                        int rc = async_data_write_accept((void **)&buf, false, 0, 0, 0, &size);
     142
     143                        if (rc != EOK) {
     144                                async_answer_0(callid, rc);
     145                                break;
     146                        }
     147
     148                        rc = telnet_user_send_data(user, buf, size);
     149                        free(buf);
     150
     151                        if (rc != EOK) {
     152                                async_answer_0(callid, rc);
     153                                break;
     154                        }
     155
     156                        async_answer_1(callid, EOK, size);
     157                        break;
     158                }
     159                case VFS_OUT_SYNC:
     160                        async_answer_0(callid, EOK);
     161                        break;
     162                case CONSOLE_CLEAR:
     163                        async_answer_0(callid, EOK);
     164                        break;
     165
     166                case CONSOLE_GET_COLOR_CAP:
     167                        async_answer_1(callid, EOK, CONSOLE_CAP_NONE);
     168                        break;
     169                case CONSOLE_SET_STYLE:
     170                        async_answer_0(callid, ENOTSUP);
     171                        break;
     172                case CONSOLE_SET_COLOR:
     173                        async_answer_0(callid, ENOTSUP);
     174                        break;
     175                case CONSOLE_SET_RGB_COLOR:
     176                        async_answer_0(callid, ENOTSUP);
     177                        break;
     178
     179                case CONSOLE_CURSOR_VISIBILITY:
     180                        async_answer_0(callid, ENOTSUP);
     181                        break;
     182
     183                default:
     184                        async_answer_0(callid, EINVAL);
     185                        break;
     186                }
     187        }
    204188}
    205189
     
    213197                return;
    214198        }
     199        async_answer_0(iid, EOK);
     200
     201        telnet_user_log(user, "New client connected (%" PRIxn").", iid);
     202
     203        /* Force character mode. */
     204        send(user->socket, (void *)telnet_force_character_mode_command,
     205            telnet_force_character_mode_command_count, 0);
    215206
    216207        /* Handle messages. */
    217         con_conn(iid, icall, &user->srvs);
     208        client_connection_message_loop(user);
     209
     210        telnet_user_notify_client_disconnected(user);
     211        telnet_user_log(user, "Client disconnected (%" PRIxn").", iid);
    218212}
    219213
     
    237231                fibril_mutex_lock(&user->guard);
    238232                user->task_finished = true;
    239                 user->srvs.aborted = true;
    240233                fibril_condvar_signal(&user->refcount_cv);
    241234                fibril_mutex_unlock(&user->guard);
     
    257250        fibril_mutex_lock(&user->guard);
    258251        user->task_finished = true;
    259         user->srvs.aborted = true;
    260252        fibril_condvar_signal(&user->refcount_cv);
    261253        fibril_mutex_unlock(&user->guard);
     
    280272static int network_user_fibril(void *arg)
    281273{
     274        int rc;
    282275        telnet_user_t *user = arg;
    283276
    284         int rc = loc_service_register(user->service_name, &user->service_id);
     277        rc = loc_service_register(user->service_name, &user->service_id);
    285278        if (rc != EOK) {
    286279                telnet_user_error(user, "Unable to register %s with loc: %s.",
     
    291284        telnet_user_log(user, "Service %s registerd with id %" PRIun ".",
    292285            user->service_name, user->service_id);
    293        
     286
    294287        fid_t spawn_fibril = fibril_create(spawn_task_fibril, user);
    295288        assert(spawn_fibril);
    296289        fibril_add_ready(spawn_fibril);
    297        
     290
    298291        /* Wait for all clients to exit. */
    299292        fibril_mutex_lock(&user->guard);
     
    302295                        closesocket(user->socket);
    303296                        user->socket_closed = true;
    304                         user->srvs.aborted = true;
    305297                        continue;
    306298                } else if (user->socket_closed) {
     
    312304        }
    313305        fibril_mutex_unlock(&user->guard);
    314        
     306
    315307        rc = loc_service_unregister(user->service_id);
    316308        if (rc != EOK) {
     
    330322        int port = 2223;
    331323       
    332         async_set_client_connection(client_connection);
    333         int rc = loc_server_register(NAME);
    334         if (rc != EOK) {
    335                 fprintf(stderr, "%s: Unable to register server\n", NAME);
    336                 return rc;
    337         }
    338        
     324        int rc = loc_server_register(NAME, client_connection);
     325        if (rc < 0) {
     326                fprintf(stderr, NAME ": Unable to register server: %s.\n",
     327                    str_error(rc));
     328                return 1;
     329        }
     330
    339331        struct sockaddr_in addr;
    340        
     332
    341333        addr.sin_family = AF_INET;
    342334        addr.sin_port = htons(port);
    343        
     335
    344336        rc = inet_pton(AF_INET, "127.0.0.1", (void *)
    345337            &addr.sin_addr.s_addr);
     
    371363
    372364        printf("%s: HelenOS Remote console service\n", NAME);
    373         task_retval(0);
    374365
    375366        while (true) {
     
    388379                assert(user);
    389380
    390                 con_srvs_init(&user->srvs);
    391                 user->srvs.ops = &con_ops;
    392                 user->srvs.sarg = user;
    393                 user->srvs.abort_timeout = 1000;
    394 
    395                 telnet_user_add(user);
    396 
    397381                fid_t fid = fibril_create(network_user_fibril, user);
    398382                assert(fid);
Note: See TracChangeset for help on using the changeset viewer.