示例#1
0
文件: fq_client.c 项目: retailnext/fq
int
fq_client_connect(fq_client conn) {
  fq_conn_s *conn_s = conn;
  if(conn_s->connected != 0) return -1;

  conn_s->connected = 1;
  if(pthread_create(&conn_s->worker, NULL, fq_conn_worker, conn_s) != 0) {
      CONNERR(conn_s, "could not start command thread");
    return -1;
  }
  if(pthread_create(&conn_s->data_worker, NULL, fq_data_worker, conn_s) != 0) {
      CONNERR(conn_s, "could not start data thread");
    return -1;
  }
  return 0;
}
示例#2
0
文件: fq_client.c 项目: ipstatic/fq
static int
fq_resolve_endpoint(fq_conn_s *conn_s) {
  conn_s->remote.sin_family = AF_INET;
  conn_s->remote.sin_port = htons(conn_s->port);
  if(inet_pton(AF_INET, conn_s->host, &conn_s->remote.sin_addr) != 1) {
#ifdef HAVE_GETHOSTBYNAME_R
    struct hostent hostbuf, *hp;
    struct in_addr **addr_list;
    int buflen = 1024, herr;
    char *buf;
    if((buf = malloc(buflen)) == NULL) {
      CONNERR(conn_s, "out of memory");
      return -1;
    }
    while((hp = gethostbyname_r(conn_s->host, &hostbuf, buf, buflen, &herr)) == NULL &&
          errno == ERANGE) {
      buflen *= 2;
      if((buf = realloc(buf, buflen)) == NULL) {
        CONNERR(conn_s, "out of memory");
        free(buf);
        return -1;
      }
    }
    if(!hp) {
      CONNERR(conn_s, "host lookup failed");
      free(buf);
      return -1;
    }
    addr_list = (struct in_addr **)hp->h_addr_list;
    if(*addr_list == 0) {
      CONNERR(conn_s, "no address for host");
      free(buf);
      return -1;
    }
    memcpy(&conn_s->remote.sin_addr, *addr_list, sizeof(struct in_addr));
    free(buf);
#else
    struct hostent *hp;
    struct in_addr **addr_list;
    hp = gethostbyname(conn_s->host);
    if(!hp) {
      CONNERR(conn_s, "host lookup failed");
      return -1;
    }
    addr_list = (struct in_addr **)hp->h_addr_list;
    if(*addr_list == 0) {
      CONNERR(conn_s, "no address for host");
      return -1;
    }
    memcpy(&conn_s->remote.sin_addr, *addr_list, sizeof(struct in_addr));
#endif
  }
  conn_s->last_resolve = fq_gethrtime();
  return 0;
}
示例#3
0
文件: fq_client.c 项目: ipstatic/fq
static void *
fq_conn_worker(void *u) {
  int backoff = 0, i;
  bool zero;
  fq_conn_s *conn_s = (fq_conn_s *)u;
  cmd_instr *last_entries[MAX_PENDING] = { NULL };
  int last_entry_idx = 0;
  int next_entry_idx = 0;

#define SAVE_ENTRY(e) do { \
  if(last_entries[next_entry_idx] != NULL) { \
    CONNERR(conn_s, "exceed max cmd pipeline"); \
    goto restart; \
  } \
  last_entries[next_entry_idx++] = e; \
  next_entry_idx = next_entry_idx % MAX_PENDING; \
} while(0)
#define last_entry last_entries[last_entry_idx]
#define PROCESS_ENTRY(e, should_free) do { \
  fq_assert(last_entries[last_entry_idx] == e); \
  if(should_free) free(last_entries[last_entry_idx]); \
  last_entries[last_entry_idx++] = NULL; \
  last_entry_idx = last_entry_idx % MAX_PENDING; \
} while(0)

  cmd_instr *entry;

  ck_pr_inc_uint(&conn_s->thrcnt);

  while(conn_s->stop == 0) {
    int wait_ms = 50;
    if(fq_client_connect_internal(conn_s) == 0) {
      backoff = 0; /* we're good, restart our backoff */
    }
    while(conn_s->data_ready && conn_s->stop == 0) {
      hrtime_t t;
      unsigned long long hb_us;
      struct timeval tv;
      int rv;

      ck_fifo_spsc_dequeue_lock(&conn_s->cmdq);
      while(ck_fifo_spsc_dequeue(&conn_s->cmdq, &entry) == true) {
#ifdef DEBUG
        fq_debug(FQ_DEBUG_CONN, "client acting on user req 0x%04x\n", entry->cmd);
#endif
        switch(entry->cmd) {
          case FQ_PROTO_STATUSREQ:
            fq_debug(FQ_DEBUG_CONN, "sending status request\n");
            if(fq_write_uint16(conn_s->cmd_fd, entry->cmd)) {
              free(entry);
              CONNERR(conn_s, "write failed (statusreq)");
              goto restart;
            }
            SAVE_ENTRY(entry);
            break;
          case FQ_PROTO_HBREQ:
            fq_debug(FQ_DEBUG_CONN, "sending heartbeat request\n");
            if(fq_write_uint16(conn_s->cmd_fd, entry->cmd) ||
               fq_write_uint16(conn_s->cmd_fd, entry->data.heartbeat.ms)) {
              free(entry);
              CONNERR(conn_s, "write failed (hbreq)");
              goto restart;
            }
            conn_s->cmd_hb_ms = entry->data.heartbeat.ms;
            tv.tv_sec = (unsigned long)entry->data.heartbeat.ms / 1000;
            tv.tv_usec = 1000UL * (entry->data.heartbeat.ms % 1000);
            if(setsockopt(conn_s->cmd_fd, SOL_SOCKET, SO_RCVTIMEO,
                          &tv, sizeof(tv)))
              CONNERR(conn_s, strerror(errno));
            tv.tv_sec = (unsigned long)entry->data.heartbeat.ms / 1000;
            tv.tv_usec = 1000UL * (entry->data.heartbeat.ms % 1000);
            if(setsockopt(conn_s->cmd_fd, SOL_SOCKET, SO_SNDTIMEO,
                          &tv, sizeof(tv)))
              CONNERR(conn_s, strerror(errno));
            conn_s->cmd_hb_last = fq_gethrtime();
            free(entry);
            break;
          case FQ_PROTO_BINDREQ:
            {
              unsigned short flags = entry->data.bind->flags;
              if(fq_write_uint16(conn_s->cmd_fd, entry->cmd) ||
                 fq_write_uint16(conn_s->cmd_fd, flags) ||
                 fq_write_short_cmd(conn_s->cmd_fd,
                                    entry->data.bind->exchange.len,
                                    entry->data.bind->exchange.name) < 0 ||
                 fq_write_short_cmd(conn_s->cmd_fd,
                                    strlen(entry->data.bind->program),
                                    entry->data.bind->program) < 0) {
	CONNERR(conn_s, "write failed (bindreq)");
                goto restart;
              }
              SAVE_ENTRY(entry);
            }
            break;
          case FQ_PROTO_UNBINDREQ:
            {
              if(fq_write_uint16(conn_s->cmd_fd, entry->cmd) ||
                 fq_write_uint32(conn_s->cmd_fd, entry->data.unbind->route_id) ||
                 fq_write_short_cmd(conn_s->cmd_fd,
                                    entry->data.unbind->exchange.len,
                                    entry->data.unbind->exchange.name) < 0) {
	CONNERR(conn_s, "write failed (unbindreq)");
                goto restart;
              }
              SAVE_ENTRY(entry);
            }
            break;
          default:
            CONNERR(conn_s, "unknown user-side cmd");
            free(entry);
        }
      }
      ck_fifo_spsc_dequeue_unlock(&conn_s->cmdq);

      if(conn_s->cmd_hb_needed) {
#ifdef DEBUG
          fq_debug(FQ_DEBUG_CONN, "-> heartbeat\n");
#endif
        if(fq_write_uint16(conn_s->cmd_fd, FQ_PROTO_HB)) {
          CONNERR(conn_s, "write failed (hb)");
          break;
        }
        conn_s->cmd_hb_needed = 0;
      }

      rv = fq_client_wfrw_internal(conn_s->cmd_fd, 1, 0, wait_ms, NULL);
      if(rv == 0) {
        wait_ms = (wait_ms >> 2) + wait_ms;
        if(conn_s->cmd_hb_ms && wait_ms > conn_s->cmd_hb_ms)
          wait_ms = conn_s->cmd_hb_ms;
        if(wait_ms > 1000) wait_ms = 1000;
      }
      else wait_ms = 50;
      fq_debug(FQ_DEBUG_CONN, "fq_client_wfrw_internal(cmd:%d) -> %d\n", conn_s->cmd_fd, rv);
      t = fq_gethrtime();
      hb_us = (unsigned long long)conn_s->cmd_hb_ms * 3 * 1000000ULL;
      if(conn_s->cmd_hb_last && hb_us &&
         conn_s->cmd_hb_last < (unsigned int) (t - hb_us)) {
        char errbuf[256];
        snprintf(errbuf, sizeof(errbuf), "heartbeat failed [%llu - %llu = %llu]",
                 (unsigned long long)t, (unsigned long long)conn_s->cmd_hb_last,
                 (unsigned long long)(t - conn_s->cmd_hb_last));
        CONNERR(conn_s, errbuf);
        break;
      }
      if(rv < 0) {
        CONNERR(conn_s, strerror(errno));
        break;
      }
      if(rv > 0) {
        bool handled = false;
        uint16_t hb;
        if(fq_read_uint16(conn_s->cmd_fd, &hb)) break;
        switch(hb) {
          case FQ_PROTO_HB:
#ifdef DEBUG
            fq_debug(FQ_DEBUG_CONN, "<- heartbeat\n");
#endif
            conn_s->cmd_hb_last = fq_gethrtime();
            conn_s->cmd_hb_needed = 1;
            break;
          case FQ_PROTO_STATUS:
            if(!last_entry || last_entry->cmd != FQ_PROTO_STATUSREQ) {
              CONNERR(conn_s, "protocol violation (status unexpected)");
              goto restart;
            }
            if(fq_read_status(conn_s->cmd_fd,
                              last_entry->data.status.callback,
                              last_entry->data.status.closure))
              goto restart;
            PROCESS_ENTRY(last_entry, 1);
            break;
          case FQ_PROTO_BIND:
            if(!last_entry || last_entry->cmd != FQ_PROTO_BINDREQ) {
              CONNERR(conn_s, "protocol violation (bind unexpected)");
              goto restart;
            }
            if(fq_read_uint32(conn_s->cmd_fd,
                              &last_entry->data.bind->out__route_id)) {
              if(conn_s->bind_hook) {
                if(conn_s->sync_hooks) {
                  enqueue_cmd_hook_req(conn_s, last_entry);
	  PROCESS_ENTRY(last_entry, 0);
	  handled = true;
                }
                else conn_s->bind_hook((fq_client)conn_s, last_entry->data.bind);
              }
              CONNERR(conn_s, "read failed (bind)");
              goto restart;
            }
            if(conn_s->bind_hook) {
              if(conn_s->sync_hooks) {
                enqueue_cmd_hook_req(conn_s, last_entry);
	PROCESS_ENTRY(last_entry, 0);
	handled = true;
              }
              else conn_s->bind_hook((fq_client)conn_s, last_entry->data.bind);
            }
            if(!handled) PROCESS_ENTRY(last_entry, 1);
            break;
          case FQ_PROTO_UNBIND:
            if(!last_entry || last_entry->cmd != FQ_PROTO_UNBINDREQ) {
              CONNERR(conn_s, "protocol violation (unbind unexpected)");
              goto restart;
            }
            if(fq_read_uint32(conn_s->cmd_fd,
                              &last_entry->data.unbind->out__success)) {
              if(conn_s->unbind_hook) {
                if(conn_s->sync_hooks) {
                  enqueue_cmd_hook_req(conn_s, last_entry);
                  PROCESS_ENTRY(last_entry, 0);
	  handled = true;
                }
                conn_s->unbind_hook((fq_client)conn_s, last_entry->data.unbind);
              }
              CONNERR(conn_s, "read failed (unbind)");
              goto restart;
            }
            if(conn_s->unbind_hook) {
              if(conn_s->sync_hooks) {
                enqueue_cmd_hook_req(conn_s, last_entry);
                PROCESS_ENTRY(last_entry, 0);
	handled = true;
                last_entry = NULL;
              }
              conn_s->unbind_hook((fq_client)conn_s, last_entry->data.unbind);
            }
            if(!handled) PROCESS_ENTRY(last_entry,1);
            break;
          default:
            CONNERR(conn_s, "protocol violation");
            goto restart;
            break;
        }
      }
    }
示例#4
0
文件: fq_client.c 项目: retailnext/fq
int
fq_client_creds(fq_client conn, const char *host, unsigned short port,
                const char *sender, const char *pass) {
  fq_conn_s *conn_s;
  conn_s = conn;

  /* make the sockets as disconnected */
  conn_s->cmd_fd = conn_s->data_fd = -1;

  /* parse the user info */
  conn_s->user = strdup(sender);
  conn_s->queue = strchr(conn_s->user, '/');
  if(conn_s->queue) *conn_s->queue++ = '\0';
  if(!conn_s->queue) {
    uuid_t out;
    char qname[39];
    uuid_generate(out);
    qname[0] = 'q'; qname[1] = '-';
    uuid_unparse_lower(out, qname+2);
    conn_s->queue = qname;
  }
  conn_s->queue = strdup(conn_s->queue);
  conn_s->pass = strdup(pass);

  /* determine our endpoint */
  conn_s->remote.sin_family = AF_INET;
  conn_s->remote.sin_port = htons(port);
  if(inet_pton(AF_INET, host, &conn_s->remote.sin_addr) != 0) {
#ifdef HAVE_GETHOSTBYNAME_R
    struct hostent hostbuf, *hp;
    struct in_addr **addr_list;
    int buflen = 1024, herr, hres;
    char *buf;
    if((buf = malloc(buflen)) == NULL) {
      CONNERR(conn_s, "out of memory");
      return -1;
    }
    while((hres = gethostbyname_r(host, &hostbuf, 
                                  buf, buflen, &hp, &herr)) == ERANGE) {
      buflen *= 2;
      if((buf = realloc(buf, buflen)) == NULL) {
        CONNERR(conn_s, "out of memory");
        return -1;
      }
    }
    if(!hp) {
      CONNERR(conn_s, "host lookup failed");
      return -1;
    }
    addr_list = (struct in_addr **)hp->h_addr_list;
    if(*addr_list == 0) {
      CONNERR(conn_s, "no address for host");
      return -1;
    }
    memcpy(&conn_s->remote.sin_addr, *addr_list, sizeof(struct in_addr));
    free(buf);
#else
    struct hostent *hp;
    struct in_addr **addr_list;
    hp = gethostbyname(host);
    if(!hp) {
      CONNERR(conn_s, "host lookup failed");
      return -1;
    }
    addr_list = (struct in_addr **)hp->h_addr_list;
    if(*addr_list == 0) {
      CONNERR(conn_s, "no address for host");
      return -1;
    }
    memcpy(&conn_s->remote.sin_addr, *addr_list, sizeof(struct in_addr));
#endif
  }
  conn_s->cmdqhead = malloc(sizeof(ck_fifo_mpmc_entry_t));
  ck_fifo_mpmc_init(&conn_s->cmdq, conn_s->cmdqhead);

  conn_s->qhead = malloc(sizeof(ck_fifo_mpmc_entry_t));
  ck_fifo_mpmc_init(&conn_s->q, conn_s->qhead);

  conn_s->backqhead = malloc(sizeof(ck_fifo_mpmc_entry_t));
  ck_fifo_mpmc_init(&conn_s->backq, conn_s->backqhead);

  return 0;
}
示例#5
0
文件: fq_client.c 项目: retailnext/fq
static void *
fq_conn_worker(void *u) {
  int backoff = 0;
  fq_conn_s *conn_s = (fq_conn_s *)u;
  cmd_instr *last_entry = NULL;
  uint16_t expect;
  while(conn_s->stop == 0) {
   restart:
    expect = 0;
    if(fq_client_connect_internal(conn_s) == 0) {
      backoff = 0; /* we're good, restart our backoff */
    }

    while(conn_s->data_ready) {
      hrtime_t t;
      unsigned long long hb_us;
      struct timeval tv;
      int rv;
      cmd_instr *entry;
      ck_fifo_mpmc_entry_t *garbage;

      while(ck_fifo_mpmc_dequeue(&conn_s->cmdq, &entry, &garbage) == true) {
        free(garbage);
#ifdef DEBUG
        fq_debug(FQ_DEBUG_CONN, "client acting on user req 0x%04x\n", entry->cmd);
#endif
        switch(entry->cmd) {
          case FQ_PROTO_STATUSREQ:
            if(expect != 0) {
              if(conn_s->errorlog) conn_s->errorlog("protocol violation");
              goto restart;
            }
            fq_debug(FQ_DEBUG_CONN, "sending status request\n");
            if(fq_write_uint16(conn_s->cmd_fd, entry->cmd)) {
              free(entry);
              goto restart;
            }
            expect = FQ_PROTO_STATUS;
            last_entry = entry;
            break;
          case FQ_PROTO_HBREQ:
            fq_debug(FQ_DEBUG_CONN, "sending heartbeat request\n");
            if(fq_write_uint16(conn_s->cmd_fd, entry->cmd) ||
               fq_write_uint16(conn_s->cmd_fd, entry->data.heartbeat.ms)) {
              free(entry);
              goto restart;
            }
            conn_s->cmd_hb_ms = entry->data.heartbeat.ms;
            tv.tv_sec = (unsigned long)entry->data.heartbeat.ms / 1000;
            tv.tv_usec = 1000UL * (entry->data.heartbeat.ms % 1000);
            if(setsockopt(conn_s->cmd_fd, SOL_SOCKET, SO_RCVTIMEO,
                          &tv, sizeof(tv)))
              CONNERR(conn_s, strerror(errno));
            tv.tv_sec = (unsigned long)entry->data.heartbeat.ms / 1000;
            tv.tv_usec = 1000UL * (entry->data.heartbeat.ms % 1000);
            if(setsockopt(conn_s->cmd_fd, SOL_SOCKET, SO_SNDTIMEO,
                          &tv, sizeof(tv)))
              CONNERR(conn_s, strerror(errno));
            conn_s->cmd_hb_last = fq_gethrtime();
            free(entry);
            break;
          case FQ_PROTO_BINDREQ:
            {
              unsigned short peermode = entry->data.bind->peermode ? 1 : 0;
              if(expect != 0) {
                if(conn_s->errorlog) conn_s->errorlog("protocol violation");
                goto restart;
              }
              if(fq_write_uint16(conn_s->cmd_fd, entry->cmd) ||
                 fq_write_uint16(conn_s->cmd_fd, peermode) ||
                 fq_write_short_cmd(conn_s->cmd_fd,
                                    entry->data.bind->exchange.len,
                                    entry->data.bind->exchange.name) < 0 ||
                 fq_write_short_cmd(conn_s->cmd_fd,
                                    strlen(entry->data.bind->program),
                                    entry->data.bind->program) < 0) {
                goto restart;
              }
              expect = FQ_PROTO_BIND;
              last_entry = entry;
            }
            break;
          case FQ_PROTO_UNBINDREQ:
            {
              if(expect != 0) {
                if(conn_s->errorlog) conn_s->errorlog("protocol violation");
                goto restart;
              }
              if(fq_write_uint16(conn_s->cmd_fd, entry->cmd) ||
                 fq_write_uint32(conn_s->cmd_fd, entry->data.unbind->route_id) ||
                 fq_write_short_cmd(conn_s->cmd_fd,
                                    entry->data.unbind->exchange.len,
                                    entry->data.unbind->exchange.name) < 0) {
                goto restart;
              }
              expect = FQ_PROTO_UNBIND;
              last_entry = entry;
            }
            break;
          default:
            if(conn_s->errorlog) conn_s->errorlog("unknown user-side cmd");
            free(entry);
        }
      }

      if(conn_s->cmd_hb_needed) {
#ifdef DEBUG
          fq_debug(FQ_DEBUG_CONN, "-> heartbeat\n");
#endif
        if(fq_write_uint16(conn_s->cmd_fd, FQ_PROTO_HB)) break;
        conn_s->cmd_hb_needed = 0;
      }

      rv = fq_client_wfrw_internal(conn_s->cmd_fd, 1, 0, 50, NULL);
      t = fq_gethrtime();
      hb_us = (unsigned long long)conn_s->cmd_hb_ms * 3 * 1000000ULL;
      if(conn_s->cmd_hb_last && hb_us &&
         conn_s->cmd_hb_last < (unsigned int) (t - hb_us)) {
        char errbuf[256];
        snprintf(errbuf, sizeof(errbuf), "heartbeat failed [%llu - %llu = %llu]",
                 (unsigned long long)t, (unsigned long long)conn_s->cmd_hb_last,
                 (unsigned long long)(t - conn_s->cmd_hb_last));
        CONNERR(conn_s, errbuf);
        break;
      }
      if(rv < 0) {
        CONNERR(conn_s, strerror(errno));
        break;
      }
      if(rv > 0) {
        uint16_t hb;
        if(fq_read_uint16(conn_s->cmd_fd, &hb)) break;
        switch(hb) {
          case FQ_PROTO_HB:
#ifdef DEBUG
            fq_debug(FQ_DEBUG_CONN, "<- heartbeat\n");
#endif
            conn_s->cmd_hb_last = fq_gethrtime();
            conn_s->cmd_hb_needed = 1;
            break;
          case FQ_PROTO_STATUS:
            if(expect != FQ_PROTO_STATUS) {
              if(conn_s->errorlog) conn_s->errorlog("protocol violation");
              goto restart;
            }
            if(fq_read_status(conn_s->cmd_fd,
                              last_entry->data.status.callback,
                              last_entry->data.status.closure))
              goto restart;
            expect = 0;
            break;
          case FQ_PROTO_BIND:
            if(expect != FQ_PROTO_BIND) {
              if(conn_s->errorlog) conn_s->errorlog("protocol violation");
              goto restart;
            }
            if(fq_read_uint32(conn_s->cmd_fd,
                              &last_entry->data.bind->out__route_id))
              goto restart;
            expect = 0;
            break;
          case FQ_PROTO_UNBIND:
            if(expect != FQ_PROTO_UNBIND) {
              if(conn_s->errorlog) conn_s->errorlog("protocol violation");
              goto restart;
            }
            if(fq_read_uint32(conn_s->cmd_fd,
                              &last_entry->data.unbind->out__success))
              goto restart;
            expect = 0;
            break;
          default:
            if(conn_s->errorlog) conn_s->errorlog("protocol violation");
            goto restart;
            break;
        }
      }
    }

#ifdef DEBUG
    fq_debug(FQ_DEBUG_CONN, "[cmd] connection failed: %s\n", conn_s->error);
#endif
    usleep(backoff);
    backoff += 10000;
  }
  fq_client_disconnect_internal(conn_s);
  return (void *)NULL;
}