Example #1
0
/** Process a timer on client socket.
 * @param ev Timer event that has a struct Connection as its
 * associated data.
 */
static void client_timer_callback(struct Event* ev)
{
  struct Client* cptr;
  struct Connection* con;

  assert(0 != ev_timer(ev));
  assert(0 != t_data(ev_timer(ev)));
  assert(ET_DESTROY == ev_type(ev) || ET_EXPIRE == ev_type(ev));

  con = (struct Connection*) t_data(ev_timer(ev));

  assert(0 != con_client(con) || ev_type(ev) == ET_DESTROY);

  cptr = con_client(con);

  assert(0 == cptr || con == cli_connect(cptr));

  if (ev_type(ev)== ET_DESTROY) {
    con_freeflag(con) &= ~FREEFLAG_TIMER; /* timer has expired... */

    if (!con_freeflag(con) && !cptr)
      free_connection(con); /* client is being destroyed */
  } else {
    Debug((DEBUG_LIST, "Client process timer for %C expired; processing",
	   cptr));
    read_packet(cptr, 0); /* read_packet will re-add timer if needed */
  }

  assert(0 == cptr || 0 == cli_connect(cptr) || con == cli_connect(cptr));
}
Example #2
0
/** Timer callback to send another outbound uping.
 * @param[in] ev Event for uping timer.
 */
static void uping_sender_callback(struct Event* ev)
{
  struct UPing *pptr;

  assert(0 != ev_timer(ev));
  assert(0 != t_data(ev_timer(ev)));

  pptr = (struct UPing*) t_data(ev_timer(ev));

  Debug((DEBUG_SEND, "uping_sender_callback called, %p (%d)", pptr,
	 ev_type(ev)));

  if (ev_type(ev) == ET_DESTROY) { /* being destroyed */
    pptr->freeable &= ~UPING_PENDING_SENDER;

    if (!pptr->freeable)
      MyFree(pptr); /* done with it, finally */
  } else {
    assert(ev_type(ev) == ET_EXPIRE);

    pptr->lastsent = CurrentTime; /* store last ping time */
    uping_send(pptr); /* send a ping */

    if (pptr->sent == pptr->count) /* done sending pings, don't send more */
      timer_del(ev_timer(ev));
  }
}
Example #3
0
/** Timer callback to stop upings.
 * @param[in] ev Event for uping expiration.
 */
static void uping_killer_callback(struct Event* ev)
{
  struct UPing *pptr;

  assert(0 != ev_timer(ev));
  assert(0 != t_data(ev_timer(ev)));

  pptr = (struct UPing*) t_data(ev_timer(ev));

  Debug((DEBUG_SEND, "uping_killer_callback called, %p (%d)", pptr,
	 ev_type(ev)));

  if (ev_type(ev) == ET_DESTROY) { /* being destroyed */
    pptr->freeable &= ~UPING_PENDING_KILLER;

    if (!pptr->freeable)
      MyFree(pptr); /* done with it, finally */
  } else {
    assert(ev_type(ev) == ET_EXPIRE);

    uping_end(pptr); /* <FUDD>kill the uping, kill the uping!</FUDD> */
  }
}
/*
 * auth_timeout - timeout a given auth request
 */
static void auth_timeout_callback(struct Event* ev)
{
  struct AuthRequest* auth;

  assert(0 != ev_timer(ev));
  assert(0 != t_data(ev_timer(ev)));

  auth = t_data(ev_timer(ev));

  if (ev_type(ev) == ET_DESTROY) { /* being destroyed */
    auth->flags &= ~AM_TIMEOUT;

    if (!(auth->flags & AM_FREE_MASK)) {
      Debug((DEBUG_LIST, "Freeing auth from timeout callback; %p [%p]", auth,
	     ev_timer(ev)));
      MyFree(auth); /* done with it, finally */
    }
  } else {
    assert(ev_type(ev) == ET_EXPIRE);

    destroy_auth_request(auth, 1);
  }
}
Example #5
0
/** Periodic timer callback to check for expired registry entries.
 * @param[in] ev Timer event (ignored).
 */
static void ip_registry_expire(struct Event* ev)
{
  int i;
  struct IPRegistryEntry* entry;
  struct IPRegistryEntry* entry_next;

  assert(ET_EXPIRE == ev_type(ev));
  assert(0 != ev_timer(ev));

  for (i = 0; i < IP_REGISTRY_TABLE_SIZE; ++i) {
    for (entry = hashTable[i]; entry; entry = entry_next) {
      entry_next = entry->next;
      if (0 == entry->connected)
        ip_registry_expire_entry(entry);
    }
  }
}
Example #6
0
/** Decrement the error count (once per hour).
 * @param[in] ev Expired timer event (ignored).
 */
static void
error_clear(struct Event* ev)
{
  if (!--errors) /* remove timer when error count reaches 0 */
    timer_del(ev_timer(ev));
}
Example #7
0
/** Check for clients that have not sent a ping response recently.
 * Reschedules itself to run again at the appropriate time.
 * @param[in] ev Timer event (ignored).
 */
