Esempio n. 1
0
File: tcfs.cpp Progetto: djibb/indi
IPState TCFS::MoveRelFocuser(FocusDirection dir, uint32_t ticks)
{
    if (FocusModeSP.sp[0].s != ISS_ON)
    {
        LOG_WARN("The focuser can only be moved in Manual mode.");
        return IPS_ALERT;
    }

    targetTicks    = ticks;
    targetPosition = currentPosition;

    // Inward
    if (dir == FOCUS_INWARD)
    {
        targetPosition -= targetTicks;
        dispatch_command(FIN);
    }
    // Outward
    else
    {
        targetPosition += targetTicks;
        dispatch_command(FOUT);
    }

    FocusAbsPosNP.s = IPS_BUSY;
    FocusRelPosNP.s = IPS_BUSY;
    IDSetNumber(&FocusAbsPosNP, nullptr);
    IDSetNumber(&FocusRelPosNP, nullptr);

    simulated_position = targetPosition;

    return IPS_BUSY;
}
Esempio n. 2
0
static gpg_error_t
process_request (assuan_context_t ctx)
{
  gpg_error_t rc;

  if (ctx->in_inquire)
    return _assuan_error (ctx, GPG_ERR_ASS_NESTED_COMMANDS);

  do
    {
      rc = _assuan_read_line (ctx);
    }
  while (_assuan_error_is_eagain (ctx, rc));
  if (gpg_err_code (rc) == GPG_ERR_EOF)
    {
      ctx->process_complete = 1;
      return 0;
    }
  if (rc)
    return rc;
  if (*ctx->inbound.line == '#' || !ctx->inbound.linelen)
    return 0; /* comment line - ignore */

  ctx->in_command = 1;
  ctx->outbound.data.error = 0;
  ctx->outbound.data.linelen = 0;
  /* dispatch command and return reply */
  rc = dispatch_command (ctx, ctx->inbound.line, ctx->inbound.linelen);

  return assuan_process_done (ctx, rc);
}
Esempio n. 3
0
File: tcfs.cpp Progetto: djibb/indi
bool TCFS::Handshake()
{
LOGF_DEBUG("%s %s",__FUNCTION__, me);
    if (isSimulation())
    {
        LOG_INFO("TCF-S: Simulating connection.");
        currentPosition = simulated_position;
        return true;
    }
    char response[TCFS_MAX_CMD] = { 0 };
    if(SetManualMode())
    {
            dispatch_command(FWAKUP);
            read_tcfs(response);        
            tcflush(PortFD, TCIOFLUSH);
            LOG_INFO("Successfully connected to TCF-S Focuser in Manual Mode.");

            // Enable temperature readout
            FocusTemperatureNP.s = IPS_OK;

            return true;
    }
    tcflush(PortFD, TCIOFLUSH);
    LOG_ERROR("Failed connection to TCF-S Focuser.");
    return false;
}
Esempio n. 4
0
File: tcfs.cpp Progetto: djibb/indi
void TCFS::GetFocusParams()
{
    char response[TCFS_MAX_CMD] = { 0 };
    int slope;
    int is_negative;

    dispatch_command(FRSLOP, 0, MODE_A);
    read_tcfs(response);
    if(sscanf(response, "A=%04d", &slope)<=0)
    {
        LOGF_WARN("Failed to read slope A from response: %s", response);
        return;
    }
    response[0] = '\0';
    dispatch_command(FRSIGN, 0, MODE_A);
    read_tcfs(response);    
    if(sscanf(response, "A=%01d", &is_negative)<=0)
    {
        LOGF_WARN("Failed to read slope sign A from response: %s", response);
        return;
    }

    FocusModeANP.np[0].value = slope * (is_negative==1?-1:1);
    IDSetNumber(&FocusModeANP, nullptr);
        
    response[0] = '\0';
    dispatch_command(FRSLOP, 0, MODE_B);
    read_tcfs(response);
    if(sscanf(response, "B=%04d", &slope)<=0)
    {
        LOGF_WARN("Failed to read slope B from response: %s", response);
        return;
    }

    response[0] = '\0';
    dispatch_command(FRSIGN, 0, MODE_B);
    read_tcfs(response);
    if(sscanf(response, "B=%01d", &is_negative)<=0)
    {
        LOGF_WARN("Failed to read slope sign B from response: %s", response);
        return;
    }
    
    FocusModeBNP.np[0].value = slope * (is_negative==1?-1:1);
    IDSetNumber(&FocusModeBNP, nullptr);
    
}
Esempio n. 5
0
static gpg_error_t
process_next (assuan_context_t ctx)
{
  gpg_error_t rc;

  /* What the next thing to do is depends on the current state.
     However, we will always first read the next line.  The client is
     required to write full lines without blocking long after starting
     a partial line.  */
  rc = _assuan_read_line (ctx);
  if (_assuan_error_is_eagain (ctx, rc))
    return 0;
  if (gpg_err_code (rc) == GPG_ERR_EOF)
    {
      ctx->process_complete = 1;
      return 0;
    }
  if (rc)
    return rc;
  if (*ctx->inbound.line == '#' || !ctx->inbound.linelen)
     /* Comment lines are ignored.  */
    return 0;

  /* Now we have a line that really means something.  It could be one
     of the following things: First, if we are not in a command
     already, it is the next command to dispatch.  Second, if we are
     in a command, it can only be the response to an INQUIRE
     reply.  */

  if (!ctx->in_command)
    {
      ctx->in_command = 1;

      ctx->outbound.data.error = 0;
      ctx->outbound.data.linelen = 0;
      /* Dispatch command and return reply.  */
      ctx->in_process_next = 1;
      rc = dispatch_command (ctx, ctx->inbound.line, ctx->inbound.linelen);
      ctx->in_process_next = 0;
    }
  else if (ctx->in_inquire)
    {
      /* FIXME: Pick up the continuation.  */
      rc = _assuan_inquire_ext_cb (ctx);
    }
  else
    {
      /* Should not happen.  The client is sending data while we are
	 in a command and not waiting for an inquire.  We log an error
	 and discard it.  */
      TRACE0 (ctx, ASSUAN_LOG_DATA, "process_next", ctx,
	      "unexpected client data");
      rc = 0;
    }

  return rc;
}
Esempio n. 6
0
File: tcfs.cpp Progetto: djibb/indi
bool TCFS::Disconnect()
{
    FocusTemperatureNP.s = IPS_IDLE;
    IDSetNumber(&FocusTemperatureNP, nullptr);

    dispatch_command(FFMODE);

    return INDI::Focuser::Disconnect();
}
Esempio n. 7
0
/*
 *  モニタタスク
 */
