EXPORT int tl_log_set_active(TS_Lua *ls) { if (ls!=NULL) { ts_log_set_active((schar)ts_lua_tonumber(ls,1)); return 0; } else { ts_debug(_("Invalid Lua handler"),TS_FL); return 0; } }
EXPORT int tl_log(TS_Lua *ls) { if (ls!=NULL) { ts_log((char *)ts_lua_tostring(ls,1)); return 0; } else { ts_debug(_("Invalid Lua handler"),TS_FL); return 0; } }
/** * Socketpool callback indicating that client sent some data that we need * to receive. * @param socket Socketpool socket */ void telnet_socket_client_receive(Socket socket) { unsigned char ch; TelnetClient client = (TelnetClient)socket->customData; TelnetSocketData socketdata = (TelnetSocketData)client->socketdata; enum { ESC_CODE = 0, ESC_PARAM1 = 1, ESC_PARAM2 = 2 } escState = ESC_CODE; unsigned long int escParam1 = 0; unsigned long int escParam2 = 0; char escCode = 0; while (read(socketdata->socketfd, &ch, 1) > 0) { // After each enter, 0 is send, which we don't need. if (ch == 0) continue; ts_debug("%d %x (%c) ", ch, ch, (ch >= 32 && ch < 127)?ch:' '); switch (socketdata->state) { // Normal state, receiving user input case TS_NORMAL: switch (ch) { case TS_IAC: ts_debug("IAC\n"); socketdata->state = TS_IAC; continue; case TS_ESC: ts_debug("ESC\n"); socketdata->state = TS_ESC; escState = ESC_CODE; escParam1 = 0; escParam2 = 0; escCode = 0; continue; // No special char was entered, proceed normal processing // by telnet. default: break; } break; case TS_ESC: { bool doContinue = true; switch (escState) { // Awaiting [ char case ESC_CODE: { if (ch == '[') { escState = ESC_PARAM1; } else { doContinue = false; } break; } // Awaiting number or char case ESC_PARAM1: { if (ch >= '0' && ch <= '9') { // Is digit, so it is parameter escParam1 *= 10; escParam1 += ch - '0'; } else if (ch == ';') { escState = ESC_PARAM2; } else { // It is not digit, it is end of command escCode = ch; } break; } case ESC_PARAM2: { if (ch >= '0' && ch <= '9') { // It is digit escParam2 *= 10; escParam2 += ch - '0'; } else { // Not digit, must be escape code escCode = ch; } } } if (escCode > 0) { switch (escCode) { case 'A': telnet_received(client, KEY_UP); break; case 'B': telnet_received(client, KEY_DOWN); break; case 'C': telnet_received(client, KEY_RIGHT); break; case 'D': telnet_received(client, KEY_LEFT); break; // Unknown code default: break; } } if (doContinue) { continue; } else { socketdata->state = TS_NORMAL; break; } } case TS_IAC: switch (ch) { case TS_SB: ts_debug("SB\n"); socketdata->state = TS_SB; break; case TS_WILL: ts_debug("WILL\n"); socketdata->state = TS_WILL; break; case TS_WONT: ts_debug("WONT\n"); socketdata->state = TS_WONT; break; case TS_DO: ts_debug("DO\n"); socketdata->state = TS_DO; break; case TS_DONT: ts_debug("DONT\n"); socketdata->state = TS_DONT; break; } continue; // IAC DO case TS_DO: switch (ch) { case TS_ECHO: { // Client accepted our local echo request, and will // not do local echo. ts_debug("ECHO\n"); client->opts |= TC_ECHO; break; } case TS_GOAHEAD: { ts_debug("GOAHEAD\n"); client->opts |= TC_UNBUFFERED; break; } default: ts_debug("IGNORE\n"); break; } socketdata->state = TS_NORMAL; continue; // IAC DONT case TS_DONT: ts_debug("IGNORE\n"); socketdata->state = TS_NORMAL; continue; // IAC WILL case TS_WILL: switch (ch) { case TS_NAWS: { // Client will send window size ts_debug("NAWS\n"); break; } case TS_TERMTYPE: { // Client allowes us to send terminal type ts_debug("TERMTYPE\n"); // Send VT100 terminal type char termtype[11] = { TS_IAC, TS_SB, TS_TERMTYPE, 0, 'V', 'T', '1', '0', '0', TS_IAC, TS_SE }; socketpool_send(socket->pool, socket->socketfd, termtype, 11); socketdata->hasTerm = true; break; } default: { ts_debug("IGNORE\n"); break; } } socketdata->state = TS_NORMAL; continue; // IAC WONT case TS_WONT: ts_debug("IGNORE\n"); socketdata->state = TS_NORMAL; continue; // IAC SB - Subnegotiation of parameters case TS_SB: socketdata->state = TS_IGNORE_TILL_SE; switch (ch) { case TS_NAWS: ts_debug("NAWS\n"); client->windowWidth = 0; client->windowHeight = 0; socketdata->state = TS_NAWS_WIDTH_LSB; break; default: break; } continue; case TS_NAWS_WIDTH_MSB: client->windowWidth = 0xFF * ch; socketdata->state = TS_NAWS_WIDTH_LSB; continue; case TS_NAWS_WIDTH_LSB: client->windowWidth += ch; socketdata->state = TS_NAWS_HEIGHT_LSB; continue; case TS_NAWS_HEIGHT_MSB: client->windowHeight = 0xFF * ch; socketdata->state = TS_NAWS_HEIGHT_LSB; continue; case TS_NAWS_HEIGHT_LSB: client->windowHeight += ch; client->opts |= TC_WINDOWSIZE; socketdata->state = TS_IGNORE_TILL_SE; continue; case TS_IGNORE: ts_debug("IGNORE\n"); socketdata->state = TS_NORMAL; continue; case TS_IGNORE_TILL_SE: switch (ch) { case TS_SE: ts_debug("SE\n"); socketdata->state = TS_NORMAL; break; default: ts_debug("IGNORE TILL SE\n"); break; } continue; case TS_KEYCODE1: if (ch == '[') { ts_debug("CONTROL\n"); socketdata->keycode = ch << 8; socketdata->state = TS_KEYCODE2; } else { ts_debug("NORMAL\n"); } continue; case TS_KEYCODE2: ts_debug("KEYCODE2\n"); socketdata->keycode |= ch; // 0x5b3* has 3 bytes (??) if ((socketdata->keycode & 0x7ff0) == 0x5b30) { socketdata->keycode = socketdata->keycode << 8; socketdata->state = TS_KEYCODE3; } else { //telnet_socket_keycode(client); socketdata->state = TS_NORMAL; } continue; case TS_KEYCODE3: ts_debug("KEYCODE3\n"); socketdata->keycode |= ch; //telnet_socket_keycode(client); socketdata->state = TS_NORMAL; continue; default: // Nothing special, unknown state... socketdata->state = TS_NORMAL; break; } if (ch == 127) { telnet_received(client, KEY_BACKSPACE); } else if (ch == TS_ESC) { telnet_received(client, KEY_ESC); } else { telnet_received(client, ch); // Don't read any more data, if command was completed. if (ch == KEY_ENTER) { break; } } } // If we are inside escape sequence, cancel it and treat this as escape // key. And don't care about sockets marked for closing, because they // should not receive any more data. if (!socket->shouldBeClosed) { if (socketdata->state == TS_ESC) { if (escState == ESC_CODE) { telnet_received(client, KEY_ESC); } socketdata->state = TS_NORMAL; } } } // telnet_client_receive
/** * @brief Store the new TS, calculate new values and update the state * * @param ts_sc The ts_sc_comp object * @param ts The timestamp to add * @param sn The sequence number of the RTP packet */ void c_add_ts(struct ts_sc_comp *const ts_sc, const uint32_t ts, const uint16_t sn) { uint16_t sn_delta; assert(ts_sc != NULL); ts_debug(ts_sc, "Timestamp = %u", ts); /* consider that TS bits are not deducible by default */ ts_sc->is_deducible = false; /* we save the old value */ ts_sc->old_ts = ts_sc->ts; ts_sc->old_sn = ts_sc->sn; /* we store the new value */ ts_sc->ts = ts; ts_sc->sn = sn; /* if we had no old values, TS_STRIDE cannot be computed yet */ if(!ts_sc->are_old_val_init) { assert(ts_sc->state == INIT_TS); ts_debug(ts_sc, "TS_STRIDE cannot be computed, stay in INIT_TS state"); ts_sc->are_old_val_init = true; return; } /* compute the absolute delta between new and old SN */ /* abs() on unsigned 16-bit values seems to be a problem sometimes */ if(ts_sc->sn >= ts_sc->old_sn) { sn_delta = ts_sc->sn - ts_sc->old_sn; } else { sn_delta = ts_sc->old_sn - ts_sc->sn; } ts_debug(ts_sc, "SN delta = %u", sn_delta); /* compute the absolute delta between new and old TS */ /* abs() on unsigned 32-bit values seems to be a problem sometimes */ if(ts_sc->ts >= ts_sc->old_ts) { ts_sc->ts_delta = ts_sc->ts - ts_sc->old_ts; } else { ts_sc->ts_delta = ts_sc->old_ts - ts_sc->ts; } ts_debug(ts_sc, "TS delta = %u", ts_sc->ts_delta); /* go back to INIT_TS state if TS is constant */ if(ts_sc->ts_delta == 0) { ts_debug(ts_sc, "TS is constant, go in INIT_TS state"); ts_sc->state = INIT_TS; return; } /* go back to INIT_TS state if TS_STRIDE cannot be SDVL-encoded */ if(!sdvl_can_value_be_encoded(ts_sc->ts_delta)) { /* TS_STRIDE is too large for SDVL encoding */ ts_debug(ts_sc, "TS_STRIDE is too large for SDVL encoding, " "go in INIT_TS state"); ts_sc->state = INIT_TS; return; } /* TS_STRIDE can be computed, so leave INIT_TS state */ if(ts_sc->state == INIT_TS) { ts_debug(ts_sc, "TS_STRIDE can be computed, go to INIT_STRIDE state"); ts_sc->state = INIT_STRIDE; ts_sc->nr_init_stride_packets = 0; } if(ts_sc->state == INIT_STRIDE) { /* TS is changing and TS_STRIDE can be computed but TS_STRIDE was * not transmitted enough times to the decompressor to be used */ ts_debug(ts_sc, "state INIT_STRIDE"); /* reset INIT_STRIDE counter if TS_STRIDE/TS_OFFSET changed */ if(ts_sc->ts_delta != ts_sc->ts_stride || (ts_sc->ts % ts_sc->ts_delta) != ts_sc->ts_offset) { ts_debug(ts_sc, "TS_STRIDE and/or TS_OFFSET changed"); ts_sc->nr_init_stride_packets = 0; } /* compute TS_STRIDE, TS_OFFSET and TS_SCALED */ ts_sc->ts_stride = ts_sc->ts_delta; ts_debug(ts_sc, "TS_STRIDE = %u", ts_sc->ts_stride); assert(ts_sc->ts_stride != 0); ts_sc->ts_offset = ts_sc->ts % ts_sc->ts_stride; ts_debug(ts_sc, "TS_OFFSET = %u modulo %u = %u", ts_sc->ts, ts_sc->ts_stride, ts_sc->ts_offset); assert(ts_sc->ts_stride != 0); ts_sc->ts_scaled = (ts_sc->ts - ts_sc->ts_offset) / ts_sc->ts_stride; ts_debug(ts_sc, "TS_SCALED = (%u - %u) / %u = %u", ts_sc->ts, ts_sc->ts_offset, ts_sc->ts_stride, ts_sc->ts_scaled); } else if(ts_sc->state == SEND_SCALED) { const uint32_t old_scaled = ts_sc->ts_scaled; const uint32_t old_offset = ts_sc->ts_offset; /* TS is changing, TS_STRIDE can be computed, and TS_STRIDE was * transmitted enough times to the decompressor to be used */ ts_debug(ts_sc, "state SEND_SCALED"); /* does TS_STRIDE changed? */ ts_debug(ts_sc, "TS_STRIDE calculated = %u", ts_sc->ts_delta); ts_debug(ts_sc, "previous TS_STRIDE = %u", ts_sc->ts_stride); if(ts_sc->ts_delta != ts_sc->ts_stride) { assert(ts_sc->ts_stride != 0); if((ts_sc->ts_delta % ts_sc->ts_stride) != 0) { /* TS delta changed and is not a multiple of previous TS_STRIDE: * record the new value as TS_STRIDE and transmit it several * times for robustness purposes */ ts_debug(ts_sc, "/!\\ TS_STRIDE changed and is not a multiple " "of previous TS_STRIDE, so change TS_STRIDE and " "transmit it several times along all TS bits " "(probably a clock resync at source)"); ts_sc->state = INIT_STRIDE; ts_sc->nr_init_stride_packets = 0; ts_debug(ts_sc, "state -> INIT_STRIDE"); ts_sc->ts_stride = ts_sc->ts_delta; } else if((ts_sc->ts_delta / ts_sc->ts_stride) != sn_delta) { /* TS delta changed but is a multiple of previous TS_STRIDE: * do not change TS_STRIDE, but transmit all TS bits several * times for robustness purposes */ ts_debug(ts_sc, "/!\\ TS delta changed but is a multiple of " "previous TS_STRIDE, so do not change TS_STRIDE, but " "retransmit it several times along all TS bits " "(probably a RTP TS jump at source)"); ts_sc->state = INIT_STRIDE; ts_sc->nr_init_stride_packets = 0; ts_debug(ts_sc, "state -> INIT_STRIDE"); } else { /* do not change TS_STRIDE, probably a packet loss */ ts_debug(ts_sc, "/!\\ TS delta changed, is a multiple of " "previous TS_STRIDE and follows SN changes, so do " "not change TS_STRIDE (probably a packet loss)"); } } ts_debug(ts_sc, "TS_STRIDE = %u", ts_sc->ts_stride); /* update TS_OFFSET is needed */ assert(ts_sc->ts_stride != 0); ts_sc->ts_offset = ts_sc->ts % ts_sc->ts_stride; ts_debug(ts_sc, "TS_OFFSET = %u modulo %u = %u", ts_sc->ts, ts_sc->ts_stride, ts_sc->ts_offset); /* compute TS_SCALED */ assert(ts_sc->ts_stride != 0); ts_sc->ts_scaled = (ts_sc->ts - ts_sc->ts_offset) / ts_sc->ts_stride; ts_debug(ts_sc, "TS_SCALED = (%u - %u) / %u = %u", ts_sc->ts, ts_sc->ts_offset, ts_sc->ts_stride, ts_sc->ts_scaled); /* could TS_SCALED be deduced from SN? */ if(ts_sc->state != SEND_SCALED) { ts_sc->is_deducible = false; } else { uint32_t ts_scaled_delta; /* be cautious with positive and negative deltas */ if(ts_sc->ts_scaled >= old_scaled) { ts_scaled_delta = ts_sc->ts_scaled - old_scaled; if(ts_sc->sn >= ts_sc->old_sn) { ts_sc->is_deducible = (ts_scaled_delta == sn_delta); } else { ts_sc->is_deducible = false; } } else { ts_scaled_delta = old_scaled - ts_sc->ts_scaled; if(ts_sc->old_sn >= ts_sc->sn) { ts_sc->is_deducible = (ts_scaled_delta == sn_delta); } else { ts_sc->is_deducible = false; } } } if(ts_sc->is_deducible) { ts_debug(ts_sc, "TS can be deducted from SN (old TS_SCALED = %u, " "new TS_SCALED = %u, old SN = %u, new SN = %u)", old_scaled, ts_sc->ts_scaled, ts_sc->old_sn, ts_sc->sn); } else { ts_debug(ts_sc, "TS can not be deducted from SN (old TS_SCALED = %u, " "new TS_SCALED = %u, old SN = %u, new SN = %u)", old_scaled, ts_sc->ts_scaled, ts_sc->old_sn, ts_sc->sn); } /* Wraparound (See RFC 4815 Section 4.4.3) */ if(ts_sc->ts < ts_sc->old_ts) { ts_debug(ts_sc, "TS wraparound detected"); if(old_offset != ts_sc->ts_offset) { ts_debug(ts_sc, "TS_OFFSET changed, re-initialize TS_STRIDE"); ts_sc->state = INIT_STRIDE; ts_sc->nr_init_stride_packets = 0; } else { ts_debug(ts_sc, "TS_OFFSET is unchanged"); } } } else { /* invalid state, should not happen */ ts_debug(ts_sc, "invalid state (%d), should not happen", ts_sc->state); assert(0); return; } }