static void check_pings(struct Event* ev) {
  int expire     = 0;
  int next_check = CurrentTime;
  int max_ping   = 0;
  int i;

  assert(ET_EXPIRE == ev_type(ev));
  assert(0 != ev_timer(ev));

  next_check += feature_int(FEAT_PINGFREQUENCY);
  
  /* Scan through the client table */
  for (i=0; i <= HighestFd; i++) {
    struct Client *cptr = LocalClientArray[i];
   
    if (!cptr)
      continue;
     
    assert(&me != cptr);  /* I should never be in the local client array! */
   

    /* Remove dead clients. */
    if (IsDead(cptr)) {
      exit_client(cptr, cptr, &me, cli_info(cptr));
      continue;
    }

    max_ping = IsRegistered(cptr) ? client_get_ping(cptr) :
      feature_int(FEAT_CONNECTTIMEOUT);
   
    Debug((DEBUG_DEBUG, "check_pings(%s)=status:%s limit: %d current: %d",
	   cli_name(cptr),
	   IsPingSent(cptr) ? "[Ping Sent]" : "[]", 
	   max_ping, (int)(CurrentTime - cli_lasttime(cptr))));

    /* If it's a server and we have not sent an AsLL lately, do so. */
    if (IsServer(cptr)) {
      if (CurrentTime - cli_serv(cptr)->asll_last >= max_ping) {
        char *asll_ts;

        SetPingSent(cptr);
        cli_serv(cptr)->asll_last = CurrentTime;
        expire = cli_serv(cptr)->asll_last + max_ping;
        asll_ts = militime_float(NULL);
        sendcmdto_prio_one(&me, CMD_PING, cptr, "!%s %s %s", asll_ts,
                           cli_name(cptr), asll_ts);
      }

      expire = cli_serv(cptr)->asll_last + max_ping;
      if (expire < next_check)
        next_check = expire;
    }

    /* Ok, the thing that will happen most frequently, is that someone will
     * have sent something recently.  Cover this first for speed.
     * -- 
     * If it's an unregistered client and hasn't managed to register within
     * max_ping then it's obviously having problems (broken client) or it's
     * just up to no good, so we won't skip it, even if its been sending
     * data to us. 
     * -- hikari
     */
    if ((CurrentTime-cli_lasttime(cptr) < max_ping) && IsRegistered(cptr)) {
      expire = cli_lasttime(cptr) + max_ping;
      if (expire < next_check) 
	next_check = expire;
      continue;
    }

    /* Unregistered clients pingout after max_ping seconds, they don't
     * get given a second chance - if they were then people could not quite
     * finish registration and hold resources without being subject to k/g
     * lines
     */
    if (!IsRegistered(cptr)) {
      assert(!IsServer(cptr));
      /* If client authorization time has expired, ask auth whether they
       * should be checked again later. */
      if ((CurrentTime-cli_firsttime(cptr) >= max_ping)
          && auth_ping_timeout(cptr))
        continue;
      /* OK, they still have enough time left, so we'll just skip to the
       * next client.  Set the next check to be when their time is up, if
       * that's before the currently scheduled next check -- hikari */
      expire = cli_firsttime(cptr) + max_ping;
      if (expire < next_check)
        next_check = expire;
      continue;
    }

    /* Quit the client after max_ping*2 - they should have answered by now */
    if (CurrentTime-cli_lasttime(cptr) >= (max_ping*2) )
    {
      /* If it was a server, then tell ops about it. */
      if (IsServer(cptr) || IsConnecting(cptr) || IsHandshake(cptr))
        sendto_opmask_butone(0, SNO_OLDSNO,
                             "No response from %s, closing link",
                             cli_name(cptr));
      exit_client_msg(cptr, cptr, &me, "Ping timeout");
      continue;
    }
    
    if (!IsPingSent(cptr))
    {
      /* If we haven't PINGed the connection and we haven't heard from it in a
       * while, PING it to make sure it is still alive.
       */
      SetPingSent(cptr);

      /* If we're late in noticing don't hold it against them :) */
      cli_lasttime(cptr) = CurrentTime - max_ping;
      
      if (IsUser(cptr))
        sendrawto_one(cptr, MSG_PING " :%s", cli_name(&me));
      else
        sendcmdto_prio_one(&me, CMD_PING, cptr, ":%s", cli_name(&me));
    }
    
    expire = cli_lasttime(cptr) + max_ping * 2;
    if (expire < next_check)
      next_check=expire;
  }
  
  assert(next_check >= CurrentTime);
  
  Debug((DEBUG_DEBUG, "[%i] check_pings() again in %is",
	 CurrentTime, next_check-CurrentTime));
  
  timer_add(&ping_timer, check_pings, 0, TT_ABSOLUTE, next_check);
}
Example #8
0
/** Look for any connections that we should try to initiate.
 * Reschedules itself to run again at the appropriate time.
 * @param[in] ev Timer event (ignored).
 */