void monitor(VP_INT exinf)
{
	INT  no, point;
	B    c;

	/* モニタで使用するデータの初期化 */

	mon_portid   = mon_default_portid = (ID)exinf;
	mon_datatype = DATA_BYTE;
	mon_logmask  = LOG_NOTICE;
	mon_lowmask  = LOG_EMERG;
	current_tskid = MONTASK;
	mon_infile   = stdin;

	if(mon_portid != CONSOLE_PORTID)
		syscall(serial_opn_por(mon_portid));
#ifdef NEED_MONITOR
	if(!need_monitor())
		ext_tsk();
#endif	/* NEED_MONITOR */
	_setup_stdio(&mon_portid);
#ifdef MONITOR_DELAY
	dly_tsk(MONITOR_DELAY);
#endif	/* MONITOR_DELAY */
#if defined(LOGTASK) && (LOGTASK_PRIORITY <= MONITOR_PRIORITY)
	chg_pri(LOGTASK, MONITOR_PRIORITY+1);
	dly_tsk(50);
	printf("change log task priority %d to %d !\n", LOGTASK_PRIORITY, MONITOR_PRIORITY+1);
#endif
	printf(banner,
		(TMONITOR_PRVER >> 12) & 0x0f,
		(TMONITOR_PRVER >> 4) & 0xff,
		TMONITOR_PRVER & 0x0f);
	vmsk_log(LOG_UPTO(mon_logmask), LOG_UPTO(mon_lowmask));
	syscall(serial_ctl_por(mon_portid, (IOCTL_CRLF | IOCTL_FCSND | IOCTL_FCRCV)));

	/* モニタのメインのデスパッチ */

	do{
		prompt(current_tskid);
		c = monitor_getstring(mon_command, &point);
		no = dispatch_command(mon_command, &point);
		putecho('\n');
		if(no >= 0)
			mon_dispatch[no].func(&mon_command[point]);
		fflush(NULL);
	}while(c != KEY_EXT);
	printf("exit monitor !!\n");
}
Esempio n. 8
0
int 
process_command(char *inputfilename, int lineno, int argc, char **argv)
{
    int status;

    if (argc < 1 || !argv || !argv[0]) return 1;

    if (dispatch_command (inputfilename, lineno, argc, argv,
			  command_table, &status))
      return status;

    prefix (inputfilename, lineno);
    fprintf (stderr, "unknown command \"%s\"\n", argv[0]);
    return 1;
}
Esempio n. 9
0
void
loop_cli(struct taltos_conf *arg_conf, struct book *arg_book)
{
    trace(__func__);

    char *cmd;

    assert(arg_conf != NULL && arg_book != NULL);
    conf = arg_conf;
    book = arg_book;
    init_settings();

    setup_mutexes();

    while (true) {
        if (fgets(line, sizeof line, stdin) == NULL) {
            if (exit_on_done)
                wait_thinking();
            exit(EXIT_SUCCESS);
        }

        if (line[0] == '\0')
            continue;

        if (strlen(line) == sizeof(line) - 1)
            abort();

        line[strcspn(line, "\n\r")] = '\0';

        tracef("%s input: \"%s\"", __func__, line);

        bool is_it_move;

        if ((cmd = xstrtok_r(line, " \t\n", &line_lasts)) == NULL)
            continue;

        mtx_lock(&game_mutex);

        is_it_move = (try_read_move(cmd) == 0);

        mtx_unlock(&game_mutex);

        if (!is_it_move)
            dispatch_command(cmd);
    }
}
Esempio n. 10
0
bool try_client_mode_command(const json_ref& cmd, bool pretty) {
  auto client = std::make_shared<watchman_client>();
  bool res;

  client->client_mode = true;
  res = dispatch_command(client.get(), cmd, CMD_CLIENT);

  if (!client->responses.empty()) {
    json_dumpf(
        client->responses.front(),
        stdout,
        pretty ? JSON_INDENT(4) : JSON_COMPACT);
    printf("\n");
  }

  return res;
}
Esempio n. 11
0
File: tcfs.cpp Progetto: djibb/indi
bool TCFS::SetManualMode()
{
    char response[TCFS_MAX_CMD] = { 0 };
    for(int retry=0; retry<5; retry++)
    {
        dispatch_command(FMMODE);
        read_tcfs(response);
        if (strcmp(response, "!") == 0)
        {
            tcflush(PortFD, TCIOFLUSH);
            currentMode = MANUAL;
            return true;
        }
    }
    tcflush(PortFD, TCIOFLUSH); 
    return false;
}
Esempio n. 12
0
// The client thread reads and decodes json packets,
// then dispatches the commands that it finds
static void *client_thread(void *ptr)
{
  struct watchman_client *client = ptr;
  struct watchman_event_poll pfd[2];
  json_t *request;
  json_error_t jerr;

  w_stm_set_nonblock(client->stm, true);
  w_set_thread_name("client:stm=%p", client->stm);

  w_stm_get_events(client->stm, &pfd[0].evt);
  pfd[1].evt = client->ping;

  while (!stopping) {
    // Wait for input from either the client socket or
    // via the ping pipe, which signals that some other
    // thread wants to unilaterally send data to the client

    ignore_result(w_poll_events(pfd, 2, 2000));

    if (stopping) {
      break;
    }

    if (pfd[0].ready) {
      request = w_json_buffer_next(&client->reader, client->stm, &jerr);

      if (!request && errno == EAGAIN) {
        // That's fine
      } else if (!request) {
        // Not so cool
        if (client->reader.wpos == client->reader.rpos) {
          // If they disconnected in between PDUs, no need to log
          // any error
          goto disconected;
        }
        send_error_response(client, "invalid json at position %d: %s",
            jerr.position, jerr.text);
        w_log(W_LOG_ERR, "invalid data from client: %s\n", jerr.text);

        goto disconected;
      } else if (request) {
        client->pdu_type = client->reader.pdu_type;
        dispatch_command(client, request, CMD_DAEMON);
        json_decref(request);
      }
    }

    if (pfd[1].ready) {
      w_event_test_and_clear(client->ping);
    }

    /* now send our response(s) */
    while (client->head) {
      struct watchman_client_response *resp;

      /* de-queue the first response */
      pthread_mutex_lock(&w_client_lock);
      resp = client->head;
      if (resp) {
        client->head = resp->next;
        if (client->tail == resp) {
          client->tail = NULL;
        }
      }
      pthread_mutex_unlock(&w_client_lock);

      if (resp) {
        bool ok;

        w_stm_set_nonblock(client->stm, false);

        /* Return the data in the same format that was used to ask for it */
        ok = w_ser_write_pdu(client->pdu_type, &client->writer,
            client->stm, resp->json);

        json_decref(resp->json);
        free(resp);

        w_stm_set_nonblock(client->stm, true);

        if (!ok) {
          break;
        }
      }
    }
  }

disconected:
  pthread_mutex_lock(&w_client_lock);
  w_ht_del(clients, w_ht_ptr_val(client));
  pthread_mutex_unlock(&w_client_lock);

  return NULL;
}
Esempio n. 13
0
File: tcfs.cpp Progetto: djibb/indi
void TCFS::TimerHit()
{
    static double lastPosition = -1, lastTemperature = -1000;

    if (!isConnected())
    {
        SetTimer(POLLMS);
        return;
    }
    int f_position      = 0;
    float f_temperature = 0;
    char response[TCFS_MAX_CMD] = { 0 };

    if(!isSimulation() && currentMode != MANUAL)
    {
        if (FocusTelemetrySP.sp[1].s == ISS_ON)
        {
            LOGF_DEBUG("%s %s",__FUNCTION__, "Telemetry is off");
            SetTimer(POLLMS);
            return;            
        }
        for(int i=0; i<2; i++)
        {
            if (read_tcfs(response) == false)
            {
                SetTimer(POLLMS);
                return;
            }
            LOGF_DEBUG("%s Received %s",__FUNCTION__, response);
            if(sscanf(response, "P=%d", &f_position) == 1)
            {
                currentPosition = f_position;
                if (lastPosition != currentPosition)
                {
                    lastPosition = currentPosition;
                    IDSetNumber(&FocusAbsPosNP, nullptr);
                }
            }
            else if(sscanf(response, "T=%f", &f_temperature)==1)
            {
                FocusTemperatureNP.np[0].value = f_temperature;

                if (lastTemperature != FocusTemperatureNP.np[0].value)
                {
                    lastTemperature = FocusTemperatureNP.np[0].value;
                    IDSetNumber(&FocusTemperatureNP, nullptr);
                }
            }
        }
        SetTimer(POLLMS);
        return;
    }

    if (FocusGotoSP.s == IPS_BUSY)
    {
        ISwitch *sp = IUFindOnSwitch(&FocusGotoSP);

        if (sp != nullptr && strcmp(sp->name, "FOCUS_CENTER") == 0)
        {
            bool rc = read_tcfs(response, true);

            if (!rc)
            {
                SetTimer(POLLMS);
                return;
            }

            if (isSimulation())
                strncpy(response, "CENTER", TCFS_MAX_CMD);

            if (strcmp(response, "CENTER") == 0)
            {
                IUResetSwitch(&FocusGotoSP);
                FocusGotoSP.s  = IPS_OK;
                FocusAbsPosNP.s = IPS_OK;

                IDSetSwitch(&FocusGotoSP, nullptr);
                IDSetNumber(&FocusAbsPosNP, nullptr);

                LOG_INFO("Focuser moved to center position.");
            }
        }
    }

    switch (FocusAbsPosNP.s)
    {
        case IPS_OK:
            if (FocusModeSP.sp[0].s == ISS_ON)
                dispatch_command(FPOSRO);

            if (read_tcfs(response) == false)
            {
                SetTimer(POLLMS);
                return;
            }

            if (isSimulation())
                snprintf(response, TCFS_MAX_CMD, "P=%04d", (int)simulated_position);

            sscanf(response, "P=%d", &f_position);
            currentPosition = f_position;

            if (lastPosition != currentPosition)
            {
                lastPosition = currentPosition;
                IDSetNumber(&FocusAbsPosNP, nullptr);
            }
            break;

        case IPS_BUSY:
            if (read_tcfs(response, true) == false)
            {
                SetTimer(POLLMS);
                return;
            }

            // Ignore error
            if (strstr(response, "ER") != nullptr)
            {
                LOGF_DEBUG("Received error: %s", response);
                SetTimer(POLLMS);
                return;
            }

            if (isSimulation())
                strncpy(response, "*", 2);

            if (strcmp(response, "*") == 0)
            {
                LOGF_DEBUG("Moving focuser %d steps to position %d.", targetTicks, targetPosition);
                FocusAbsPosNP.s = IPS_OK;
                FocusRelPosNP.s = IPS_OK;
                FocusGotoSP.s  = IPS_OK;
                IDSetNumber(&FocusAbsPosNP, nullptr);
                IDSetNumber(&FocusRelPosNP, nullptr);
                IDSetSwitch(&FocusGotoSP, nullptr);
            }
            else
            {
                FocusAbsPosNP.s = IPS_ALERT;
                LOGF_ERROR("Unable to read response from focuser #%s#.", response);
                IDSetNumber(&FocusAbsPosNP, nullptr);
            }
            break;

        default:
            break;
    }

    if (FocusTemperatureNP.s != IPS_IDLE)
    {
        // Read Temperature
        // Manual Mode
        if (FocusModeSP.sp[0].s == ISS_ON)
            dispatch_command(FTMPRO);

        if (read_tcfs(response) == false)
        {
            SetTimer(POLLMS);
            return;
        }

        if (isSimulation())
            snprintf(response, TCFS_MAX_CMD, "T=%0.1f", simulated_temperature);

        sscanf(response, "T=%f", &f_temperature);

        FocusTemperatureNP.np[0].value = f_temperature;

        if (lastTemperature != FocusTemperatureNP.np[0].value)
        {
            lastTemperature = FocusTemperatureNP.np[0].value;
            IDSetNumber(&FocusTemperatureNP, nullptr);
        }
    }

    SetTimer(POLLMS);
}
Esempio n. 14
0
/* returns:
 *  <0 for error
 *     -1 out of memory
 *     -2 other
 *   0 for async dispatched
 *   1 for command completed (connection can be closed)
 */
