static void read_quote(event_loop el, int fd, int mask, void *data) { char *buf; struct sockaddr_in si; socklen_t slen = sizeof si; int nread; NOT_USED(el); NOT_USED(mask); NOT_USED(data); if ((buf = CALLOC(1, sizeof (Quote))) == NULL) return; /* FIXME */ if ((nread = recvfrom(fd, buf, sizeof (Quote), 0, (struct sockaddr *)&si, &slen)) > 0) { Quote *quote; struct msg *msg; quote = (Quote *)buf; if (quote->thyquote.m_nLen == sizeof (THYQuote)) { int tlen; quote->thyquote.m_cJYS[sizeof quote->thyquote.m_cJYS - 1] = '\0'; quote->thyquote.m_cHYDM[sizeof quote->thyquote.m_cHYDM - 1] = '\0'; quote->m_nMSec = 0; /* for testing */ dlist_rwlock_rdlock(monitors); if (dlist_length(monitors) > 0) { char res[512]; dlist_iter_t iter = dlist_iter_new(monitors, DLIST_START_HEAD); dlist_node_t node; snprintf(res, sizeof res, "RX '%d,%s,%s,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f," "%.2f,%.2f,%d,%.2f,%d,%d,%.2f,%d,%.2f,%d'\r\n", quote->thyquote.m_nTime, quote->thyquote.m_cHYDM, quote->thyquote.m_cJYS, quote->thyquote.m_dZXJ, quote->thyquote.m_dJKP, quote->thyquote.m_dZGJ, quote->thyquote.m_dZDJ, quote->thyquote.m_dZSP, quote->thyquote.m_dJSP, quote->thyquote.m_dZJSJ, quote->thyquote.m_dJJSJ, quote->thyquote.m_nCJSL, quote->thyquote.m_dCJJE, quote->thyquote.m_nZCCL, quote->thyquote.m_nCCL, quote->thyquote.m_dMRJG1, quote->thyquote.m_nMRSL1, quote->thyquote.m_dMCJG1, quote->thyquote.m_nMCSL1); while ((node = dlist_next(iter))) { client c = (client)dlist_node_value(node); pthread_spin_lock(&c->lock); if (c->flags & CLIENT_CLOSE_ASAP) { pthread_spin_unlock(&c->lock); continue; } if (net_try_write(c->fd, res, strlen(res), 10, NET_NONBLOCK) == -1) { xcb_log(XCB_LOG_WARNING, "Writing to client '%p': %s", c, strerror(errno)); if (++c->eagcount >= 10) client_free_async(c); } else if (c->eagcount) c->eagcount = 0; pthread_spin_unlock(&c->lock); } dlist_iter_free(&iter); } dlist_rwlock_unlock(monitors); /* FIXME */ if (quote->thyquote.m_nTime == 999999999) { FREE(buf); return; } else if ((tlen = intlen(quote->thyquote.m_nTime)) < 10) { struct timeval tv; struct tm lt; gettimeofday(&tv, NULL); localtime_r(&tv.tv_sec, <); if (quote->thyquote.m_cHYDM[0] == 'S' && quote->thyquote.m_cHYDM[1] == 'P') quote->thyquote.m_nTime *= 1000; else if (tlen == 6 || tlen == 7) quote->thyquote.m_nTime *= 100; lt.tm_hour = quote->thyquote.m_nTime / 10000000; lt.tm_min = quote->thyquote.m_nTime % 10000000 / 100000; lt.tm_sec = quote->thyquote.m_nTime % 100000 / 1000; quote->m_nMSec = quote->thyquote.m_nTime % 1000; quote->thyquote.m_nTime = mktime(<); } /* FIXME */ if (addms) { struct timeval tv; dstr contract = dstr_new(quote->thyquote.m_cHYDM); struct sms *sms; gettimeofday(&tv, NULL); if ((sms = table_get_value(times, contract)) == NULL) { if (NEW(sms)) { sms->qsec = quote->thyquote.m_nTime; sms->sec = tv.tv_sec; sms->msec = tv.tv_usec / 1000; table_insert(times, contract, sms); } } else if (sms->qsec != quote->thyquote.m_nTime) { sms->qsec = quote->thyquote.m_nTime; sms->sec = tv.tv_sec; sms->msec = tv.tv_usec / 1000; dstr_free(contract); } else { int32_t offset; if ((offset = (tv.tv_sec - sms->sec) * 1000 + tv.tv_usec / 1000 - sms->msec) > 999) offset = 999; quote->m_nMSec = offset; dstr_free(contract); } } } if (NEW0(msg) == NULL) { FREE(buf); return; } msg->data = buf; msg->refcount = 1; thrpool_queue(tp, send_quote, msg, NULL, msgfree, NULL); } else FREE(buf); }
void process_quote(void *data) { Quote *quote; struct msg *msg; quote = (Quote *)data; if (quote->thyquote.m_nLen == sizeof (tHYQuote)) { dlist_iter_t iter; dlist_node_t node; int tlen; quote->thyquote.m_cJYS[sizeof quote->thyquote.m_cJYS - 1] = '\0'; quote->thyquote.m_cHYDM[sizeof quote->thyquote.m_cHYDM - 1] = '\0'; quote->m_nMSec = 0; /* in case of multiple monitors */ dlist_rwlock_rdlock(monitors); if (dlist_length(monitors) > 0) { char res[512]; snprintf(res, sizeof res, "RX '%d,%s,%s,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f," "%.2f,%.2f,%d,%.2f,%d,%d,%.2f,%d,%.2f,%d'\r\n", quote->thyquote.m_nTime, quote->thyquote.m_cHYDM, quote->thyquote.m_cJYS, quote->thyquote.m_dZXJ, quote->thyquote.m_dJKP, quote->thyquote.m_dZGJ, quote->thyquote.m_dZDJ, quote->thyquote.m_dZSP, quote->thyquote.m_dJSP, quote->thyquote.m_dZJSJ, quote->thyquote.m_dJJSJ, quote->thyquote.m_nCJSL, quote->thyquote.m_dCJJE, quote->thyquote.m_nZCCL, quote->thyquote.m_nCCL, quote->thyquote.m_dMRJG1, quote->thyquote.m_nMRSL1, quote->thyquote.m_dMCJG1, quote->thyquote.m_nMCSL1); iter = dlist_iter_new(monitors, DLIST_START_HEAD); while ((node = dlist_next(iter))) { client c = (client)dlist_node_value(node); pthread_spin_lock(&c->lock); if (!(c->flags & CLIENT_CLOSE_ASAP)) { if (net_try_write(c->fd, res, strlen(res), 10, NET_NONBLOCK) == -1) { xcb_log(XCB_LOG_WARNING, "Writing to client '%p': %s", c, strerror(errno)); if (++c->eagcount >= 3) client_free_async(c); } else if (c->eagcount) c->eagcount = 0; } pthread_spin_unlock(&c->lock); } dlist_iter_free(&iter); } dlist_rwlock_unlock(monitors); /* FIXME */ if (quote->thyquote.m_nTime == 999999999) { FREE(data); return; /* idiosyncrasy of different timestamps */ } else if ((tlen = intlen(quote->thyquote.m_nTime)) < 10) { int hour; struct tm lt; hour = quote->thyquote.m_nTime / 10000000; if (tv.tv_sec == 0 || hour == 9 || hour == 21) gettimeofday(&tv, NULL); if (prev_hour == 23 && hour == 0) tv.tv_sec += 24 * 60 * 60; prev_hour = hour; localtime_r(&tv.tv_sec, <); if (quote->thyquote.m_cHYDM[0] == 'S' && quote->thyquote.m_cHYDM[1] == 'P') quote->thyquote.m_nTime *= 1000; else if (tlen == 6 || tlen == 7) quote->thyquote.m_nTime *= 100; lt.tm_sec = quote->thyquote.m_nTime % 100000 / 1000; lt.tm_min = quote->thyquote.m_nTime % 10000000 / 100000; lt.tm_hour = hour; quote->m_nMSec = quote->thyquote.m_nTime % 1000; quote->thyquote.m_nTime = mktime(<); } /* FIXME: no millisecond field in some exchanges' quotes */ if (addms) { struct timeval tv; dstr contract = dstr_new(quote->thyquote.m_cHYDM); struct sms *sms; gettimeofday(&tv, NULL); if ((sms = table_get_value(times, contract)) == NULL) { if (NEW(sms)) { sms->qsec = quote->thyquote.m_nTime; sms->sec = tv.tv_sec; sms->msec = tv.tv_usec / 1000; table_insert(times, contract, sms); } } else if (sms->qsec != quote->thyquote.m_nTime) { sms->qsec = quote->thyquote.m_nTime; sms->sec = tv.tv_sec; sms->msec = tv.tv_usec / 1000; dstr_free(contract); } else { int32_t offset; if ((offset = (tv.tv_sec - sms->sec) * 1000 + tv.tv_usec / 1000 - sms->msec) > 999) offset = 999; quote->m_nMSec = offset; dstr_free(contract); } } if (get_logger_level() == __LOG_DEBUG) { time_t t = (time_t)quote->thyquote.m_nTime; char datestr[64]; strftime(datestr, sizeof datestr, "%F %T", localtime(&t)); xcb_log(XCB_LOG_DEBUG, "%s.%03d,%s,%s,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f," "%d,%.2f,%d,%d,%.2f,%d,%.2f,%d", datestr, quote->m_nMSec, quote->thyquote.m_cHYDM, quote->thyquote.m_cJYS, quote->thyquote.m_dZXJ, quote->thyquote.m_dJKP, quote->thyquote.m_dZGJ, quote->thyquote.m_dZDJ, quote->thyquote.m_dZSP, quote->thyquote.m_dJSP, quote->thyquote.m_dZJSJ, quote->thyquote.m_dJJSJ, quote->thyquote.m_nCJSL, quote->thyquote.m_dCJJE, quote->thyquote.m_nZCCL, quote->thyquote.m_nCCL, quote->thyquote.m_dMRJG1, quote->thyquote.m_nMRSL1, quote->thyquote.m_dMCJG1, quote->thyquote.m_nMCSL1); } } else xcb_log(XCB_LOG_DEBUG, "Data '%s' received", data); if (NEW0(msg) == NULL) { FREE(data); return; } msg->data = data; msg->refcount = 1; thrpool_queue(tp, send_quote, msg, NULL, msgfree, NULL); }
static int send_quote(void *data, void *data2) { struct msg *msg = (struct msg *)data; Quote *quote; int status; NOT_USED(data2); quote = (Quote *)msg->data; if (quote->thyquote.m_nLen == sizeof (THYQuote)) { if (get_logger_level() == __LOG_DEBUG) { time_t t = (time_t)quote->thyquote.m_nTime; char datestr[64]; strftime(datestr, sizeof datestr, "%F %T", localtime(&t)); xcb_log(XCB_LOG_DEBUG, "%s.%03d,%s,%s,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f," "%d,%.2f,%d,%d,%.2f,%d,%.2f,%d", datestr, quote->m_nMSec, quote->thyquote.m_cHYDM, quote->thyquote.m_cJYS, quote->thyquote.m_dZXJ, quote->thyquote.m_dJKP, quote->thyquote.m_dZGJ, quote->thyquote.m_dZDJ, quote->thyquote.m_dZSP, quote->thyquote.m_dJSP, quote->thyquote.m_dZJSJ, quote->thyquote.m_dJJSJ, quote->thyquote.m_nCJSL, quote->thyquote.m_dCJJE, quote->thyquote.m_nZCCL, quote->thyquote.m_nCCL, quote->thyquote.m_dMRJG1, quote->thyquote.m_nMRSL1, quote->thyquote.m_dMCJG1, quote->thyquote.m_nMCSL1); } /* for testing */ dlist_rwlock_rdlock(monitors); if (dlist_length(monitors) > 0) { char res[512]; dlist_iter_t iter = dlist_iter_new(monitors, DLIST_START_HEAD); dlist_node_t node; snprintf(res, sizeof res, "TX '%d,%s,%s,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f," "%d,%.2f,%d,%d,%.2f,%d,%.2f,%d'\r\n", quote->thyquote.m_nTime, quote->thyquote.m_cHYDM, quote->thyquote.m_cJYS, quote->thyquote.m_dZXJ, quote->thyquote.m_dJKP, quote->thyquote.m_dZGJ, quote->thyquote.m_dZDJ, quote->thyquote.m_dZSP, quote->thyquote.m_dJSP, quote->thyquote.m_dZJSJ, quote->thyquote.m_dJJSJ, quote->thyquote.m_nCJSL, quote->thyquote.m_dCJJE, quote->thyquote.m_nZCCL, quote->thyquote.m_nCCL, quote->thyquote.m_dMRJG1, quote->thyquote.m_nMRSL1, quote->thyquote.m_dMCJG1, quote->thyquote.m_nMCSL1); while ((node = dlist_next(iter))) { client c = (client)dlist_node_value(node); pthread_spin_lock(&c->lock); if (c->flags & CLIENT_CLOSE_ASAP) { pthread_spin_unlock(&c->lock); continue; } if (net_try_write(c->fd, res, strlen(res), 10, NET_NONBLOCK) == -1) { xcb_log(XCB_LOG_WARNING, "Writing to client '%p': %s", c, strerror(errno)); if (++c->eagcount >= 10) client_free_async(c); } else if (c->eagcount) c->eagcount = 0; pthread_spin_unlock(&c->lock); } dlist_iter_free(&iter); } dlist_rwlock_unlock(monitors); } /* FIXME */ if ((status = pgm_send(pgm_sender, msg->data, sizeof (Quote), NULL)) != PGM_IO_STATUS_NORMAL) xcb_log(XCB_LOG_WARNING, "Sending data failed"); msg_decr(msg); return 0; }
/* FIXME */ void s_command(client c) { dstr pkey, skey; int i; dlist_t dlist; struct kvd *kvd; if (dstr_length(c->argv[0]) == 1) { add_reply_error(c, "index can't be empty\r\n"); return; } pkey = dstr_new(c->argv[0] + 1); skey = dstr_new(pkey); if (c->argc > 1) for (i = 1; i < c->argc; ++i) { skey = dstr_cat(skey, ","); skey = dstr_cat(skey, c->argv[i]); } table_lock(cache); if ((dlist = table_get_value(cache, pkey))) { dlist_iter_t iter = dlist_iter_new(dlist, DLIST_START_HEAD); dlist_node_t node; /* FIXME: still has room to improve */ while ((node = dlist_next(iter))) { kvd = (struct kvd *)dlist_node_value(node); if (dstr_length(kvd->key) >= dstr_length(skey) && !memcmp(kvd->key, skey, dstr_length(skey))) { dstr *fields = NULL; int nfield = 0; dstr res, contracts = NULL; fields = dstr_split_len(kvd->key, dstr_length(kvd->key), ",", 1, &nfield); res = dstr_new(fields[0]); if (nfield > 1) { contracts = dstr_new(fields[1]); for (i = 2; i < nfield; ++i) { contracts = dstr_cat(contracts, ","); contracts = dstr_cat(contracts, fields[i]); } } dstr_free_tokens(fields, nfield); fields = NULL, nfield = 0; fields = dstr_split_len(kvd->u.value, dstr_length(kvd->u.value), ",", 1, &nfield); res = dstr_cat(res, ","); res = dstr_cat(res, fields[0]); if (contracts) { res = dstr_cat(res, ","); res = dstr_cat(res, contracts); } for (i = 1; i < nfield; ++i) { res = dstr_cat(res, ","); res = dstr_cat(res, fields[i]); } res = dstr_cat(res, "\r\n"); pthread_spin_lock(&c->lock); if (!(c->flags & CLIENT_CLOSE_ASAP)) { if (net_try_write(c->fd, res, dstr_length(res), 10, NET_NONBLOCK) == -1) { xcb_log(XCB_LOG_WARNING, "Writing to client '%p': %s", c, strerror(errno)); if (++c->eagcount >= 3) { client_free_async(c); pthread_spin_unlock(&c->lock); dstr_free(contracts); dstr_free(res); dstr_free_tokens(fields, nfield); table_unlock(cache); dstr_free(skey); dstr_free(pkey); return; } } else if (c->eagcount) c->eagcount = 0; } pthread_spin_unlock(&c->lock); dstr_free(contracts); dstr_free(res); dstr_free_tokens(fields, nfield); } } dlist_iter_free(&iter); } table_unlock(cache); table_rwlock_wrlock(subscribers); if ((dlist = table_get_value(subscribers, pkey)) == NULL) { if (NEW(kvd)) { kvd->key = skey; kvd->u.dlist = dlist_new(NULL, NULL); dlist_insert_tail(kvd->u.dlist, c); dlist = dlist_new(cmpkvd, kdfree); dlist_insert_sort(dlist, kvd); table_insert(subscribers, pkey, dlist); } else { add_reply_error(c, "error allocating memory for kvd\r\n"); dstr_free(skey); dstr_free(pkey); } } else { if (NEW(kvd)) { dlist_node_t node; kvd->key = skey; kvd->u.dlist = dlist_new(NULL, NULL); if ((node = dlist_find(dlist, kvd)) == NULL) { dlist_insert_tail(kvd->u.dlist, c); dlist_insert_sort(dlist, kvd); } else { kdfree(kvd); kvd = (struct kvd *)dlist_node_value(node); if (dlist_find(kvd->u.dlist, c) == NULL) dlist_insert_tail(kvd->u.dlist, c); } } else { add_reply_error(c, "error allocating memory for kvd\r\n"); dstr_free(skey); } dstr_free(pkey); } table_rwlock_unlock(subscribers); }