static void try_connections(struct Event* ev) {
  struct ConfItem*  aconf;
  struct ConfItem** pconf;
  time_t            next;
  struct Jupe*      ajupe;
  int               hold;
  int               done;

  assert(ET_EXPIRE == ev_type(ev));
  assert(0 != ev_timer(ev));

  Debug((DEBUG_NOTICE, "Connection check at   : %s", myctime(CurrentTime)));
  next = CurrentTime + feature_int(FEAT_CONNECTFREQUENCY);
  done = 0;

  for (aconf = GlobalConfList; aconf; aconf = aconf->next) {
    /* Only consider server items with non-zero port and non-zero
     * connect times that are not actively juped.
     */
    if (!(aconf->status & CONF_SERVER)
        || aconf->address.port == 0
        || !(aconf->flags & CONF_AUTOCONNECT)
        || ((ajupe = jupe_find(aconf->name)) && JupeIsActive(ajupe)))
      continue;

    /* Do we need to postpone this connection further? */
    hold = aconf->hold > CurrentTime;

    /* Update next possible connection check time. */
    if (hold && next > aconf->hold)
        next = aconf->hold;

    /* Do not try to connect if its use is still on hold until future,
     * we have already initiated a connection this try_connections(),
     * too many links in its connection class, it is already linked,
     * or if connect rules forbid a link now.
     */
    if (hold || done
        || (ConfLinks(aconf) > ConfMaxLinks(aconf))
        || FindServer(aconf->name)
        || conf_eval_crule(aconf->name, CRULE_MASK))
      continue;

    /* Ensure it is at the end of the list for future checks. */
    if (aconf->next) {
      /* Find aconf's location in the list and splice it out. */
      for (pconf = &GlobalConfList; *pconf; pconf = &(*pconf)->next)
        if (*pconf == aconf)
          *pconf = aconf->next;
      /* Reinsert it at the end of the list (where pconf is now). */
      *pconf = aconf;
      aconf->next = 0;
    }

    /* Activate the connection itself. */
    if (connect_server(aconf, 0))
      sendto_opmask_butone(0, SNO_OLDSNO, "Connection to %s activated.",
			   aconf->name);

    /* And stop looking for further candidates. */
    done = 1;
  }

  Debug((DEBUG_NOTICE, "Next connection check : %s", myctime(next)));
  timer_add(&connect_timer, try_connections, 0, TT_ABSOLUTE, next);
}
Example #9
0
/** Read a 'packet' of data from a connection and process it.  Read in
 * 8k chunks to give a better performance rating (for server
 * connections).  Do some tricky stuff for client connections to make
 * sure they don't do any flooding >:-) -avalon
 * @param cptr Client from which to read data.
 * @param socket_ready If non-zero, more data can be read from the client's socket.
 * @return Positive number on success, zero on connection-fatal failure, negative
 *   if user is killed.
 */
