X-Git-Url: https://git.squeep.com/?a=blobdiff_plain;f=command.c;fp=command.c;h=20ca0fc38f853efa82c33922903f208d5cc7107c;hb=3c54afe11e890fc476cc4730226be1c45f8a04cb;hp=0000000000000000000000000000000000000000;hpb=29235d4c1f0b11bd2efcad262eaae70383228293;p=lemu diff --git a/command.c b/command.c new file mode 100644 index 0000000..20ca0fc --- /dev/null +++ b/command.c @@ -0,0 +1,248 @@ +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "command.h" +#include "common.h" +#include "connections.h" +#include "db.h" +#include "lua_interface.h" +#include "notify.h" +#include "server.h" + +/** + * Return a new populated command. + */ +struct command * +command_new(unsigned char *command_line, size_t command_len, command_flags_t flags) +{ + struct command *command; + + command = calloc(1, sizeof *command); + if (command == NULL) { + NOTIFY_ERROR("%s:%s", "calloc", strerror(errno)); + return NULL; + } + + command->command = command_line; + command->command_len = command_len; + command->flags = flags; + + return command; +} + + +/** + * Release a command and its data. + */ +void +command_free(struct command *command) +{ + command->command_len = 0; + command->flags = 0; + if (command->command) { + free(command->command); + command->command = NULL; + } + free(command); +} + + +/** + * This is invoked when a connection has successfully joined the server. + */ +void +command_connected(struct connection *c) +{ + connection_printf(c, "Welcome!\n"); + connection_printf_broadcast(c, true, "[%s has connected]\n", c->name); +} + + +/** + * This is invoked when a connection has been disconnected from the server, + * before the connection is destroyed. + */ +void +command_disconnected(struct connection *c) +{ + connection_printf(c, "Goodbye!\n"); + connection_printf_broadcast(c, true, "[%s has disconnected]\n", c->name); + NOTIFY_DEBUG("%s disconnected", c->name); +} + + +/** + * process some simple commands, until we get fancier + */ +void +command_parse(struct connection *c, struct server_worker_context *ctx, size_t thread_id, struct command *command) +{ + NOTIFY_DEBUG("parsing '%s' from '%s' (%p) [%zu]", command->command, c->name, ctx, thread_id); + + if (command->flags & COMMAND_FLAG_EVENT_CONNECT) { + command_connected(c); + } + if (command->flags & COMMAND_FLAG_EVENT_DISCONNECT) { + command_disconnected(c); + } + + if (!command->command) { + return; + } + + if (strncasecmp((char *)command->command, "auth", 4) == 0) { + char *cmd, *user, *secret, *state; + int uid = 0; + int r = 0; + + cmd = strtok_r((char *)command->command, " \t\n\r", &state); + user = strtok_r(NULL, " \t\n\r", &state); + secret = strtok_r(NULL, " \t\n\r", &state); + + if (!cmd || !user || !secret) { + connection_printf(c, "Failed.\n"); + return; + } + + NOTIFY_DEBUG("authentication request for '%s'", user); + + r = db_uid_from_name(&c->server->db, (unsigned char *)user, &uid); + NOTIFY_DEBUG("r:%d uid: %d", r, uid); + + connection_printf(c, ">> r:%d uid: %d\n", r, uid); + + return; + } + + if (memcmp(command->command, "QUIT", command->command_len) == 0) { + bufferevent_disable(c->bev, EV_READ); + connection_printf(c, "Goodbye! You sent me a total of %zu bytes! (user_time:%ld.%.6ld sys_time:%ld.%.6ld)\n", + c->total_read, + c->utime.tv_sec, (long int) c->utime.tv_usec, + c->stime.tv_sec, (long int) c->utime.tv_usec); + c->state = CONNECTION_STATE_WANT_CLOSE; + return; + } + + if (memcmp(command->command, "@SHUTDOWN", command->command_len) == 0) { + struct timeval _now = { 0, 0 }; + struct event_base *base = c->bev->ev_base; /* no accessor like bufferevent_get_base() so need to directly grab this with */ + + connection_printf(c, "Killing server.\n"); + + event_base_loopexit(base, &_now); + return; + } + + if (memcmp(command->command, "INFO", command->command_len) == 0) { + char *uuid_buf = NULL; + size_t uuid_len; + uuid_rc_t rc; + + rc = uuid_export(c->uuid, UUID_FMT_STR, &uuid_buf, &uuid_len); + if (rc != UUID_RC_OK) { + NOTIFY_ERROR("%s:%s", "uuid_export", uuid_error(rc)); + } + + connection_lock_output(c); + connection_printf(c, "You are connected from: %s\n", c->client_address); + connection_printf(c, "Your connection is %sencrypted.\n", c->flags & CONN_TYPE_SSL ? "" : "not "); + connection_printf(c, "Your UUID is: %s\n", uuid_buf); + connection_unlock_output(c); + + free(uuid_buf); + + return; + } + + if (memcmp(command->command, "WHO", command->command_len) == 0) { + struct connection **clist; + struct connection **clist_iter; + + clist_iter = clist = connections_all_as_array(&c->server->connections, NULL); + + connection_lock_output(c); + while (*clist_iter) { + connection_printf(c, "%s from %s%s%s\n", + (*clist_iter)->name, + (*clist_iter)->client_address, + (*clist_iter)->flags & CONN_TYPE_SSL ? " (via ssl)" : "", + (*clist_iter == c) ? " <- you" : ""); + connection_free(*clist_iter); + clist_iter++; + } + connection_unlock_output(c); + + free(clist); + + return; + } + +#define TOSD(__off__) NOTIFY_DEBUG("TOS[%d]: %s '%s'", lua_gettop(L) - (__off__), lua_typename(L, lua_type(L, -1 - (__off__))), lua_tostring(L, -1 - (__off__))) + if (*command->command == '!') { + lua_State *L = ctx->L; + const char *echo = (const char *) command->command + 1; + + + // lemu_cosnnection_push(L, c); // c + + // int t = lua_gettop(L); + // lua_pushnil(L); /* first key */ + // while (lua_next(L, t) != 0) { + // /* uses 'key' (at index -2) and 'value' (at index -1) */ + // printf("k:%s v:%s\n", + // lua_typename(L, lua_type(L, -2)), + // lua_typename(L, lua_type(L, -1))); + // /* removes 'value'; keeps 'key' for next iteration */ + // switch (lua_type(L, -2)) { + // case LUA_TSTRING: + // printf("\tk:%s\n", lua_tostring(L, -2)); + // break; + // case LUA_TNUMBER: + // printf("\tk:%f\n", lua_tonumber(L, -2)); + // break; + // default: + // printf("\tk:?\n"); + // } + // switch (lua_type(L, -1)) { + // case LUA_TSTRING: + // printf("\tv:%s\n", lua_tostring(L, -1)); + // break; + // case LUA_TNUMBER: + // printf("\tv:%f\n", lua_tonumber(L, -1)); + // break; + // default: + // printf("\tv:?\n"); + // } + // lua_pop(L, 1); + // } + + NOTIFY_DEBUG("lua echo on '%s'", echo); + TOSD(0); + lemu_connection_push(L, c); // c + TOSD(0); + lua_getfield(L, 1, "send"); // c sendfn + TOSD(0); + lua_rotate(L, 1, 1); // sendfn c + TOSD(0); + lua_pushfstring(L, "(lua echo) %s", echo); // sendfn c str + TOSD(0); + lua_call(L, 2, 0); + } + + /* default to broadcasting message */ + connection_printf_broadcast(c, true, "%s said: %s\n", c->name, command->command); + connection_printf(c, "%s said: %s\n", "You", command->command); +}