int execute_or_dispatch_command(client_conn_t *conn, enum commands cmd, const char *argument)
{
    int desc = conn->sd;
    char term = conn->term;
    const struct cl_engine *engine = conn->engine;
    /* execute commands that can be executed quickly on the recvloop thread,
     * these must:
     *  - not involve any operation that can block for a long time, such as disk
     *  I/O
     *  - send of atomic message is allowed.
     * Dispatch other commands */
    if (conn->group) {
	switch (cmd) {
	    case COMMAND_FILDES:
	    case COMMAND_SCAN:
	    case COMMAND_END:
	    case COMMAND_INSTREAM:
	    case COMMAND_INSTREAMSCAN:
	    case COMMAND_VERSION:
	    case COMMAND_PING:
	    case COMMAND_STATS:
	    case COMMAND_COMMANDS:
		/* These commands are accepted inside IDSESSION */
		break;
	    default:
		/* these commands are not recognized inside an IDSESSION */
		conn_reply_error(conn, "Command invalid inside IDSESSION.");
		logg("$SESSION: command is not valid inside IDSESSION: %d\n", cmd);
		conn->group = NULL;
		return 1;
	}
    }

    switch (cmd) {
	case COMMAND_SHUTDOWN:
	    pthread_mutex_lock(&exit_mutex);
	    progexit = 1;
	    pthread_mutex_unlock(&exit_mutex);
	    return 1;
	case COMMAND_RELOAD:
	    pthread_mutex_lock(&reload_mutex);
	    reload = 1;
	    pthread_mutex_unlock(&reload_mutex);
	    mdprintf(desc, "RELOADING%c", term);
	    /* we set reload flag, and we'll reload before closing the
	     * connection */
	    return 1;
	case COMMAND_PING:
	    if (conn->group)
		mdprintf(desc, "%u: PONG%c", conn->id, term);
	    else
		mdprintf(desc, "PONG%c", term);
	    return conn->group ? 0 : 1;
	case COMMAND_VERSION:
	    {
		if (conn->group)
		    mdprintf(desc, "%u: ", conn->id);
		print_ver(desc, conn->term, engine);
		return conn->group ? 0 : 1;
	    }
	case COMMAND_COMMANDS:
	    {
		if (conn->group)
		    mdprintf(desc, "%u: ", conn->id);
		print_commands(desc, conn->term, engine);
		return conn->group ? 0 : 1;
	    }
	case COMMAND_DETSTATSCLEAR:
	    {
		detstats_clear();
		return 1;
	    }
	case COMMAND_DETSTATS:
	    {
		detstats_print(desc, conn->term);
		return 1;
	    }
	case COMMAND_INSTREAM:
	    {
		int rc = cli_gentempfd(optget(conn->opts, "TemporaryDirectory")->strarg, &conn->filename, &conn->scanfd);
		if (rc != CL_SUCCESS)
		    return rc;
		conn->quota = optget(conn->opts, "StreamMaxLength")->numarg;
		conn->mode = MODE_STREAM;
		return 0;
	    }
	case COMMAND_STREAM:
	case COMMAND_MULTISCAN:
	case COMMAND_CONTSCAN:
	case COMMAND_STATS:
	case COMMAND_FILDES:
	case COMMAND_SCAN:
	case COMMAND_INSTREAMSCAN:
	    return dispatch_command(conn, cmd, argument);
	case COMMAND_IDSESSION:
	    conn->group = thrmgr_group_new();
	    if (!conn->group)
		return CL_EMEM;
	    return 0;
	case COMMAND_END:
	    if (!conn->group) {
		/* end without idsession? */
		conn_reply_single(conn, NULL, "UNKNOWN COMMAND");
		return 1;
	    }
	    /* need to close connection  if we were last in group */
	    return 1;
	/*case COMMAND_UNKNOWN:*/
	default:
	    conn_reply_single(conn, NULL, "UNKNOWN COMMAND");
	    return 1;
    }
}
Esempio n. 15
0
// The client thread reads and decodes json packets,
// then dispatches the commands that it finds
static void *client_thread(void *ptr)
{
  struct watchman_client *client = ptr;
  struct watchman_event_poll pfd[2];
  struct watchman_client_response *queued_responses_to_send;
  json_t *request;
  json_error_t jerr;
  bool send_ok = true;

  w_stm_set_nonblock(client->stm, true);
  w_set_thread_name("client=%p:stm=%p", client, client->stm);

  client->client_is_owner = w_stm_peer_is_owner(client->stm);

  w_stm_get_events(client->stm, &pfd[0].evt);
  pfd[1].evt = client->ping;

  while (!stopping) {
    // Wait for input from either the client socket or
    // via the ping pipe, which signals that some other
    // thread wants to unilaterally send data to the client

    ignore_result(w_poll_events(pfd, 2, 2000));

    if (stopping) {
      break;
    }

    if (pfd[0].ready) {
      request = w_json_buffer_next(&client->reader, client->stm, &jerr);

      if (!request && errno == EAGAIN) {
        // That's fine
      } else if (!request) {
        // Not so cool
        if (client->reader.wpos == client->reader.rpos) {
          // If they disconnected in between PDUs, no need to log
          // any error
          goto disconected;
        }
        send_error_response(client, "invalid json at position %d: %s",
            jerr.position, jerr.text);
        w_log(W_LOG_ERR, "invalid data from client: %s\n", jerr.text);

        goto disconected;
      } else if (request) {
        client->pdu_type = client->reader.pdu_type;
        dispatch_command(client, request, CMD_DAEMON);
        json_decref(request);
      }
    }

    if (pfd[1].ready) {
      w_event_test_and_clear(client->ping);
    }

    /* de-queue the pending responses under the lock */
    pthread_mutex_lock(&w_client_lock);
    queued_responses_to_send = client->head;
    client->head = NULL;
    client->tail = NULL;
    pthread_mutex_unlock(&w_client_lock);

    /* now send our response(s) */
    while (queued_responses_to_send) {
      struct watchman_client_response *response_to_send =
        queued_responses_to_send;

      if (send_ok) {
        w_stm_set_nonblock(client->stm, false);
        /* Return the data in the same format that was used to ask for it.
         * Don't bother sending any more messages if the client disconnects,
         * but still free their memory.
         */
        send_ok = w_ser_write_pdu(client->pdu_type, &client->writer,
                                  client->stm, response_to_send->json);
        w_stm_set_nonblock(client->stm, true);
      }

      queued_responses_to_send = response_to_send->next;

      json_decref(response_to_send->json);
      free(response_to_send);
    }
  }

disconected:
  w_set_thread_name("NOT_CONN:client=%p:stm=%p", client, client->stm);
  // Remove the client from the map before we tear it down, as this makes
  // it easier to flush out pending writes on windows without worrying
  // about w_log_to_clients contending for the write buffers
  pthread_mutex_lock(&w_client_lock);
  w_ht_del(clients, w_ht_ptr_val(client));
  pthread_mutex_unlock(&w_client_lock);

  client_delete(client);

  return NULL;
}
Esempio n. 16
0
/* use a binary search to find the table in the entry */
static int find_handler(unsigned int tag)
{
    int     min = 0, max = Protocol_Size - 1, try;

    while (!global.sigCaught)
    {
        try = (max + min) / 2;
        if(tag == Protocol[try].message)
            return try;
        else if(min == max)
            return -1;      /* not found */
        else if(tag < Protocol[try].message)
        {
            if(try == min)
                return -1;
            max = try - 1;
        }
        else
        {
            if(try == max)
                return -1;
            min = try + 1;
        }
        ASSERT(min <= max);
    }
    return -1;
}

/* this is not a real handler, but takes the same arguments as one */
HANDLER(dispatch_command)
{
    int     l;
    tag_count_t *tagcount = 0;
    int     tagDelta;
    u_char  byte;

    ASSERT(validate_connection(con));
    ASSERT(pkt != 0);

    /* HACK ALERT
    the handler routines all assume that the `pkt' argument is nul (\0)
    terminated, so we have to replace the byte after the last byte in
    this packet with a \0 to make sure we dont read overflow in the
    handlers.  the handle_connection() function should always allocate 1
    byte more than necessary for this purpose */
    ASSERT(VALID_LEN(con->recvbuf->data, con->recvbuf->consumed + 4 + len + 1));
    stats.tags++;
    byte = *(pkt + len);
    *(pkt + len) = 0;
    l = find_handler(tag);
    if(l != -1)
    {
        ASSERT(Protocol[l].handler != 0);
        if(ISUSER(con))
        {
            tagcount = hash_lookup(con->user->tagCountHash, (void *) tag);
            if(!tagcount)
            {
                tagcount = CALLOC(1, sizeof(tag_count_t));
                tagcount->count = 0;
                tagcount->lastInterval = global.current_time;
                hash_add(con->user->tagCountHash, (void *) tag, tagcount );
            }
            tagcount->count++;
            if(tagcount->count % 1000 == 0)
            {
                tagDelta =  global.current_time - tagcount->lastInterval;
                if(tagDelta == 0)
                    tagDelta = 1;
                if((1000 / tagDelta) >= 100)
                    log_message_level(LOG_LEVEL_ERROR, "dispatch_command: %s has done \"%s\"(%hu) %lu times (%d/sec)", con->user->nick, tag2hrf(tag), tag, tagcount->count, 1000/tagDelta);
                tagcount->lastInterval = global.current_time;
            }
        }
        else if(ISSERVER(con))
        {
            tagcount = hash_lookup(con->sopt->tagCountHash, (void *) tag);
            if(!tagcount)
            {
                tagcount = CALLOC(1, sizeof(tag_count_t));
                tagcount->count = 0;
                tagcount->lastInterval = global.current_time;
                hash_add(con->sopt->tagCountHash, (void *) tag, tagcount );
            }
            tagcount->count++;
            if(tagcount->count % 1000 == 0)
            {
                tagcount->flag = 0;
                tagDelta =  global.current_time - tagcount->lastInterval;
                if(tagDelta == 0)
                    tagDelta = 1;
                if((1000 / tagDelta) >= 200)
                {
                    log_message_level(LOG_LEVEL_ERROR, "dispatch_command: %s has done \"%s\"(%hu) %lu times (%d/sec)", con->host, tag2hrf(tag), tag, tagcount->count, 1000/tagDelta);
                    tagcount->flag = 1;
                }
                tagcount->lastInterval = global.current_time;
            }
        }
        /*
        if(tag == 10018 || (tag != 2 && (tagcount && tagcount->flag)))
        {
        int     i;
        char    message[4096];

        i=0;
        while (i<=len-1) 
        {
        message[i] = isprint(pkt[i]) ? pkt[i] : '.';
        i++;
        }
        message[i]=0;
        log_message_level(LOG_LEVEL_ERROR, "dispatch_command: tag: %d, pkt: %s", tag, message);
        }
        */
        /* do flood control if enabled */
        if(global.floodTime > 0 && !(Protocol[l].flags & F_EXEMPT) && ISUSER(con))
        {
            /* this command is subject to flood control. */
            if(con->flood_start + global.floodTime < global.current_time)
            {
                /* flood expired, reset counters */
                con->flood_start = global.current_time;
                con->flood_commands = 0;
            }
            else if(++con->flood_commands >= global.floodCommands)
            {
                LIST   *list;

                log_message_level( LOG_LEVEL_CLIENT, "dispatch_command: flooding from %s %s(%hu)", get_user(con, 2), tag2hrf(tag), tag);
                notify_mods(FLOODLOG_MODE, "Flooding from %s!%s %s(%hu)", con->user->nick, con->host, tag2hrf(tag), tag );
                /* stop reading from the descriptor until the flood counter
                * expires.
                */
                clear_read(con->fd);

                /* add to the list of flooders that is check in the main
                * loop.  Since we don't traverse the entire client list we
                * have to keep track of which ones to check for expiration
                */
                list = CALLOC(1, sizeof(LIST));
                list->data = con;
                global.flooderList = list_push(global.flooderList, list);
            }
        }

        /* This is to get some info where e.g. pop_user is called from...  */
        global.current_tag = tag;
        /*
        i=0;
        while (i<=len-1) 
		{
        message[i] = isprint(pkt[i]) ? pkt[i] : '.';
        i++;
        }
        message[i]=0;
        log_message("%hu:R:%hu(%s)\t:%hu:\t%s", con->fd, tag, tag2hrf(tag), len+4, message);
        */
        /* note that we pass only the data part of the packet */
        Protocol[l].handler(con, tag, len, pkt);
        Protocol[l].count++;
        Protocol[l].bytes += len+4;
    }
    else
    {
        log_message_level(LOG_LEVEL_ERROR | LOG_LEVEL_SERVER, "dispatch_command: unknown message: tag=%hu, length=%hu, data=%s", tag, len, pkt);
        unknown_numeric.message = tag;
        unknown_numeric.count++;
        unknown_numeric.bytes += len+4;

        send_cmd(con, MSG_SERVER_NOSUCH, "Unknown command code %hu", tag);
#if ONAP_DEBUG
        /* if this is a server connection, shut it down to avoid flooding the
        other server with these messages */
        if(ISSERVER(con))
        {
            u_char  ch;
            int     bytes;

            /* dump some bytes from the input buffer to see if it helps aid
            debugging */
            bytes = con->recvbuf->datasize - con->recvbuf->consumed;
            /* print at most 128 bytes */
            if(bytes > 128)
                bytes = 128;
            fprintf(stdout, "Dump(%d): ", con->recvbuf->datasize - con->recvbuf->consumed);
            for (l = con->recvbuf->consumed; bytes > 0; bytes--, l++)
            {
                ch = *(con->recvbuf->data + l);
                fputc(isprint(ch) ? ch : '.', stdout);
            }
            fputc('\n', stdout);
        }
#endif /* ONAP_DEBUG */
    }
    /* restore the byte we overwrite at the beginning of this function */
    *(pkt + len) = byte;
}

