From 6da1fe5fbff2e7e5fc50415dd3f18556a9df0313 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20G=C3=A4vert?= Date: Sun, 20 Nov 2016 14:37:20 +0100 Subject: [PATCH] Add support for the Mud Server Status Protocol While the protocol is somewhat dead some spiders use it. http://tintin.sourceforge.net/mssp/ --- comm.h | 1 + comm1.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ master.n | 5 ++++ parse.c | 1 - telnet.c | 67 +++++++++++++++++++++++++++++++++++++++++++++-- telnet.h | 18 ++++++++++++- 6 files changed, 168 insertions(+), 4 deletions(-) diff --git a/comm.h b/comm.h index 3e23431..7fef6a4 100644 --- a/comm.h +++ b/comm.h @@ -41,3 +41,4 @@ void remove_interactive(struct interactive *, int); void interactive_input(struct interactive *, char *); void gmcp_input(struct interactive *, char *); void *new_player(void *, struct sockaddr_storage *, socklen_t, u_short); +void mssp_request(struct interactive *ip); diff --git a/comm1.c b/comm1.c index 510d4d9..53cb6f0 100644 --- a/comm1.c +++ b/comm1.c @@ -1162,3 +1162,83 @@ gmcp_input(struct interactive *ip, char *cp) } } } + +void +mssp_request(struct interactive *ip) +{ + struct svalue *ret = NULL; + struct gdexception exception_frame; + struct allocation_pool pool = EMPTY_ALLOCATION_POOL; + + exception_frame.e_exception = NULL; + exception_frame.e_catch = 0; + + command_giver = ip->ob; + current_object = NULL; + current_interactive = command_giver; + + if (setjmp(exception_frame.e_context)) { + exception = exception_frame.e_exception; + clear_state(); + } else { + exception = &exception_frame; + push_object(ip->ob); + ret = apply_master_ob(M_INCOMING_MSSP, 1); + exception = NULL; + + if (ret == NULL || ret->type != T_MAPPING) { + printf("incoming_mssp in the master did not return a mapping\n"); + return; + } + + struct mapping *m = ret->u.map; + mssp_t *mssp[card_mapping(m)]; + size_t mssp_count = 0; + + for (int i = 0; i < m->size; i++) { + for (struct apair *p = m->pairs[i]; p; p = p->next) { + struct svalue key = p->arg; + struct svalue val = p->val; + mssp_t *variable = NULL; + + if (key.type != T_STRING) + continue; + + if (val.type == T_STRING || val.type == T_NUMBER) { + variable = pool_alloc(&pool, sizeof(mssp_t) + 1 * sizeof(char *)); + variable->name = (u_char *)key.u.string; + variable->size = 1; + + if (val.type == T_STRING) { + variable->values[0] = (u_char *)val.u.string; + } else { + size_t needed = snprintf(NULL, 0, "%lld", val.u.number) + 1; + char *str = pool_alloc(&pool, needed); + snprintf(str, needed, "%lld", val.u.number); + variable->values[0] = (u_char *)str; + } + } + + if (val.type == T_POINTER) { + variable = pool_alloc(&pool, sizeof(mssp_t) + val.u.vec->size * sizeof(char *)); + variable->name = (u_char *)key.u.string; + variable->size = val.u.vec->size; + + for (int y = 0; y < val.u.vec->size; y++) { + struct svalue *aval = &val.u.vec->item[y]; + variable->values[y] = (u_char *)""; + if (aval->type == T_STRING) { + variable->values[y] = (u_char *)aval->u.string; + } + } + } + + if (variable != NULL) + mssp[mssp_count++] = variable; + } + } + + telnet_output_mssp(ip->tp, mssp, mssp_count); + pool_free(&pool); + } +} diff --git a/master.n b/master.n index df6f59b..a62fd7a 100644 --- a/master.n +++ b/master.n @@ -91,3 +91,8 @@ object_name # gmcp ####### incoming_gmcp +# +# +# mssp +####### +incoming_mssp diff --git a/parse.c b/parse.c index 48ad1ba..1f43c9d 100644 --- a/parse.c +++ b/parse.c @@ -840,7 +840,6 @@ struct svalue * one_parse(struct vector *obvec, char *pat, struct vector *wvec, int *cix_in, int *fail, struct svalue *prep_param) { - char ch; struct svalue *pval; static struct svalue stmp = { T_NUMBER }; char *str1, *str2; diff --git a/telnet.c b/telnet.c index 48470d1..2adc048 100644 --- a/telnet.c +++ b/telnet.c @@ -67,7 +67,7 @@ #define TELNET_CANQ_SIZE (1024 * 8) #define TELNET_RAWQ_SIZE (1024 * 4) #define TELNET_OPTQ_SIZE (1024) -#define TELNET_OUTQ_SIZE (16*1024) +#define TELNET_OUTQ_SIZE (32*1024) /* * Output Queue Flow Control Parameters. @@ -294,6 +294,34 @@ telnet_output_gmcp(telnet_t *tp, u_char *cp) return 1; } + +int +telnet_output_mssp(telnet_t *tp, mssp_t *vars[], size_t count) +{ + nqueue_t *nq; + nq = tp->t_outq; + + nq_putc(nq, IAC); + nq_putc(nq, SB); + nq_putc(nq, TELOPT_MSSP); + + for (size_t i = 0; i < count; i++) { + nq_putc(nq, MSSP_VAR); + nq_puts(nq, vars[i]->name); + + for (size_t k = 0; k < vars[i]->size; k++) { + nq_putc(nq, MSSP_VAL); + nq_puts(nq, vars[i]->values[k]); + } + } + + nq_putc(nq, IAC); + nq_putc(nq, SE); + + telnet_enabw(tp); + return 1; +} + /* * Notify an interactive object that the Telnet session has been disconnected. */ @@ -529,6 +557,9 @@ telnet_get_optp(telnet_t *tp, u_char opt) case TELOPT_GMCP: return &tp->t_optb[OP_GMCP]; + case TELOPT_MSSP: + return &tp->t_optb[OP_MSSP]; + default: return NULL; } @@ -684,6 +715,8 @@ telnet_ack_lenab(telnet_t *tp, u_char opt) case TELOPT_GMCP: tp->t_flags |= TF_GMCP; break; + case TELOPT_MSSP: + break; } } @@ -861,6 +894,29 @@ telnet_disable_gmcp(telnet_t *tp) telnet_neg_ldisab(tp, TELOPT_GMCP); } +/* + * Enable MSSP + */ +void +telnet_enable_mssp(telnet_t *tp) +{ + if (nq_avail(tp->t_outq) < 3) + return; + + telnet_neg_lenab(tp, TELOPT_MSSP); +} + +/* + * Disable MSSP + */ +void +telnet_disable_mssp(telnet_t *tp) +{ + if (nq_avail(tp->t_outq) < 3) + return; + + telnet_neg_ldisab(tp, TELOPT_MSSP); +} /* * Process IAC WILL