static int read_packet(struct Client *cptr, int socket_ready)
{
  unsigned int dolen = 0;
  unsigned int length = 0;

  if (socket_ready &&
      !(IsUser(cptr) &&
	DBufLength(&(cli_recvQ(cptr))) > feature_uint(FEAT_CLIENT_FLOOD))) {
#if defined(USE_SSL)
    switch (client_recv(cptr, readbuf, sizeof(readbuf), &length)) {
#else
    switch (os_recv_nonb(cli_fd(cptr), readbuf, sizeof(readbuf), &length)) {
#endif
    case IO_SUCCESS:
      if (length)
      {
        cli_lasttime(cptr) = CurrentTime;
        ClearPingSent(cptr);
        ClrFlag(cptr, FLAG_NONL);
        if (cli_lasttime(cptr) > cli_since(cptr))
          cli_since(cptr) = cli_lasttime(cptr);
      }
      break;
    case IO_BLOCKED:
      break;
    case IO_FAILURE:
      cli_error(cptr) = errno;
      /* SetFlag(cptr, FLAG_DEADSOCKET); */
      return 0;
    }
  }

  /*
   * For server connections, we process as many as we can without
   * worrying about the time of day or anything :)
   */
  if (length > 0 && IsServer(cptr))
    return server_dopacket(cptr, readbuf, length);
  else if (length > 0 && (IsHandshake(cptr) || IsConnecting(cptr)))
    return connect_dopacket(cptr, readbuf, length);
  else
  {
    /*
     * Before we even think of parsing what we just read, stick
     * it on the end of the receive queue and do it when its
     * turn comes around.
     */
    if (length > 0 && dbuf_put(cptr, &(cli_recvQ(cptr)), readbuf, length) == 0)
      return exit_client(cptr, cptr, &me, "dbuf_put fail");

    if ((DBufLength(&(cli_recvQ(cptr))) > feature_uint(FEAT_CLIENT_FLOOD))
         && !IsChannelService(cptr))
      return exit_client(cptr, cptr, &me, "Excess Flood");

    while (DBufLength(&(cli_recvQ(cptr))) && !NoNewLine(cptr) &&
           (IsTrusted(cptr) || IsChannelService(cptr) || cli_since(cptr) - CurrentTime < 10))
    {
      dolen = dbuf_getmsg(&(cli_recvQ(cptr)), cli_buffer(cptr), BUFSIZE);
      /*
       * Devious looking...whats it do ? well..if a client
       * sends a *long* message without any CR or LF, then
       * dbuf_getmsg fails and we pull it out using this
       * loop which just gets the next 512 bytes and then
       * deletes the rest of the buffer contents.
       * -avalon
       */
      if (dolen == 0)
      {
        if (DBufLength(&(cli_recvQ(cptr))) < 510)
          SetFlag(cptr, FLAG_NONL);
        else
        {
          /* More than 512 bytes in the line - drop the input and yell
           * at the client.
           */
          DBufClear(&(cli_recvQ(cptr)));
          send_reply(cptr, ERR_INPUTTOOLONG);
        }
      }
      else if (client_dopacket(cptr, dolen) == CPTR_KILLED)
        return CPTR_KILLED;
      /*
       * If it has become registered as a Server
       * then skip the per-message parsing below.
       */
      if (IsHandshake(cptr) || IsServer(cptr))
      {
        while (-1)
        {
          dolen = dbuf_get(&(cli_recvQ(cptr)), readbuf, sizeof(readbuf));
          if (dolen <= 0)
            return 1;
          else if (dolen == 0)
          {
            if (DBufLength(&(cli_recvQ(cptr))) < 510)
              SetFlag(cptr, FLAG_NONL);
            else {
              DBufClear(&(cli_recvQ(cptr)));
              /* send_reply(cptr, ERR_INPUTTOOLONG); */
            }
          }
          else if ((IsServer(cptr) &&
                    server_dopacket(cptr, readbuf, dolen) == CPTR_KILLED) ||
                   (!IsServer(cptr) &&
                    connect_dopacket(cptr, readbuf, dolen) == CPTR_KILLED))
            return CPTR_KILLED;
        }
      }
    }

    /* If there's still data to process, wait 2 seconds first */
    if (DBufLength(&(cli_recvQ(cptr))) && !NoNewLine(cptr) &&
	!t_onqueue(&(cli_proc(cptr))))
    {
      Debug((DEBUG_LIST, "Adding client process timer for %C", cptr));
      cli_freeflag(cptr) |= FREEFLAG_TIMER;
      timer_add(&(cli_proc(cptr)), client_timer_callback, cli_connect(cptr),
		TT_RELATIVE, 2);
    }
  }
  return 1;
}

/** Start a connection to another server.
 * @param aconf Connect block data for target server.
 * @param by Client who requested the connection (if any).
 * @return Non-zero on success; zero on failure.
 */
int connect_server(struct ConfItem* aconf, struct Client* by)
{
  struct Client*   cptr = 0;
  assert(0 != aconf);

  if (aconf->dns_pending) {
    sendto_opmask(0, SNO_OLDSNO, "Server %s connect DNS pending",
                  aconf->name);
    return 0;
  }
  Debug((DEBUG_NOTICE, "Connect to %s[@%s]", aconf->name,
         ircd_ntoa(&aconf->address.addr)));

  if ((cptr = FindClient(aconf->name))) {
    if (IsServer(cptr) || IsMe(cptr)) {
      sendto_opmask(0, SNO_OLDSNO, "Server %s already present from %s",
                    aconf->name, cli_name(cli_from(cptr)));
      if (by && IsUser(by) && !MyUser(by)) {
        sendcmdto_one(&me, CMD_NOTICE, by, "%C :Server %s already present "
                      "from %s", by, aconf->name, cli_name(cli_from(cptr)));
      }
      return 0;
    }
    else if (IsHandshake(cptr) || IsConnecting(cptr)) {
      if (by && IsUser(by)) {
        sendcmdto_one(&me, CMD_NOTICE, by, "%C :Connection to %s already in "
                      "progress", by, cli_name(cptr));
      }
      return 0;
    }
  }
  /*
   * If we don't know the IP# for this host and it is a hostname and
   * not a ip# string, then try and find the appropriate host record.
   */
  if (!irc_in_addr_valid(&aconf->address.addr)
      && !ircd_aton(&aconf->address.addr, aconf->host)) {
    char buf[HOSTLEN + 1];

    host_from_uh(buf, aconf->host, HOSTLEN);
    gethost_byname(buf, connect_dns_callback, aconf);
    aconf->dns_pending = 1;
    return 0;
  }
  cptr = make_client(NULL, STAT_UNKNOWN_SERVER);

  /*
   * Copy these in so we have something for error detection.
   */
  ircd_strncpy(cli_name(cptr), aconf->name, HOSTLEN);
  ircd_strncpy(cli_sockhost(cptr), aconf->host, HOSTLEN);

  /*
   * Attach config entries to client here rather than in
   * completed_connection. This to avoid null pointer references
   */
  attach_confs_byhost(cptr, aconf->host, CONF_SERVER);

  if (!find_conf_byhost(cli_confs(cptr), aconf->host, CONF_SERVER)) {
    sendto_opmask(0, SNO_OLDSNO, "Host %s is not enabled for "
                  "connecting: no Connect block", aconf->name);
    if (by && IsUser(by) && !MyUser(by)) {
      sendcmdto_one(&me, CMD_NOTICE, by, "%C :Connect to host %s failed: no "
                    "Connect block", by, aconf->name);
    }
    det_confs_butmask(cptr, 0);
    free_client(cptr);
    return 0;
  }
  /*
   * attempt to connect to the server in the conf line
   */
  if (!connect_inet(aconf, cptr)) {
    if (by && IsUser(by) && !MyUser(by)) {
      sendcmdto_one(&me, CMD_NOTICE, by, "%C :Couldn't connect to %s", by,
                    cli_name(cptr));
    }
    det_confs_butmask(cptr, 0);
    free_client(cptr);
    return 0;
  }
  /*
   * NOTE: if we're here we have a valid C:Line and the client should
   * have started the connection and stored the remote address/port and
   * ip address name in itself
   *
   * The socket has been connected or connect is in progress.
   */
  make_server(cptr);
  if (by && IsUser(by)) {
    ircd_snprintf(0, cli_serv(cptr)->by, sizeof(cli_serv(cptr)->by), "%s%s",
		  NumNick(by));
    assert(0 == cli_serv(cptr)->user);
    cli_serv(cptr)->user = cli_user(by);
    cli_user(by)->refcnt++;
  }
  else {
    *(cli_serv(cptr))->by = '\0';
    /* strcpy(cptr->serv->by, "Auto"); */
  }
  cli_serv(cptr)->up = &me;
  SetConnecting(cptr);

  if (cli_fd(cptr) > HighestFd)
    HighestFd = cli_fd(cptr);

  LocalClientArray[cli_fd(cptr)] = cptr;

  Count_newunknown(UserStats);
  /* Actually we lie, the connect hasn't succeeded yet, but we have a valid
   * cptr, so we register it now.
   * Maybe these two calls should be merged.
   */
  add_client_to_list(cptr);
  hAddClient(cptr);
/*    nextping = CurrentTime; */

  return (s_state(&cli_socket(cptr)) == SS_CONNECTED) ?
    completed_connection(cptr) : 1;
}

/** Find the real hostname for the host running the server (or one which
 * matches the server's name) and its primary IP#.  Hostname is stored
 * in the client structure passed as a pointer.
 */
void init_server_identity(void)
{
  const struct LocalConf* conf = conf_get_local();
  assert(0 != conf);

  ircd_strncpy(cli_name(&me), conf->name, HOSTLEN);
  SetYXXServerName(&me, conf->numeric);
}

/** Process events on a client socket.
 * @param ev Socket event structure that has a struct Connection as
 *   its associated data.
 */
static void client_sock_callback(struct Event* ev)
{
  struct Client* cptr;
  struct Connection* con;
  char *fmt = "%s";
  char *fallback = 0;

  assert(0 != ev_socket(ev));
  assert(0 != s_data(ev_socket(ev)));

  con = (struct Connection*) s_data(ev_socket(ev));

  assert(0 != con_client(con) || ev_type(ev) == ET_DESTROY);

  cptr = con_client(con);

  assert(0 == cptr || con == cli_connect(cptr));

  switch (ev_type(ev)) {
  case ET_DESTROY:
    con_freeflag(con) &= ~FREEFLAG_SOCKET;

    if (!con_freeflag(con) && !cptr)
      free_connection(con);
#if defined(USE_SSL)
    ssl_free(ev_socket(ev));
#endif
    break;

  case ET_CONNECT: /* socket connection completed */
    if (!completed_connection(cptr) || IsDead(cptr))
      fallback = cli_info(cptr);
    break;

  case ET_ERROR: /* an error occurred */
    fallback = cli_info(cptr);
    cli_error(cptr) = ev_data(ev);
    /* If the OS told us we have a bad file descriptor, we should
     * record that for future reference.
     */
    if (cli_error(cptr) == EBADF)
      cli_fd(cptr) = -1;
    if (s_state(&(con_socket(con))) == SS_CONNECTING) {
      completed_connection(cptr);
      /* for some reason, the os_get_sockerr() in completed_connection()
       * can return 0 even when ev_data(ev) indicates a real error, so
       * re-assign the client error here.
       */
      cli_error(cptr) = ev_data(ev);
      break;
    }
    /*FALLTHROUGH*/
  case ET_EOF: /* end of file on socket */
    Debug((DEBUG_ERROR, "READ ERROR: fd = %d %d", cli_fd(cptr),
	   cli_error(cptr)));
    SetFlag(cptr, FLAG_DEADSOCKET);
    if ((IsServer(cptr) || IsHandshake(cptr)) && cli_error(cptr) == 0) {
      exit_client_msg(cptr, cptr, &me, "Server %s closed the connection (%s)",
		      cli_name(cptr), cli_serv(cptr)->last_error_msg);
      return;
    } else {
      fmt = "Read error: %s";
      fallback = "EOF from client";
    }
    break;

  case ET_WRITE: /* socket is writable */
    ClrFlag(cptr, FLAG_BLOCKED);
    if (cli_listing(cptr) && MsgQLength(&(cli_sendQ(cptr))) < 2048)
      list_next_channels(cptr);
    Debug((DEBUG_SEND, "Sending queued data to %C", cptr));
    send_queued(cptr);
    break;

  case ET_READ: /* socket is readable */
    if (!IsDead(cptr)) {
      Debug((DEBUG_DEBUG, "Reading data from %C", cptr));
      if (read_packet(cptr, 1) == 0) /* error while reading packet */
	fallback = "EOF from client";
    }
    break;

  default:
    assert(0 && "Unrecognized socket event in client_sock_callback()");
    break;
  }

  assert(0 == cptr || 0 == cli_connect(cptr) || con == cli_connect(cptr));

  if (fallback) {
    const char* msg = (cli_error(cptr)) ? strerror(cli_error(cptr)) : fallback;
    if (!msg)
      msg = "Unknown error";
    exit_client_msg(cptr, cptr, &me, fmt, msg);
  }
}

/** Process a timer on client socket.
 * @param ev Timer event that has a struct Connection as its
 * associated data.
 */
static void client_timer_callback(struct Event* ev)
{
  struct Client* cptr;
  struct Connection* con;

  assert(0 != ev_timer(ev));
  assert(0 != t_data(ev_timer(ev)));
  assert(ET_DESTROY == ev_type(ev) || ET_EXPIRE == ev_type(ev));

  con = (struct Connection*) t_data(ev_timer(ev));

  assert(0 != con_client(con) || ev_type(ev) == ET_DESTROY);

  cptr = con_client(con);

  assert(0 == cptr || con == cli_connect(cptr));

  if (ev_type(ev)== ET_DESTROY) {
    con_freeflag(con) &= ~FREEFLAG_TIMER; /* timer has expired... */

    if (!con_freeflag(con) && !cptr)
      free_connection(con); /* client is being destroyed */
  } else {
    Debug((DEBUG_LIST, "Client process timer for %C expired; processing",
	   cptr));
    read_packet(cptr, 0); /* read_packet will re-add timer if needed */
  }

  assert(0 == cptr || 0 == cli_connect(cptr) || con == cli_connect(cptr));
}
/* decrements the error count once per hour */
static void
error_clear(struct Event *ev)
{
  if (!--errors)
    timer_del(ev_timer(ev));
}
Example #11
0
static UWORD crysbind(WORD opcode, LONG pglobal, WORD control[], WORD int_in[], WORD int_out[], LONG addr_in[])
{
        LONG    maddr;
        LONG    tree;
        WORD    mouse, ret;
        WORD    unsupported = FALSE;

        maddr = 0;
        ret = TRUE;

        switch(opcode)
        {       
                                /* Application Manager                  */
          case APPL_INIT:
#if DBG_GEMSUPER
                aestrace("appl_init()");
#endif
                LWSET(pglobal, AES_VERSION);    /* version number       */
                LWSET(pglobal+2, 0x0001);       /* num of concurrent procs*/
/*              LLSET(pglobal, 0x00010200L);
*/
                LWSET(pglobal+4, rlr->p_pid);
                sh_deskf(0, pglobal+6);
                LWSET(pglobal+20, gl_nplanes);
                LLSET(pglobal+22, ADDR(&D));
                                                /* reset dispatcher     */
                                                /*  count to let the app*/
                                                /*  run a while.        */
                dspcnt = 0;
                ret = ap_init();
                break;
          case APPL_READ:
          case APPL_WRITE:
                ap_rdwr(opcode == APPL_READ ? MU_MESAG : MU_SDMSG, 
                        fpdnm(NULLPTR, AP_RWID), AP_LENGTH, AP_PBUFF);
                break;
          case APPL_FIND:
                ret = ap_find( AP_PNAME );
                break;
          case APPL_TPLAY:
                ap_tplay(AP_TBUFFER, AP_TLENGTH, AP_TSCALE);
                break;
          case APPL_TRECORD:
                ret = ap_trecd(AP_TBUFFER, AP_TLENGTH);
                break;
#if CONF_WITH_PCGEM
          case APPL_YIELD:
                dsptch();
                break;
#endif
          case APPL_EXIT:
#if DBG_GEMSUPER
                aestrace("appl_exit()");
#endif
                ap_exit();
                break;
                                /* Event Manager                        */
          case EVNT_KEYBD:
                  ret = ev_block(MU_KEYBD, 0x0L);
                break;
          case EVNT_BUTTON:
                ret = ev_button(B_CLICKS, B_MASK, B_STATE, &EV_MX);
                break;
          case EVNT_MOUSE:
                ret = ev_mouse((MOBLK *)&MO_FLAGS, &EV_MX);
                break;
          case EVNT_MESAG:
#if DBG_GEMSUPER
                aestrace("evnt_mesag()");
#endif
                ap_rdwr(MU_MESAG, rlr, 16, ME_PBUFF);
                break;
          case EVNT_TIMER:
                ev_timer( HW(T_HICOUNT) + LW(T_LOCOUNT) );
                break;
          case EVNT_MULTI:
#if DBG_GEMSUPER
                aestrace("evnt_multi()");
#endif
                if (MU_FLAGS & MU_TIMER)
                  maddr = HW(MT_HICOUNT) + LW(MT_LOCOUNT);
                tree = HW(MB_CLICKS) | LW((MB_MASK << 8) | MB_STATE);
                ret = ev_multi(MU_FLAGS, (MOBLK *)&MMO1_FLAGS, (MOBLK *)&MMO2_FLAGS, 
                        maddr, tree, MME_PBUFF, &EV_MX);
                break;
          case EVNT_DCLICK:
                ret = ev_dclick(EV_DCRATE, EV_DCSETIT);
                break;
                                /* Menu Manager                         */
          case MENU_BAR:
                if (gl_mnppd == rlr || gl_mnppd == NULL)
                  mn_bar(MM_ITREE, SHOW_IT, rlr->p_pid);
                else
                  menu_tree[rlr->p_pid] = (SHOW_IT) ? MM_ITREE : 0x0L;
                break;
          case MENU_ICHECK:
                do_chg(MM_ITREE, ITEM_NUM, CHECKED, CHECK_IT, FALSE, FALSE);
                break;
          case MENU_IENABLE:
                do_chg(MM_ITREE, (ITEM_NUM & 0x7fff), DISABLED, 
                        !ENABLE_IT, ((ITEM_NUM & 0x8000) != 0x0), FALSE);
                break;
          case MENU_TNORMAL:
                if (gl_mntree == menu_tree[rlr->p_pid])
                  do_chg(MM_ITREE, TITLE_NUM, SELECTED, !NORMAL_IT, 
                                TRUE, TRUE);
                break;
          case MENU_TEXT:
                tree = MM_ITREE;
                strcpy((char *)LLGET(OB_SPEC(ITEM_NUM)), 
                         (char *)MM_PTEXT);   
                break;
          case MENU_REGISTER:
                ret = mn_register(MM_PID, MM_PSTR);
                break;
          case MENU_UNREGISTER:
#if CONF_WITH_PCGEM
                /* distinguish between menu_unregister() and menu_popup() */
                if (IN_LEN == 1)
                  mn_unregister( MM_MID );
                else
#endif
                  unsupported = TRUE;
                break;
          case MENU_CLICK:
                /* distinguish between menu_click() and menu_attach() */
                /*
                 * although menu_click() is PC-GEM only, it's always
                 * enabled because the desktop uses it.
                 */
                if (IN_LEN == 2) {
                  if (MN_SETIT)
                    gl_mnclick = MN_CLICK;
                  ret = gl_mnclick;
                } else
                  unsupported = TRUE;
                break;
                                /* Object Manager                       */
          case OBJC_ADD:
                ob_add(OB_TREE, OB_PARENT, OB_CHILD);
                break;
          case OBJC_DELETE:
                ob_delete(OB_TREE, OB_DELOB);
                break;
          case OBJC_DRAW:
                gsx_sclip((GRECT *)&OB_XCLIP);
                ob_draw(OB_TREE, OB_DRAWOB, OB_DEPTH);
                break;
          case OBJC_FIND:
                ret = ob_find(OB_TREE, OB_STARTOB, OB_DEPTH, 
                                OB_MX, OB_MY);
                break;
          case OBJC_OFFSET:
                ob_offset(OB_TREE, OB_OBJ, &OB_XOFF, &OB_YOFF);
                break;
          case OBJC_ORDER:
                ob_order(OB_TREE, OB_OBJ, OB_NEWPOS);
                break;
          case OBJC_EDIT:
                gsx_sclip(&gl_rfull);
                OB_ODX = OB_IDX;
                ret = ob_edit(OB_TREE, OB_OBJ, OB_CHAR, &OB_ODX, OB_KIND);
                break;
          case OBJC_CHANGE:
                gsx_sclip((GRECT *)&OB_XCLIP);
                ob_change(OB_TREE, OB_DRAWOB, OB_NEWSTATE, OB_REDRAW);
                break;
                                /* Form Manager                         */
          case FORM_DO:
                ret = fm_do(FM_FORM, FM_START);
                break;
          case FORM_DIAL:
                ret = fm_dial(FM_TYPE, (GRECT *)&FM_X);
                break;
          case FORM_ALERT:
                ret = fm_alert(FM_DEFBUT, FM_ASTRING);
                break;
          case FORM_ERROR:
                ret = fm_error(FM_ERRNUM);
                break;
          case FORM_CENTER:
                ob_center(FM_FORM, (GRECT *)&FM_XC);
                break;
          case FORM_KEYBD:
                gsx_sclip(&gl_rfull);
                FM_OCHAR = FM_ICHAR;
                FM_ONXTOB = FM_INXTOB;
                ret = fm_keybd(FM_FORM, FM_OBJ, &FM_OCHAR, &FM_ONXTOB);
                break;
          case FORM_BUTTON:
                gsx_sclip(&gl_rfull);
                ret = fm_button(FM_FORM, FM_OBJ, FM_CLKS, &FM_ONXTOB);
                break;
                                /* Graphics Manager                     */
          case GRAF_RUBBOX:
                gr_rubbox(GR_I1, GR_I2, GR_I3, GR_I4, 
                          &GR_O1, &GR_O2);
                break;
          case GRAF_DRAGBOX:
                gr_dragbox(GR_I1, GR_I2, GR_I3, GR_I4, (GRECT *)&GR_I5, 
                           &GR_O1, &GR_O2);
                break;
          case GRAF_MBOX:
                gr_movebox(GR_I1, GR_I2, GR_I3, GR_I4, GR_I5, GR_I6);
                break;
          case GRAF_GROWBOX:
                gr_growbox((GRECT *)&GR_I1, (GRECT *)&GR_I5);
                break;
          case GRAF_SHRINKBOX:
                gr_shrinkbox((GRECT *)&GR_I1, (GRECT *)&GR_I5);
                break;
          case GRAF_WATCHBOX:
                ret = gr_watchbox(GR_TREE, GR_OBJ, GR_INSTATE, GR_OUTSTATE);
                break;
          case GRAF_SLIDEBOX:
                ret = gr_slidebox(GR_TREE, GR_PARENT, GR_OBJ, GR_ISVERT);
                break;
          case GRAF_HANDLE:
                GR_WCHAR = gl_wchar;
                GR_HCHAR = gl_hchar;
                GR_WBOX = gl_wbox;
                GR_HBOX = gl_hbox;
                ret = gl_handle;
                break;
          case GRAF_MOUSE:
                if (GR_MNUMBER > 255)
                {
                  if (GR_MNUMBER == M_OFF)
                    gsx_moff();
                  if (GR_MNUMBER == M_ON)
                    gsx_mon();
                }
                else
                {
                  if (GR_MNUMBER != 255)                
                  {
                    switch(GR_MNUMBER) {
                      case 1:
                        mouse = MICE01;
                        break;
                      case 2:
                        mouse = MICE02;
                        break;
                      case 3:
                        mouse = MICE03;
                        break;
                      case 4:
                        mouse = MICE04;
                        break;
                      case 5:
                        mouse = MICE05;
                        break;
                      case 6:
                        mouse = MICE06;
                        break;
                      case 7:
                        mouse = MICE07;
                        break;
                      default:
                        mouse = MICE00;
                        break;
                    }
                    maddr = *(LONG *) &rs_bitblk[mouse];
                  }
                  else
                    maddr = GR_MADDR;
                  gsx_mfset(maddr);
                }
                break;
          case GRAF_MKSTATE:
                gr_mkstate(&GR_MX, &GR_MY, &GR_MSTATE, &GR_KSTATE);
                break;
                                /* Scrap Manager                        */
          case SCRP_READ:
                ret = sc_read((BYTE*)SC_PATH);
                break;
          case SCRP_WRITE:
                ret = sc_write((const BYTE*)SC_PATH);
                break;
#if CONF_WITH_PCGEM
          case SCRP_CLEAR:
                ret = sc_clear();
                break;
#endif
                                /* File Selector Manager                */
          case FSEL_INPUT:
                ret = fs_input((BYTE*)FS_IPATH, (BYTE*)FS_ISEL, &FS_BUTTON, NULL);
                break;
          case FSEL_EXINPUT:
                ret = fs_input((BYTE*)FS_IPATH, (BYTE*)FS_ISEL, &FS_BUTTON, (BYTE *)FS_ILABEL);
                break;
                                /* Window Manager                       */
          case WIND_CREATE:
                ret = wm_create(WM_KIND, (GRECT *)&WM_WX);
                break;
          case WIND_OPEN:
                wm_open(WM_HANDLE, (GRECT *)&WM_WX);
                break;
          case WIND_CLOSE:
                wm_close(WM_HANDLE);
                break;
          case WIND_DELETE:
                wm_delete(WM_HANDLE);
                break;
          case WIND_GET:
                wm_get(WM_HANDLE, WM_WFIELD, &WM_OX);
                break;
          case WIND_SET:
                  wm_set(WM_HANDLE, WM_WFIELD, &WM_IX);
                  break;
          case WIND_FIND:
                ret = wm_find(WM_MX, WM_MY);
                break;
          case WIND_UPDATE:
                wm_update(WM_BEGUP);
                break;
          case WIND_CALC:
                wm_calc(WM_WCTYPE, WM_WCKIND, WM_WCIX, WM_WCIY, 
                        WM_WCIW, WM_WCIH, &WM_WCOX, &WM_WCOY, 
                        &WM_WCOW, &WM_WCOH);
                break;
          case WIND_NEW:
                wm_new();
                break;
                                /* Resource Manager                     */
          case RSRC_LOAD:
                ret = rs_load(pglobal, RS_PFNAME);
                break;
          case RSRC_FREE:
                ret = rs_free(pglobal);
                break;
          case RSRC_GADDR:
                ret = rs_gaddr(pglobal, RS_TYPE, RS_INDEX, &ad_rso);
                break;
          case RSRC_SADDR:
                ret = rs_saddr(pglobal, RS_TYPE, RS_INDEX, RS_INADDR);
                break;
          case RSRC_OBFIX:
                rs_obfix(RS_TREE, RS_OBJ);
                break;
                                /* Shell Manager                        */
          case SHEL_READ:
                sh_read((BYTE*)SH_PCMD, (BYTE*)SH_PTAIL);
                break;
          case SHEL_WRITE:
                ret = sh_write(SH_DOEX, SH_ISGR, SH_ISCR, (const BYTE*)SH_PCMD, (const BYTE*)SH_PTAIL);
                break;
          case SHEL_GET:
                sh_get((void*)SH_PBUFFER, SH_LEN);
                break;
          case SHEL_PUT:
                sh_put((const void *)SH_PDATA, SH_LEN);
                break;
          case SHEL_FIND:
                ret = sh_find((BYTE*)SH_PATH);
                break;
          case SHEL_ENVRN:
                sh_envrn((BYTE**)SH_PATH, (const BYTE*)SH_SRCH);
                break;
#if CONF_WITH_PCGEM
          case SHEL_RDEF:
                sh_rdef((BYTE*)SH_LPCMD, (BYTE*)SH_LPDIR);
                break;
          case SHEL_WDEF:
                sh_wdef((const BYTE*)SH_LPCMD, (const BYTE*)SH_LPDIR);
                break;
#endif
          default:
                unsupported = TRUE;
                break;
        }

        if (unsupported) {
            kprintf("Bad AES function %d\n", opcode);
            if (opcode != 0)    /* Ignore the 0 since some PRGs are this call */
                fm_show(ALNOFUNC, &opcode, 1);
            ret = -1;
        }

        return(ret);
}