void handle_connection(CONNECTION * con)
{
    int     n;
    u_short tag, len;
    /* char*   msg[4096]; */

    ASSERT(validate_connection(con));

#ifdef CSC
    if(ISUSER(con)) 
	{
        if(con->uopt->csc) 
		{
            do 
			{
                n = READ(con->fd, Buf, sizeof(Buf));
                if(n <= 0) 
				{
                    if(n == -1) 
					{
                        if(N_ERRNO == EWOULDBLOCK)
                            break;
                        log_message_level(LOG_LEVEL_ERROR, "handle_connection_z: read: %s (errno %d) for host %s (fd %d)", strerror(N_ERRNO), N_ERRNO, con->host, con->fd);
                    } 
					else 
					{
                        log_message_level(LOG_LEVEL_ERROR, "handle_connection_z: EOF from %s", con->user->nick);
                    }
                    destroy_connection(con);
                    return;
                }
                global.bytes_in += n;
                if(global.min_read > 0 && n < global.min_read) 
				{
                    log_message_level(LOG_LEVEL_ERROR, "handle_connection_z: %d bytes from %s", n, con->host);
                }
                if(buffer_decompress(con->recvbuf, con->uopt->zin, Buf, n)) 
				{
                    destroy_connection(con);
                    return;
                }
            } while (n == sizeof(Buf));
            goto dcomp_ok;
        }
    }
#endif

    if(ISSERVER(con)) 
    {
        /* server data is compressed.  read as much as we can and pass it
        to the decompressor.  we attempt to read all data from the socket
        in this loop, which will prevent unnecessary passes through the
        main loop (since select would return immediately) */
        do
        {
            n = READ(con->fd, Buf, sizeof(Buf));
            if(n <= 0)
            {
                if(n == -1)
                {
                    /* try to empty the socket each time, so we read until
                    *  we hit this error (queue empty).  this should only
                    *  happen in the rare event that the data in the queue
                    *  is a multiple of sizeof(Buf)
                    */
                    if(N_ERRNO == EWOULDBLOCK)
                        break;  /* not an error */
                    log_message_level(LOG_LEVEL_ERROR, "handle_connection: read: %s (errno %d) for host %s (fd %d)", strerror(N_ERRNO), N_ERRNO, con->host, con->fd);
                }
                else
                    log_message_level(LOG_LEVEL_SERVER | LOG_LEVEL_ERROR , "handle_connection: EOF from %s", con->host);
                destroy_connection(con);
                return;
            }
            global.bytes_in += n;

            if(global.min_read > 0 && n < global.min_read)
            {
                log_message_level(LOG_LEVEL_ERROR | LOG_LEVEL_SERVER, "handle_connection: %d bytes from %s", n, con->host);
            }

            /* this can safely be called multiple times in this loop.  the
            * decompressor will realloc the output buffer if there is not
            * enough room to store everything
            */
            if(buffer_decompress(con->recvbuf, con->sopt->zin, Buf, n))
            {
                destroy_connection(con);
                return;
            }
            /* if what we read was equal to sizeof(Buf) it's very likely
            * that more data exists in the queue
            */
        } while (n == sizeof(Buf));
    }
    else
    {
        /* create the input buffer if it doesn't yet exist */
        if(!con->recvbuf)
        {
            con->recvbuf = CALLOC(1, sizeof(BUFFER));
            if(!con->recvbuf)
            {
                OUTOFMEMORY("handle_connection");
                destroy_connection(con);
                return;
            }
#if ONAP_DEBUG
            con->recvbuf->magic = MAGIC_BUFFER;
#endif
            con->recvbuf->data = MALLOC(RECVBUF_INITAL_SIZE + 1);
            if(!con->recvbuf->data)
            {
                OUTOFMEMORY("handle_connection");
                destroy_connection(con);
                return;
            }
            con->recvbuf->datamax = RECVBUF_INITAL_SIZE;
        }
        /* read the packet header if we haven't seen it already */
        while (con->recvbuf->datasize < 4)
        {
            n = READ(con->fd, con->recvbuf->data + con->recvbuf->datasize, 4 - con->recvbuf->datasize);
            if(n == -1)
            {
                if(N_ERRNO != EWOULDBLOCK)
                {
                    log_message_level(LOG_LEVEL_ERROR | LOG_LEVEL_SERVER, "handle_connection: read: %s (errno %d) for host %s", strerror(N_ERRNO), N_ERRNO, con->host);
                    destroy_connection(con);
                }
                return;
            }
            else if(n == 0)
            {
                destroy_connection(con);
                return;
            }
            global.bytes_in += n;
            con->recvbuf->datasize += n;
        }
        /* read the packet body */
        memcpy(&len, con->recvbuf->data, 2);
        len = BSWAP16(len);
        if(len > 0)
        {
            if(global.maxCommandLen && len > global.maxCommandLen)
            {
                log_message_level(LOG_LEVEL_ERROR | LOG_LEVEL_SERVER, "handle_connection: %hu byte message from %s", len, con->host);
                destroy_connection(con);
                return;
            }

            /* if there isn't enough space to read the entire body, resize the input buffer */
            if(con->recvbuf->datamax < 4 + len)
            {
                /* allocate 1 extra byte for the \0 that dispatch_command() requires */
                if(safe_realloc((void **) &con->recvbuf->data, 4 + len + 1))
                {
                    OUTOFMEMORY("handle_connection");
                    destroy_connection(con);
                    return;
                }
                con->recvbuf->datamax = 4 + len;
            }
            n = READ(con->fd, con->recvbuf->data + con->recvbuf->datasize, len + 4 - con->recvbuf->datasize);
            if(n == -1)
            {
                /* since the header and body could arrive in separate packets, we have to check for this here so we don't close the
                *  connection on this nonfatal error.  we just wait for the next packet to arrive 
                */
                if(N_ERRNO != EWOULDBLOCK)
                {
                    log_message_level(LOG_LEVEL_ERROR | LOG_LEVEL_SERVER, "handle_connection: read: %s (errno %d) for host %s", strerror(N_ERRNO), N_ERRNO, con->host);
                    destroy_connection(con);
                }
                return;
            }
            else if(n == 0)
            {
                log_message_level(LOG_LEVEL_ERROR, "handle_connection: EOF from %s", con->host);
                destroy_connection(con);
                return;
            }
            con->recvbuf->datasize += n;
            global.bytes_in += n;
        }
    }
    /* process as many complete commands as possible.  for a client this
    will be exactly one, but a server link may have sent multiple commands
    in one compressed packet */
#ifdef CSC
dcomp_ok:
#endif
    while (con->recvbuf->consumed < con->recvbuf->datasize)
    {
        /* if we don't have the complete packet header, wait until we
        read more data */
        if(con->recvbuf->datasize - con->recvbuf->consumed < 4)
            break;
        /* read the packet header */
        memcpy(&len, con->recvbuf->data + con->recvbuf->consumed, 2);
        memcpy(&tag, con->recvbuf->data + con->recvbuf->consumed + 2, 2);
        len = BSWAP16(len);
        tag = BSWAP16(tag);
        /* check if the entire packet body has arrived */
        if(con->recvbuf->consumed + 4 + len > con->recvbuf->datasize)
            break;
        /*
        bzero( msg, 4096 );
        memcpy(&msg, con->recvbuf->data + con->recvbuf->consumed + 4, len);
        log_message_level( LOG_LEVEL_DEBUG, "recv: [%u] %s (%u)", tag, msg, len);
        */
        /* require that the client register before doing anything else */
        if(con->class == CLASS_UNKNOWN &&
            (tag != MSG_CLIENT_LOGIN && tag != MSG_CLIENT_LOGIN_REGISTER &&
            tag != MSG_CLIENT_REGISTER && tag != MSG_SERVER_LOGIN &&
            tag != MSG_SERVER_LOGIN_ACK && tag != MSG_SERVER_ERROR &&
            tag != 4 && /* unknown: v2.0 beta 5a sends this? */
            tag != 300 && tag != 11 && tag != 920))
        {
            log_message_level(LOG_LEVEL_ERROR, "handle_connection: %s is not registered", con->host);
            *(con->recvbuf->data + con->recvbuf->consumed + 4 + len) = 0;
            log_message_level(LOG_LEVEL_ERROR, "handle_connection: tag=%hu, len=%hu, data=%s", tag, len, con->recvbuf->data + con->recvbuf->consumed + 4);
            send_cmd(con, MSG_SERVER_ERROR, "invalid command");
            destroy_connection(con);
            return;
        }

        if(ISUSER(con))
        {
            /* check for end of share/unshare sequence.  in order to avoid
            having to send a single message for each shared file,
            the add_file and remove_file commands set a flag noting the
            start of a possible series of commands.  this routine checks
            to see if the end of the sequence has been reached (a command
            other than share/unshare has been issued) and then relays
            the final result to the peer servers.
            NOTE: the only issue with this is that if the user doesn't
            issue any commands after sharing files, the information will
            never get passed to the peer servers.  This is probably ok
            since this case will seldom happen */
            if(con->user->sharing)
            {
                if(tag != MSG_CLIENT_ADD_FILE
                    && tag != MSG_CLIENT_SHARE_FILE
                    && tag != MSG_CLIENT_ADD_DIRECTORY)
                {
                    pass_message_args(con, MSG_SERVER_USER_SHARING, "%s %hu %u", con->user->nick, con->user->shared, con->user->libsize);
                    con->user->sharing = 0;
                }
            }
            else if(con->user->unsharing)
            {
                if(tag != MSG_CLIENT_REMOVE_FILE)
                {
                    pass_message_args(con, MSG_SERVER_USER_SHARING, "%s %hu %u", con->user->nick, con->user->shared, con->user->libsize);
                    con->user->unsharing = 0;
                }
            }
        }
        /* call the protocol handler */
        dispatch_command(con, tag, len, con->recvbuf->data + con->recvbuf->consumed + 4);
        /* mark data as processed */
        con->recvbuf->consumed += 4 + len;
    }
    if(con->recvbuf->consumed)
    {
        n = con->recvbuf->datasize - con->recvbuf->consumed;
        if(n > 0)
        {
            /* shift down unprocessed data */
            memmove(con->recvbuf->data, con->recvbuf->data + con->recvbuf->consumed, n);
        }
        con->recvbuf->datasize = n;
        con->recvbuf->consumed = 0; /* reset */
    }
}

