3 #include <event2/event.h>
4 #include <event2/bufferevent.h>
5 #include <event2/bufferevent_struct.h>
18 #include "connections.h"
20 #include "lua_interface.h"
25 * Return a new populated command.
28 command_new(unsigned char *command_line
, size_t command_len
, command_flags_t flags
)
30 struct command
*command
;
32 command
= calloc(1, sizeof *command
);
33 if (command
== NULL
) {
34 NOTIFY_ERROR("%s:%s", "calloc", strerror(errno
));
38 command
->command
= command_line
;
39 command
->command_len
= command_len
;
40 command
->flags
= flags
;
47 * Release a command and its data.
50 command_free(struct command
*command
)
52 command
->command_len
= 0;
54 if (command
->command
) {
55 free(command
->command
);
56 command
->command
= NULL
;
63 * This is invoked when a connection has successfully joined the server.
66 command_connected(struct connection
*c
)
68 connection_printf(c
, "Welcome!\n");
69 connection_printf_broadcast(c
, true, "[%s has connected]\n", c
->name
);
74 * This is invoked when a connection has been disconnected from the server,
75 * before the connection is destroyed.
78 command_disconnected(struct connection
*c
)
80 connection_printf(c
, "Goodbye!\n");
81 connection_printf_broadcast(c
, true, "[%s has disconnected]\n", c
->name
);
82 NOTIFY_DEBUG("%s disconnected", c
->name
);
87 * process some simple commands, until we get fancier
90 command_parse(struct connection
*c
, struct server_worker_context
*ctx
, size_t thread_id
, struct command
*command
)
92 NOTIFY_DEBUG("parsing '%s' from '%s' (%p) [%zu]", command
->command
, c
->name
, ctx
, thread_id
);
94 if (command
->flags
& COMMAND_FLAG_EVENT_CONNECT
) {
97 if (command
->flags
& COMMAND_FLAG_EVENT_DISCONNECT
) {
98 command_disconnected(c
);
101 if (!command
->command
) {
105 if (strncasecmp((char *)command
->command
, "auth", 4) == 0) {
106 char *cmd
, *user
, *secret
, *state
;
110 cmd
= strtok_r((char *)command
->command
, " \t\n\r", &state
);
111 user
= strtok_r(NULL
, " \t\n\r", &state
);
112 secret
= strtok_r(NULL
, " \t\n\r", &state
);
114 if (!cmd
|| !user
|| !secret
) {
115 connection_printf(c
, "Failed.\n");
119 NOTIFY_DEBUG("authentication request for '%s'", user
);
121 r
= db_uid_from_name(&c
->server
->db
, (unsigned char *)user
, &uid
);
122 NOTIFY_DEBUG("r:%d uid: %d", r
, uid
);
124 connection_printf(c
, ">> r:%d uid: %d\n", r
, uid
);
129 if (memcmp(command
->command
, "QUIT", command
->command_len
) == 0) {
130 bufferevent_disable(c
->bev
, EV_READ
);
131 connection_printf(c
, "Goodbye! You sent me a total of %zu bytes! (user_time:%ld.%.6ld sys_time:%ld.%.6ld)\n",
133 c
->utime
.tv_sec
, (long int) c
->utime
.tv_usec
,
134 c
->stime
.tv_sec
, (long int) c
->utime
.tv_usec
);
135 c
->state
= CONNECTION_STATE_WANT_CLOSE
;
139 if (memcmp(command
->command
, "@SHUTDOWN", command
->command_len
) == 0) {
140 struct timeval _now
= { 0, 0 };
141 struct event_base
*base
= c
->bev
->ev_base
; /* no accessor like bufferevent_get_base() so need to directly grab this with <event2/bufferevent_struct.h> */
143 connection_printf(c
, "Killing server.\n");
145 event_base_loopexit(base
, &_now
);
149 if (memcmp(command
->command
, "INFO", command
->command_len
) == 0) {
150 char *uuid_buf
= NULL
;
154 rc
= uuid_export(c
->uuid
, UUID_FMT_STR
, &uuid_buf
, &uuid_len
);
155 if (rc
!= UUID_RC_OK
) {
156 NOTIFY_ERROR("%s:%s", "uuid_export", uuid_error(rc
));
159 connection_lock_output(c
);
160 connection_printf(c
, "You are connected from: %s\n", c
->client_address
);
161 connection_printf(c
, "Your connection is %sencrypted.\n", c
->flags
& CONN_TYPE_SSL
? "" : "not ");
162 connection_printf(c
, "Your UUID is: %s\n", uuid_buf
);
163 connection_unlock_output(c
);
170 if (memcmp(command
->command
, "WHO", command
->command_len
) == 0) {
171 struct connection
**clist
;
172 struct connection
**clist_iter
;
174 clist_iter
= clist
= connections_all_as_array(&c
->server
->connections
, NULL
);
176 connection_lock_output(c
);
177 while (*clist_iter
) {
178 connection_printf(c
, "%s from %s%s%s\n",
180 (*clist_iter
)->client_address
,
181 (*clist_iter
)->flags
& CONN_TYPE_SSL
? " (via ssl)" : "",
182 (*clist_iter
== c
) ? " <- you" : "");
183 connection_free(*clist_iter
);
186 connection_unlock_output(c
);
193 #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__)))
194 if (*command
->command
== '!') {
195 lua_State
*L
= ctx
->L
;
196 const char *echo
= (const char *) command
->command
+ 1;
199 // lemu_cosnnection_push(L, c); // c
201 // int t = lua_gettop(L);
202 // lua_pushnil(L); /* first key */
203 // while (lua_next(L, t) != 0) {
204 // /* uses 'key' (at index -2) and 'value' (at index -1) */
205 // printf("k:%s v:%s\n",
206 // lua_typename(L, lua_type(L, -2)),
207 // lua_typename(L, lua_type(L, -1)));
208 // /* removes 'value'; keeps 'key' for next iteration */
209 // switch (lua_type(L, -2)) {
211 // printf("\tk:%s\n", lua_tostring(L, -2));
214 // printf("\tk:%f\n", lua_tonumber(L, -2));
217 // printf("\tk:?\n");
219 // switch (lua_type(L, -1)) {
221 // printf("\tv:%s\n", lua_tostring(L, -1));
224 // printf("\tv:%f\n", lua_tonumber(L, -1));
227 // printf("\tv:?\n");
232 NOTIFY_DEBUG("lua echo on '%s'", echo
);
234 lemu_connection_push(L
, c
); // c
236 lua_getfield(L
, 1, "send"); // c sendfn
238 lua_rotate(L
, 1, 1); // sendfn c
240 lua_pushfstring(L
, "(lua echo) %s", echo
); // sendfn c str
245 /* default to broadcasting message */
246 connection_printf_broadcast(c
, true, "%s said: %s\n", c
->name
, command
->command
);
247 connection_printf(c
, "%s said: %s\n", "You", command
->command
);