char* tag2hrf(int tag) 
{
	switch (tag) 
	{
	case MSG_SERVER_ERROR:
		return "server error";       /* 0 */
	case MSG_CLIENT_LOGIN:
		return "login";          /* 2 */
	case MSG_SERVER_EMAIL:
		return "login ack";      /* 3 */
	case MSG_CLIENT_VERSION_CHECK:
		return "version_check";      /* 4 */
	case MSG_CLIENT_LOGIN_REGISTER:
		return "register login"; /* 6 */
	case MSG_CLIENT_REGISTER:
		return "register nick";      /* 7 */
	case MSG_SERVER_REGISTER_OK:
		return "register ok";        /* 8 */
	case MSG_SERVER_REGISTER_FAIL:
		return "register fail";      /* 9 */
	case MSG_SERVER_BAD_NICK:
		return "bad nick";       /* 10 */
	case MSG_CLIENT_CHECK_PASS:
		return "check_password"; /* 11 */
	case MSG_SERVER_PASS_OK:
		return "password ok";        /* 12 */
	case MSG_SERVER_ECHO:
		return "server echo";        /* 13 */
	case MSG_CLIENT_REGISTRATION_INFO:
		return "ignore_command"; /* 14 */
#ifndef ROUTING_ONLY
	case MSG_CLIENT_ADD_FILE:
		return "add_file";       /* 100 */
	case MSG_CLIENT_REMOVE_FILE:
		return "remove_file";        /* 102 */
#endif
	case MSG_CLIENT_UNSHARE_ALL:
		return "unshare_all";        /* 110 */
#ifndef ROUTING_ONLY
	case MSG_CLIENT_SEARCH:
		return "search";     /* 200 */
#endif
	case MSG_SERVER_SEARCH_RESULT:
		return "search result";      /* 201 */
	case MSG_SERVER_SEARCH_END:
		return "search end";     /* 202 */
	case MSG_CLIENT_DOWNLOAD:
		return "download";       /* 203 */
	case MSG_SERVER_FILE_READY:
		return "file ready";     /* 204 */
	case MSG_CLIENT_PRIVMSG:
		return "privmsg";        /* 205 */
	case MSG_SERVER_SEND_ERROR:
		return "send error";     /* 206 */
	case MSG_CLIENT_ADD_HOTLIST:
		return "add_hotlist";        /* 207 */
	case MSG_CLIENT_ADD_HOTLIST_SEQ:
		return "add_hotlist";        /* 208 */
	case MSG_SERVER_USER_SIGNON:
		return "user signon";        /* 209 */
	case MSG_SERVER_USER_SIGNOFF:
		return "user signoff";       /* 210 */
	case MSG_CLIENT_BROWSE:
		return "browse";     /* 211 */
	case MSG_SERVER_BROWSE_RESPONSE:
		return "browse response";    /* 212 */
	case MSG_SERVER_BROWSE_END:
		return "browse end";     /* 213 */
	case MSG_SERVER_STATS:
		return "server stats";       /* 214 */
	case MSG_CLIENT_RESUME_REQUEST:
		return "resume request"; /* 215 */
	case MSG_SERVER_RESUME_MATCH:
		return "resume match";       /* 216 */
	case MSG_SERVER_RESUME_MATCH_END:
		return "resume match end";   /* 217 */
	case MSG_CLIENT_DOWNLOAD_START:
		return "download start"; /* 218 */
	case MSG_CLIENT_DOWNLOAD_END:
		return "download end";       /* 219 */
	case MSG_CLIENT_UPLOAD_START:
		return "upload start";       /* 220 */
	case MSG_CLIENT_UPLOAD_END:
		return "upload end";     /* 221 */
	case MSG_CLIENT_CHECK_PORT:
		return "check port (ignored)";   /* 300 */
	case MSG_SERVER_HOTLIST_ACK:
		return "hotlist ack";        /* 301 */
	case MSG_SERVER_HOTLIST_ERROR:
		return "hotlist error";      /* 302 */
	case MSG_CLIENT_REMOVE_HOTLIST:
		return "remove_hotlist"; /* 303 */
	case MSG_SERVER_DISCONNECTING:
		return "disconnecting";      /* 316 */
	case MSG_CLIENT_IGNORE_LIST:
		return "ignore list";        /* 320 */
	case MSG_SERVER_IGNORE_ENTRY:
		return "ignore entry";       /* 321 */
	case MSG_CLIENT_IGNORE_USER:
		return "ignore user";        /* 322 */
	case MSG_CLIENT_UNIGNORE_USER:
		return "unignore user";      /* 323 */
	case MSG_SERVER_NOT_IGNORED:
		return "not ignored";        /* 324 */
	case MSG_SERVER_ALREADY_IGNORED:
		return "already ignored";    /* 325 */
	case MSG_CLIENT_CLEAR_IGNORE:
		return "clear ignore";       /* 326 */
	case MSG_CLIENT_JOIN:
		return "join";           /* 400 */
	case MSG_CLIENT_PART:
		return "part";           /* 401 */
	case MSG_CLIENT_PUBLIC:
		return "public";     /* 402 */
	case MSG_SERVER_PUBLIC:
		return "public";     /* 403 */
	case MSG_SERVER_NOSUCH:
		return "server error";       /* 404 */
	case MSG_SERVER_JOIN_ACK:
		return "chan join ack";      /* 405 */
	case MSG_SERVER_JOIN:
		return "chan join";      /* 406 */
	case MSG_SERVER_PART:
		return "chan part";      /* 407 */
	case MSG_SERVER_CHANNEL_USER_LIST:
		return "chan list";      /* 408 */
	case MSG_SERVER_CHANNEL_USER_LIST_END:
		return "chan list end";      /* 409 */
	case MSG_SERVER_TOPIC:
		return "chan topic";     /* 410 */
	case MSG_CLIENT_CHANNEL_BAN_LIST:
		return "chan banlist";       /* 420 */
	case MSG_SERVER_CHANNEL_BAN_LIST:
		return "chan banlist";       /* 421 */
	case MSG_CLIENT_CHANNEL_BAN:
		return "chan ban";       /* 422 */
	case MSG_CLIENT_CHANNEL_UNBAN:
		return "chan unban";     /* 423 */
	case MSG_CLIENT_CHANNEL_CLEAR_BANS:
		return "chan clear bans";    /* 424 */
	case MSG_CLIENT_DOWNLOAD_FIREWALL:
		return "download firewall";  /* 500 */
	case MSG_SERVER_UPLOAD_FIREWALL:
		return "upload firewall";    /* 501 */
	case MSG_CLIENT_USERSPEED:
		return "user speed";     /* 600 */
	case MSG_SERVER_USER_SPEED:
		return "user speed";     /* 601 */
	case MSG_CLIENT_WHOIS:
		return "whois";          /* 603 */
	case MSG_SERVER_WHOIS_RESPONSE:
		return "whois";          /* 604 */
	case MSG_SERVER_WHOWAS:
		return "whowas";     /* 605 */
	case MSG_CLIENT_SETUSERLEVEL:
		return "level";          /* 606 */
	case MSG_SERVER_UPLOAD_REQUEST:
		return "upload request"; /* 607 */
	case MSG_CLIENT_UPLOAD_OK:
		return "upload ok";      /* 608 */
	case MSG_CLIENT_ACCEPT_FAILED:
		return "accept failed";      /* 609 */
	case MSG_CLIENT_KILL:
		return "kill";           /* 610 */
	case MSG_CLIENT_NUKE:
		return "nuke";           /* 611 */
	case MSG_CLIENT_BAN:
		return "ban";            /* 612 */
	case MSG_CLIENT_ALTER_PORT:
		return "alter port";     /* 613 */
	case MSG_CLIENT_UNBAN:
		return "unban";          /* 614 */
	case MSG_CLIENT_BANLIST:
		return "banlist";        /* 615 */
	case MSG_SERVER_IP_BANLIST:
		return "ip banlist";     /* 616 */
	case MSG_SERVER_CHANNEL_LIST_END:
		return "chan list end";      /* 617 */
	case MSG_SERVER_CHANNEL_LIST:
		return "chan list";      /* 618 */
	case MSG_CLIENT_LIMIT:
		return "queue limit";        /* 619 */
	case MSG_SERVER_LIMIT:
		return "queue limit";        /* 620 */
	case MSG_CLIENT_MOTD:
		return "motd";           /* 621 */
	case MSG_CLIENT_MUZZLE:
		return "muzzle";     /* 622 */
	case MSG_CLIENT_UNMUZZLE:
		return "unmuzzle";       /* 623 */
	case MSG_CLIENT_UNNUKE:
		return "unnuke?";        /* 624 */
	case MSG_CLIENT_ALTER_SPEED:
		return "alter speed";        /* 625 */
	case MSG_CLIENT_DATA_PORT_ERROR:
		return "data port error";    /* 626 */
	case MSG_CLIENT_WALLOP:
		return "wallop";     /* 627 */
	case MSG_CLIENT_ANNOUNCE:
		return "announce";       /* 628 */
	case MSG_SERVER_NICK_BANLIST:
		return "nick banlist";       /* 629 */
	case MSG_CLIENT_BROWSE_DIRECT:
		return "browse direct";      /* 640 */
	case MSG_SERVER_BROWSE_DIRECT_OK:
		return "browse direct ok";   /* 641 */
	case MSG_SERVER_BROWSE_DIRECT_ERR:
		return "browse direct error";    /* 642 */
	case MSG_CLIENT_CLOAK:
		return "cloak";          /* 652 */
	case MSG_CLIENT_CHANGE_SPEED:
		return "change_speed";       /* 700 */
	case MSG_CLIENT_CHANGE_PASS:
		return "change_pass";        /* 701 */
	case MSG_CLIENT_CHANGE_EMAIL:
		return "change_email";       /* 702 */
	case MSG_CLIENT_CHANGE_DATA_PORT:
		return "change_data_port";   /* 703 */
	case MSG_SERVER_GHOST:
		return "ghost";          /* 748 */
	case MSG_CLIENT_PING_SERVER:
		return "ping server";        /* 750 */
	case MSG_CLIENT_PING:
		return "ping";           /* 751 */
	case MSG_CLIENT_PONG:
		return "pong";           /* 752 */
	case MSG_CLIENT_ALTER_PASS:
		return "alter pass";     /* 753 */
	case MSG_CLIENT_SERVER_RECONFIG:
		return "server reconfig";    /* 800 */
	case MSG_CLIENT_SERVER_VERSION:
		return "server version"; /* 801 */
	case MSG_CLIENT_SERVER_CONFIG:
		return "server config";      /* 810 */
	case MSG_CLIENT_CLEAR_CHANNEL:
		return "clear channel";      /* 820 */
	case MSG_CLIENT_REDIRECT:
		return "redirect client";    /* 821 */
	case MSG_CLIENT_CYCLE:
		return "cycle client";       /* 822 */
	case MSG_CLIENT_SET_CHAN_LEVEL:
		return "channel level";      /* 823 */
	case MSG_CLIENT_EMOTE:
		return "emote";          /* 824 */
	case MSG_SERVER_NAMES_LIST:
		return "names list";     /* 825 */
	case MSG_CLIENT_CHANNEL_LIMIT:
		return "channel limit";      /* 826 */
	case MSG_CLIENT_FULL_CHANNEL_LIST:
		return "full chan list"; /* 827 */
	case MSG_SERVER_FULL_CHANNEL_INFO:
		return "full chan info"; /* 828 */
	case MSG_CLIENT_KICK:
		return "kick";           /* 829 */
	case MSG_CLIENT_NAMES_LIST:
		return "list users";     /* 830 */
	case MSG_CLIENT_GLOBAL_USER_LIST:
		return "global user list";   /* 831 */
	case MSG_SERVER_GLOBAL_USER_LIST:
		return "global user list";   /* 832 */
#ifndef ROUTING_ONLY
	case MSG_CLIENT_ADD_DIRECTORY:
		return "add_directory";      /* 870 */
#endif
	case 920:
		return "ignore_command"; /* 920 */
	case MSG_CLIENT_ADD_SERVER:
		return "add server";     /* 9998 */
	case MSG_CLIENT_LIST_SERVER:
		return "list server";        /* 9999 */
	case MSG_CLIENT_QUIT:
		return "client quit";        /* 10000 */
	case MSG_SERVER_LOGIN:
		return "server login";       /* 10010 */
	case MSG_SERVER_LOGIN_ACK:
		return "server login ack";   /* 10011 */
	case MSG_SERVER_USER_SHARING:
		return "user sharing";       /* 10012 */
	case MSG_SERVER_USER_IP:
		return "user ip";        /* 10013 */
	case MSG_SERVER_REGINFO:
		return "reginfo";        /* 10014 */
	case MSG_SERVER_REMOTE_SEARCH:
		return "remote search";      /* 10015 */
	case MSG_SERVER_REMOTE_SEARCH_RESULT:
		return "remote search result";   /* 10016 */
	case MSG_SERVER_REMOTE_SEARCH_END:
		return "remote search end";  /* 10017 */
	case MSG_SERVER_ENCAPSULATED:
		return "encapsulated";       /* 10018 */
	case MSG_SERVER_LINK_INFO:
		return "link info";      /* 10019 */
	case MSG_SERVER_QUIT:
		return "server disconnect";  /* 10020 - deprecated by 10101 */
	case MSG_SERVER_NOTIFY_MODS:
		return "remote notify_mods"; /* 10021 */
	case MSG_SERVER_SERVER_PONG:
		return "server pong";        /* 10022 */
	case MSG_SERVER_TIME_CHECK:
		return "time check";     /* 10023 */
	case MSG_SERVER_WHOIS_NOTIFY:
		return "whois notify";       /* 10024 */
	case MSG_CLIENT_USERFLAGS:
		return "change userflags";   /* 10050 */
	case MSG_CLIENT_CONNECT:
		return "server connect"; /* 10100 */
	case MSG_CLIENT_DISCONNECT:
		return "server disconnect";  /* 10101 */
	case MSG_CLIENT_KILL_SERVER:
		return "kill server";        /* 10110 */
	case MSG_CLIENT_REMOVE_SERVER:
		return "remove server";      /* 10111 */
	case MSG_CLIENT_LINKS:
		return "server links";       /* 10112 */
	case MSG_CLIENT_USAGE_STATS:
		return "server usage";       /* 10115 */
	case MSG_SERVER_SEARCH_STATS:
		return "search cache stats"; /* 10116 */
	case MSG_CLIENT_REHASH:
		return "rehash";     /* 10117 */
	case MSG_CLIENT_VERSION_STATS:
		return "client version stats";   /* 10118 */
	case MSG_CLIENT_WHICH_SERVER:
		return "which server";       /* 10119 */
	case MSG_CLIENT_PING_ALL_SERVERS:
		return "ping all servers";   /* 10120 */
	case MSG_CLIENT_WHO_WAS:
		return "whowas";     /* 10121 */
	case MSG_CLIENT_MASS_KILL:
		return "mass kill";      /* 10122 */
	case MSG_CLIENT_HISTOGRAM:
		return "histogram recv"; /* 10123 */
	case MSG_SERVER_HISTOGRAM:
		return "histogram recv end"; /* 10124 */
	case MSG_CLIENT_SHISTOGRAM:
		return "histogram send"; /* 10125 */ 
	case MSG_SERVER_SHISTOGRAM:
		return "histogram send end"; /* 10126 */ 
	case MSG_CLIENT_REGISTER_USER:
		return "register user";      /* 10200 */
	case MSG_CLIENT_USER_MODE:
		return "user mode cmd";      /* 10203 */
	case MSG_CLIENT_OP:
		return "chan op";        /* 10204 */
	case MSG_CLIENT_DEOP:
		return "chan deop";      /* 10205 */
	case MSG_CLIENT_CHANNEL_WALLOP:
		return "chan wallop";        /* 10208 */
	case MSG_CLIENT_CHANNEL_MODE:
		return "chan mode";      /* 10209 */
	case MSG_CLIENT_CHANNEL_INVITE:
		return "chan invite";        /* 10210 */
	case MSG_CLIENT_CHANNEL_VOICE:
		return "chan voice";     /* 10211 */
	case MSG_CLIENT_CHANNEL_UNVOICE:
		return "chan unvoice";       /* 10212 */
	case MSG_CLIENT_CHANNEL_MUZZLE:
		return "chan muzzle";        /* 10213 */
	case MSG_CLIENT_CHANNEL_UNMUZZLE:
		return "chan unmuzzle";      /* 10214 */
	case MSG_CLIENT_CLASS_ADD:
		return "acl generic add";    /* 10250 */
	case MSG_CLIENT_CLASS_DEL:
		return "acl generic del";    /* 10251 */
	case MSG_CLIENT_CLASS_LIST:
		return "acl generic list";   /* 10252 */
	case MSG_CLIENT_DLINE_ADD:
		return "acl d-line add"; /* 10253 */
	case MSG_CLIENT_DLINE_DEL:
		return "acl d-line del"; /* 10254 */
	case MSG_CLIENT_DLINE_LIST:
		return "acl d-line list";    /* 10255 */
	case MSG_CLIENT_ILINE_ADD:
		return "acl i-line add"; /* 10256 */
	case MSG_CLIENT_ILINE_DEL:
		return "acl i-line del"; /* 10257 */
	case MSG_CLIENT_ILINE_LIST:
		return "acl i-line list";    /* 10258 */
	case MSG_CLIENT_ELINE_ADD:
		return "acl e-line add"; /* 10259 */
	case MSG_CLIENT_ELINE_DEL:
		return "acl e-line del"; /* 10260 */
	case MSG_CLIENT_ELINE_LIST:
		return "acl e-line list";    /* 10261 */
	case MSG_SERVER_SYNC_END:
		return "server sync end";    /* 10262 */
	case MSG_SERVER_SYNC_END_ACK:      
		return "server sync end ack";/* 10263 */
	case MSG_CLIENT_LOG_LEVEL:
		return "change log level";
	case MSG_CLIENT_SHARE_FILE:
		return "share generic file"; /* 10300 */
	case MSG_CLIENT_BROWSE_NEW:
		return "browse new";     /* 10301 */
	case MSG_SERVER_BROWSE_RESULT_NEW:
		return "browse result new";  /* 10302 */
#ifdef USE_PROTNET  
	case MSG_CLIENT_RESYNC_USER:
		return "resync user";        /* 10303 */
	case MSG_CLIENT_DESYNC_USER:
		return "desync user";        /* 10304 */
#endif
	}
	return "unknown";
}

void add_shist( unsigned int tag, unsigned int len ) 
{
    LIST        *list;
    histogram_t *h;

    for (list = global.histOutList; list; list = list->next) 
	{
        h = list->data;
        if(tag == h->tag) 
		{
            h->count++;
            h->len += len;
            return;
        }
    }

    /* tag not found add one */
    while (1) 
    {   
        h = CALLOC(1, sizeof(histogram_t));
        if(!h)
            break;
        h->tag = tag;
        h->count = 1;
        h->len = len;
        list = CALLOC(1, sizeof(LIST));
        if(!list)
            break;
        list->data = h;
        list->next = global.histOutList;
        global.histOutList = list;
        return;
    }

    OUTOFMEMORY("add_shist");
    if(h)
        FREE(h);
    if(list)
        FREE(list);
    return;
}
Esempio n. 17
0
// The client thread reads and decodes json packets,
// then dispatches the commands that it finds
static void *client_thread(void *ptr)
{
  struct watchman_client *client = ptr;
  struct pollfd pfd[2];
  json_t *request;
  json_error_t jerr;
  char buf[16];

  w_set_nonblock(client->fd);

  while (true) {
    // Wait for input from either the client socket or
    // via the ping pipe, which signals that some other
    // thread wants to unilaterally send data to the client

    pfd[0].fd = client->fd;
    pfd[0].events = POLLIN|POLLHUP|POLLERR;
    pfd[0].revents = 0;

    pfd[1].fd = client->ping[0];
    pfd[1].events = POLLIN|POLLHUP|POLLERR;
    pfd[1].revents = 0;

    ignore_result(poll(pfd, 2, 200));

    if (pfd[0].revents & (POLLHUP|POLLERR)) {
disconected:
      pthread_mutex_lock(&w_client_lock);
      w_ht_del(clients, client->fd);
      pthread_mutex_unlock(&w_client_lock);
      break;
    }

    if (pfd[0].revents) {
      request = w_json_buffer_next(&client->reader, client->fd, &jerr);

      if (!request && errno == EAGAIN) {
        // That's fine
      } else if (!request) {
        // Not so cool
        send_error_response(client, "invalid json at position %d: %s",
            jerr.position, jerr.text);
        w_log(W_LOG_ERR, "invalid data from client: %s\n", jerr.text);

        goto disconected;
      } else if (request) {
        client->pdu_type = client->reader.pdu_type;
        dispatch_command(client, request);
        json_decref(request);
      }
    }

    if (pfd[1].revents) {
      ignore_result(read(client->ping[0], buf, sizeof(buf)));
    }

    /* now send our response(s) */
    while (client->head) {
      struct watchman_client_response *resp;

      /* de-queue the first response */
      pthread_mutex_lock(&w_client_lock);
      resp = client->head;
      if (resp) {
        client->head = resp->next;
        if (client->tail == resp) {
          client->tail = NULL;
        }
      }
      pthread_mutex_unlock(&w_client_lock);

      if (resp) {
        w_clear_nonblock(client->fd);

        /* Return the data in the same format that was used to ask for it */
        w_ser_write_pdu(client->pdu_type, &client->writer,
            client->fd, resp->json);

        json_decref(resp->json);
        free(resp);

        w_set_nonblock(client->fd);
      }
    }
  }

  return NULL;
}
Esempio n. 18
0
File: tcfs.cpp Progetto: djibb/indi
bool TCFS::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
{
//LOGF_DEBUG("%s %s",__FUNCTION__, me);
    //  first check if it's for our device
    if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
    {
        char response[TCFS_MAX_CMD] = { 0 };

        if (!strcmp(name, FocusModeANP.name))
        {
            IUUpdateNumber(&FocusModeANP, values, names, n);

            dispatch_command(FLSLOP, FocusModeAN[0].value, MODE_A);
            if (read_tcfs(response) == false)
            {
                FocusModeANP.s = IPS_ALERT;
                IDSetNumber(&FocusModeANP, "Error reading TCF-S reply.");
                return true;
            }
            dispatch_command(FLSIGN, FocusModeAN[0].value, MODE_A);
            if (read_tcfs(response) == false)
            {
                FocusModeANP.s = IPS_ALERT;
                IDSetNumber(&FocusModeANP, "Error reading TCF-S reply.");
                return true;
            }
            //saveConfig();
            dispatch_command(FDELAY, FocusModeAN[1].value*100, MODE_A);
            if (read_tcfs(response) == false)
            {
                FocusModeANP.s = IPS_ALERT;
                IDSetNumber(&FocusModeANP, "Error reading TCF-S reply.");
                return true;
            }
            //saveConfig();
            FocusModeANP.s = IPS_OK;
            IDSetNumber(&FocusModeANP, nullptr);

            return true;
        }
        if (!strcmp(name, FocusModeBNP.name))
        {
            IUUpdateNumber(&FocusModeBNP, values, names, n);

            dispatch_command(FLSLOP, FocusModeBN[0].value, MODE_B);
            if (read_tcfs(response) == false)
            {
                FocusModeBNP.s = IPS_ALERT;
                IDSetNumber(&FocusModeBNP, "Error reading TCF-S reply.");
                return true;
            }
            dispatch_command(FLSIGN, FocusModeBN[0].value, MODE_B);
            if (read_tcfs(response) == false)
            {
                FocusModeBNP.s = IPS_ALERT;
                IDSetNumber(&FocusModeBNP, "Error reading TCF-S reply.");
                return true;
            }
            dispatch_command(FDELAY, FocusModeBN[1].value*100, MODE_B);
            if (read_tcfs(response) == false)
            {
                FocusModeBNP.s = IPS_ALERT;
                IDSetNumber(&FocusModeBNP, "Error reading TCF-S reply.");
                return true;
            }
            //saveConfig();
            FocusModeBNP.s = IPS_OK;
            IDSetNumber(&FocusModeBNP, nullptr);

            return true;
        }
    }

    return Focuser::ISNewNumber(dev, name, values, names, n);
}
Esempio n. 19
0
// The client thread reads and decodes json packets,
// then dispatches the commands that it finds
static void *client_thread(void *ptr)
{
  struct watchman_client *client = ptr;
  struct pollfd pfd[2];
  json_t *request;
  json_error_t jerr;
  char buf[16];

  w_set_nonblock(client->fd);

  while (!stopping) {
    // Wait for input from either the client socket or
    // via the ping pipe, which signals that some other
    // thread wants to unilaterally send data to the client

    pfd[0].fd = client->fd;
    pfd[0].events = POLLIN|POLLHUP|POLLERR;
    pfd[0].revents = 0;

    pfd[1].fd = client->ping[0];
    pfd[1].events = POLLIN|POLLHUP|POLLERR;
    pfd[1].revents = 0;

    ignore_result(poll(pfd, 2, 200));

    if (stopping) {
      break;
    }

    if (pfd[0].revents & (POLLHUP|POLLERR)) {
      w_log(W_LOG_DBG, "got HUP|ERR on client %p fd=%d, disconnecting\n",
          client, client->fd);
      break;
    }

    if (pfd[0].revents) {
      // Solaris: we may not detect POLLHUP until we try to read, so
      // let's peek ahead and characterize it correctly.  This is only
      // needed if we have no data buffered
      if (client->reader.wpos == client->reader.rpos) {
        char peek;
        if (recv(client->fd, &peek, sizeof(peek), MSG_PEEK) == 0) {
          w_log(W_LOG_DBG, "got HUP|ERR on client fd=%d, disconnecting\n",
            client->fd);
          goto disconected;
        }
      }

      request = w_json_buffer_next(&client->reader, client->fd, &jerr);

      if (!request && errno == EAGAIN) {
        // That's fine
      } else if (!request) {
        // Not so cool
        send_error_response(client, "invalid json at position %d: %s",
            jerr.position, jerr.text);
        w_log(W_LOG_ERR, "invalid data from client: %s\n", jerr.text);

        goto disconected;
      } else if (request) {
        client->pdu_type = client->reader.pdu_type;
        dispatch_command(client, request, CMD_DAEMON);
        json_decref(request);
      }
    }

    if (pfd[1].revents) {
      ignore_result(read(client->ping[0], buf, sizeof(buf)));
    }

    /* now send our response(s) */
    while (client->head) {
      struct watchman_client_response *resp;

      /* de-queue the first response */
      pthread_mutex_lock(&w_client_lock);
      resp = client->head;
      if (resp) {
        client->head = resp->next;
        if (client->tail == resp) {
          client->tail = NULL;
        }
      }
      pthread_mutex_unlock(&w_client_lock);

      if (resp) {
        w_clear_nonblock(client->fd);

        /* Return the data in the same format that was used to ask for it */
        w_ser_write_pdu(client->pdu_type, &client->writer,
            client->fd, resp->json);

        json_decref(resp->json);
        free(resp);

        w_set_nonblock(client->fd);
      }
    }
  }

disconected:
  pthread_mutex_lock(&w_client_lock);
  w_ht_del(clients, client->fd);
  pthread_mutex_unlock(&w_client_lock);

  return NULL;
}
Esempio n. 20
0
File: tcfs.cpp Progetto: djibb/indi
bool TCFS::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
{
//LOGF_DEBUG("%s %s",__FUNCTION__, me);
    if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
    {
        char response[TCFS_MAX_CMD] = { 0 };

        if (!strcmp(FocusPowerSP.name, name))
        {
            IUUpdateSwitch(&FocusPowerSP, states, names, n);
            bool sleep = false;

            ISwitch *sp = IUFindOnSwitch(&FocusPowerSP);

            // Sleep
            if (!strcmp(sp->name, "FOCUS_SLEEP"))
            {
                dispatch_command(FSLEEP);
                sleep = true;
            }
            // Wake Up
            else
                dispatch_command(FWAKUP);

            if (read_tcfs(response) == false)
            {
                IUResetSwitch(&FocusPowerSP);
                FocusPowerSP.s = IPS_ALERT;
                IDSetSwitch(&FocusPowerSP, "Error reading TCF-S reply.");
                return true;
            }

            if (sleep)
            {
                if (isSimulation())
                    strncpy(response, "ZZZ", TCFS_MAX_CMD);

                if (strcmp(response, "ZZZ") == 0)
                {
                    FocusPowerSP.s = IPS_OK;
                    IDSetSwitch(&FocusPowerSP, "Focuser is set into sleep mode.");
                    FocusAbsPosNP.s = IPS_IDLE;
                    IDSetNumber(&FocusAbsPosNP, nullptr);
//                    if (FocusTemperatureNP)
                    {
                        FocusTemperatureNP.s = IPS_IDLE;
                        IDSetNumber(&FocusTemperatureNP, nullptr);
                    }

                    return true;
                }
                else
                {
                    FocusPowerSP.s = IPS_ALERT;
                    IDSetSwitch(&FocusPowerSP, "Focuser sleep mode operation failed. Response: %s.", response);
                    return true;
                }
            }
            else
            {
                if (isSimulation())
                    strncpy(response, "WAKE", TCFS_MAX_CMD);

                if (strcmp(response, "WAKE") == 0)
                {
                    FocusPowerSP.s = IPS_OK;
                    IDSetSwitch(&FocusPowerSP, "Focuser is awake.");
                    FocusAbsPosNP.s = IPS_OK;
                    IDSetNumber(&FocusAbsPosNP, nullptr);
//                    if (FocusTemperatureNP)
                    {
                        FocusTemperatureNP.s = IPS_OK;
                        IDSetNumber(&FocusTemperatureNP, nullptr);
                    }

                    return true;
                }
                else
                {
                    FocusPowerSP.s = IPS_ALERT;
                    IDSetSwitch(&FocusPowerSP, "Focuser wake up operation failed. Response: %s", response);
                    return true;
                }
            }
        }

        // Do not process any command if focuser is asleep
        if (isConnected() && FocusPowerSP.sp[0].s == ISS_ON)
        {
            ISwitchVectorProperty *svp = getSwitch(name);
            if (svp)
            {
                svp->s = IPS_IDLE;
                LOG_WARN("Focuser is still in sleep mode. Wake up in order to issue commands.");
                IDSetSwitch(svp, nullptr);
            }
            return true;
        }

        if (!strcmp(FocusModeSP.name, name))
        {
            IUUpdateSwitch(&FocusModeSP, states, names, n);
            FocusModeSP.s = IPS_OK;

            ISwitch *sp = IUFindOnSwitch(&FocusModeSP);

            if (!strcmp(sp->name, "Manual"))
            {
                if (!isSimulation() && !SetManualMode())
                {
                    IUResetSwitch(&FocusModeSP);
                    FocusModeSP.s = IPS_ALERT;
                    IDSetSwitch(&FocusModeSP, "Error switching to manual mode. No reply from TCF-S. Try again.");
                    return true;
                }
            }
            else if (!strcmp(sp->name, "Auto A"))
            {
                dispatch_command(FAMODE);
                read_tcfs(response);
                if (!isSimulation() && strcmp(response, "A") != 0)
                {
                    IUResetSwitch(&FocusModeSP);
                    FocusModeSP.s = IPS_ALERT;
                    IDSetSwitch(&FocusModeSP, "Error switching to Auto Mode A. No reply from TCF-S. Try again.");
                    return true;
                }
                LOG_INFO("Entered Auto Mode A");
                currentMode = MODE_A;
            }
            else
            {
                dispatch_command(FBMODE);
                read_tcfs(response);
                if (!isSimulation() && strcmp(response, "B") != 0)
                {
                    IUResetSwitch(&FocusModeSP);
                    FocusModeSP.s = IPS_ALERT;
                    IDSetSwitch(&FocusModeSP, "Error switching to Auto Mode B. No reply from TCF-S. Try again.");
                    return true;
                }
                LOG_INFO("Entered Auto Mode B");
                currentMode = MODE_B;
            }

            IDSetSwitch(&FocusModeSP, nullptr);
            return true;
        }

        if (!strcmp(FocusGotoSP.name, name))
        {
            if (FocusModeSP.sp[0].s != ISS_ON)
            {
                FocusGotoSP.s = IPS_IDLE;
                IDSetSwitch(&FocusGotoSP, nullptr);
                LOG_WARN("The focuser can only be moved in Manual mode.");
                return false;
            }

            IUUpdateSwitch(&FocusGotoSP, states, names, n);
            FocusGotoSP.s = IPS_BUSY;

            ISwitch *sp = IUFindOnSwitch(&FocusGotoSP);

            // Min
            if (!strcmp(sp->name, "FOCUS_MIN"))
            {
                targetTicks = currentPosition;
                MoveRelFocuser(FOCUS_INWARD, currentPosition);
                IDSetSwitch(&FocusGotoSP, "Moving focuser to minimum position...");
            }
            // Center
            else if (!strcmp(sp->name, "FOCUS_CENTER"))
            {
                dispatch_command(FCENTR);
                FocusAbsPosNP.s = FocusRelPosNP.s = IPS_BUSY;
                IDSetNumber(&FocusAbsPosNP, nullptr);
                IDSetNumber(&FocusRelPosNP, nullptr);
                IDSetSwitch(&FocusGotoSP, "Moving focuser to center position %d...", isTCFS3 ? 5000 : 3500);
                return true;
            }
            // Max
            else if (!strcmp(sp->name, "FOCUS_MAX"))
            {
                unsigned int delta = 0;
                delta              = FocusAbsPosN[0].max - currentPosition;
                MoveRelFocuser(FOCUS_OUTWARD, delta);
                IDSetSwitch(&FocusGotoSP, "Moving focuser to maximum position %g...", FocusAbsPosN[0].max);
            }
            // Home
            else if (!strcmp(sp->name, "FOCUS_HOME"))
            {
                dispatch_command(FHOME);
                read_tcfs(response);

                if (isSimulation())
                    strncpy(response, "DONE", TCFS_MAX_CMD);

                if (strcmp(response, "DONE") == 0)
                {
                    IUResetSwitch(&FocusGotoSP);
                    FocusGotoSP.s = IPS_OK;
                    IDSetSwitch(&FocusGotoSP, "Moving focuser to new calculated position based on temperature...");
                    return true;
                }
                else
                {
                    IUResetSwitch(&FocusGotoSP);
                    FocusGotoSP.s = IPS_ALERT;
                    IDSetSwitch(&FocusGotoSP, "Failed to move focuser to home position!");
                    return true;
                }
            }

            IDSetSwitch(&FocusGotoSP, nullptr);
            return true;
        }
        // handle quiet mode on/off
        if (!strcmp(FocusTelemetrySP.name, name))
        {
            IUUpdateSwitch(&FocusTelemetrySP, states, names, n);


            bool quiet = false;

            ISwitch *sp = IUFindOnSwitch(&FocusTelemetrySP);

            // Telemetry off
            if (!strcmp(sp->name, "FOCUS_TELEMETRY_OFF"))
            {
                dispatch_command(FQUIET, 1);
                quiet = true;
            }
            // Telemetry On
            else
                dispatch_command(FQUIET, 0);

            if (read_tcfs(response) == false)
            {
                IUResetSwitch(&FocusTelemetrySP);
                FocusTelemetrySP.s = IPS_ALERT;
                IDSetSwitch(&FocusTelemetrySP, "Error reading TCF-S reply.");
                return true;
            }

            if (isSimulation())
                strncpy(response, "DONE", TCFS_MAX_CMD);

            if (strcmp(response, "DONE") == 0)
            {
                FocusTelemetrySP.s = IPS_OK;
                IDSetSwitch(&FocusTelemetrySP, 
                        quiet ? "Focuser Telemetry is off." : "Focuser Telemetry is on.");
//                if (FocusTemperatureNP)
                {
                    FocusTemperatureNP.s = quiet?IPS_IDLE:IPS_OK;
                    IDSetNumber(&FocusTemperatureNP, nullptr);
                }
                return true;
            }
            else
            {
                FocusTelemetrySP.s = IPS_ALERT;
                IDSetSwitch(&FocusTelemetrySP, "Focuser telemetry mode failed. Response: %s.", response);
                return true;
            }
        }
    }
    return INDI::Focuser::ISNewSwitch(dev, name, states, names, n);
}