/* * Dump debugging state to a result string */ bool_t rcmd_debug_dump_to_string_1_svc(char **result, struct svc_req *rqstp) { char* buffer = NULL; size_t buffer_size = 0; FILE* fp = NULL; fp = open_memstream(&buffer, &buffer_size); if (!fp) { error_perror("unable to create in-memory file"); *result = xstrdup("Error: out of memory"); goto cleanup; } show_debugging_info(fp); fclose(fp); *result = buffer ? buffer : xstrdup("Error: out of memory"); cleanup: return true; }
/* * Commit current xenstore transaction. * * Returns: * XSTS_OK success * XSTS_RETRY retry the transaction * XSTS_NORETRY out of retry limit (message logged) * XSTS_FAIL commit failed (message logged) */ static XsTransactionStatus commit_xs(int* p_nretries) { if (xst == XS_TRANSACTION_NULL) fatal_msg("bug: commit_xs outside of a transaction"); if (xs_transaction_end(xs, xst, FALSE)) { debug_msg(15, "committed transaction"); xst = XS_TRANSACTION_NULL; return XSTS_OK; } xst = XS_TRANSACTION_NULL; if (errno == EAGAIN) { if (++(*p_nretries) > max_xs_retries) { error_perror("unable to write xenstore (transaction retry limit exceeded)"); return XSTS_NORETRY; } retry_wait(*p_nretries); debug_msg(2, "restarting xenstore transaction"); return XSTS_RETRY; } else { error_perror("unable to write xenstore (xs_transaction_end)"); return XSTS_FAIL; } }
int net_packet_push_lua(int len, const char *data, int sockfd, packet_t **head, packet_t **tail) { if(len+4 > PACKET_LEN_MAX) { fprintf(stderr, "net_packet_new: packet too large (%i > %i)\n" , len, PACKET_LEN_MAX-4); return 1; } if(len < 1) { fprintf(stderr, "net_packet_new: packet too small (%i < 1)\n" , len); return 1; } int poffs = (len >= 64 ? 3 : 1); packet_t *pkt = (packet_t*)malloc(sizeof(packet_t)+len+poffs); if(pkt == NULL) { error_perror("net_packet_new"); return 1; } pkt->data[0] = (poffs == 1 ? len+0x3F : 0x7F); if(poffs != 1) { pkt->data[1] = len&255; pkt->data[2] = len>>8; }
/* * Start XenStore transaction. * If successful, return @true. * On error, return @false and log error message. . */ static bool begin_xs(void) { int nretries = 0; if (xst != XS_TRANSACTION_NULL) fatal_msg("bug: begin_xs inside a transaction"); for (;;) { xst = xs_transaction_start(xs); if (xst != XS_TRANSACTION_NULL) break; /* * ENOSPC means too many concurrent transactions from the domain */ if (errno == ENOSPC) { if (++nretries > max_xs_retries) { error_perror("unable to start xenstore transaction (retry limit exceeded)"); break; } retry_wait(nretries); debug_msg(2, "retrying to start xenstore transaction"); } else { error_perror("unable to start xenstore transaction"); break; } } if (xst != XS_TRANSACTION_NULL) { debug_msg(15, "started transaction"); return true; } else { return false; } }
int net_packet_push(int len, const char *data, int neth, packet_t **head, packet_t **tail) { if(len > PACKET_LEN_MAX) { fprintf(stderr, "net_packet_new: packet too large (%i > %i)\n" , len, PACKET_LEN_MAX); return 1; } client_t *cli = net_neth_get_client(neth); if(cli == NULL) { fprintf(stderr, "Note: NULL client in packet pusher, ignoring\n"); return 0; //fflush(stderr); //abort(); } if(cli->sockfd == SOCKFD_ENET) { ENetPacket *ep = enet_packet_create(data, len, ENET_PACKET_FLAG_RELIABLE); enet_peer_send(cli->peer, 1, ep); } else { if(len < 1) { fprintf(stderr, "net_packet_new: packet too small (%i < 1)\n" , len); return 1; } packet_t *pkt = (packet_t*)malloc(sizeof(packet_t)+len); if(pkt == NULL) { error_perror("net_packet_new"); return 1; } memcpy(pkt->data, data, len); pkt->len = len; pkt->neth = neth; if(*head == NULL) { pkt->p = pkt->n = NULL; *head = *tail = pkt; } else { (*tail)->n = pkt; pkt->p = (*tail); pkt->n = NULL; *tail = pkt; } } return 0; }
/* * Handle poll(...) completion. * Return @true if any event was processed, * @false otherwise. */ bool rcmd_handle_pollfds(struct pollfd* pollfds) { struct pollfd* pollfd; int nfds = svc_max_pollfd; int k, fd; struct sockaddr_un addr; socklen_t addrlen = sizeof addr; bool res = false; /* any events on RPC connection sockets? */ for (k = 0; k < nfds; k++) { if (pollfds[k].revents && pollfds[k].fd != -1) res = true; } /* handle events on RPC connection sockets */ if (res) { debug_msg(40, "calling svc_getreq_poll"); svc_getreq_poll(pollfds, nfds); debug_msg(40, "finished svc_getreq_poll"); } /* handle events (if any) on the listener socket */ if (sock != -1) { pollfd = pollfds + nfds; if (pollfd->revents & pollfd->events) { res = true; debug_msg(12, "accepting RPC connection"); DO_RESTARTABLE(fd, accept(sock, (struct sockaddr*) &addr, &addrlen)); if (fd == -1) { error_perror("unable to accept RPC connection"); } else { debug_msg(12, "accepted RPC connection"); SVCXPRT* transp = svcunixfd_create(fd, 0, 0); if (transp == NULL) { error_msg("unable to accept RPC connection (svcunixfd_create failed)"); close(fd); } } } } return res; }
/* * Read and apply updated membalance settings */ static void update_membalance_settings(void) { char *pv = NULL; unsigned int len; long v; char* ep = NULL; if (!subscribed_membalance) return; pv = xs_read(xs, xst, membalance_interval_path, &len); if (!pv) { /* * In the event of a temporary glitch, schedule to read the * settings a little later. Could be a temporary shortage * of resources, or membalanced did not yet add this VM to the * permission list on the key. */ error_perror("unable to read xenstore (%s)", membalance_interval_path); need_update_membalance_settings = true; return; } need_update_membalance_settings = false; errno = 0; v = strtol(pv, &ep, 10); if (errno || ep == pv || *ep || v <= 0) { error_msg("ignoring invalid refresh interval setting"); goto cleanup; } /* sanity check */ if (v > max_interval) { error_msg("restricting value of refresh interval to %d seconds", max_interval); v = max_interval; } interval = v; debug_msg(2, "updated interval to %d seconds", interval); cleanup: if (pv) free(pv); }
int model_save_pmf(model_t *pmf, const char *fname) { int i,j; FILE *fp = fopen(fname, "wb"); // check for errors if(fp == NULL) return error_perror("model_save_pmf"); // and now we crawl through the spec. // start with the header of "PMF",0x1A,1,0,0,0 char head[8]; fwrite("PMF\x1A\x01\x00\x00\x00", 8, 1, fp); // then there's a uint32_t denoting how many body parts there are uint32_t bone_count = pmf->bonelen; fwrite(&bone_count, 4, 1, fp); // then, for each body part, for(i = 0; i < (int)bone_count; i++) { // there's a null-terminated 16-byte string (max 15 chars) denoting the part fwrite(pmf->bones[i]->name, 16, 1, fp); // then there's a uint32_t denoting how many points there are in this body part uint32_t pt_count = pmf->bones[i]->ptlen; fwrite(&pt_count, 4, 1, fp); // then there's a whole bunch of this: // uint16_t radius; // int16_t x,y,z; // uint8_t b,g,r,reserved; fwrite(pmf->bones[i]->pts, sizeof(model_point_t), pt_count, fp); // rinse, lather, repeat // units are 8:8 fixed point in terms of the vxl grid by default } fclose(fp); return 0; }
int net_packet_push_lua_enet(int len, const char *data, int neth, packet_t **head, packet_t **tail) { if(len+4 > PACKET_LEN_MAX) { fprintf(stderr, "net_packet_new: packet too large (%i > %i)\n" , len, PACKET_LEN_MAX-4); return 1; } if(len < 1) { fprintf(stderr, "net_packet_new: packet too small (%i < 1)\n" , len); return 1; } client_t *cli = net_neth_get_client(neth); if(cli == NULL) { fprintf(stderr, "Note: NULL client in packet pusher, ignoring\n"); return 0; //fflush(stderr); //abort(); } int poffs = (len >= 64 ? 3 : 1); packet_t *pkt = (packet_t*)malloc(sizeof(packet_t)+len+poffs); if(pkt == NULL) { error_perror("net_packet_new"); return 1; } pkt->data[0] = (poffs == 1 ? len+0x3F : 0x7F); if(poffs != 1) { pkt->data[1] = len&255; pkt->data[2] = len>>8; }
int net_packet_push(int len, const char *data, int sockfd, packet_t **head, packet_t **tail) { if(len > PACKET_LEN_MAX) { fprintf(stderr, "net_packet_new: packet too large (%i > %i)\n" , len, PACKET_LEN_MAX); return 1; } if(len < 1) { fprintf(stderr, "net_packet_new: packet too small (%i < 1)\n" , len); return 1; } packet_t *pkt = (packet_t*)malloc(sizeof(packet_t)+len); if(pkt == NULL) { error_perror("net_packet_new"); return 1; } memcpy(pkt->data, data, len); pkt->len = len; pkt->sockfd = sockfd; if(*head == NULL) { pkt->p = pkt->n = NULL; *head = *tail = pkt; } else { (*tail)->n = pkt; pkt->p = (*tail); pkt->n = NULL; *tail = pkt; } return 0; }
model_t *model_parse_pmf(int len, const char *data) { int i,j; const char *p = data; const char *dend = data + len; // and now we crawl through the spec. // start with the header of "PMF",0x1A,1,0,0,0 char head[8]; if(memcmp(p, "PMF\x1A\x01\x00\x00\x00", 8)) { fprintf(stderr, "model_load_pmf: not a valid PMF v1 file\n"); return NULL; } p += 8; // then there's a uint32_t denoting how many body parts there are uint32_t bone_count = *(uint32_t *)p; p += 4; if(bone_count > MODEL_BONE_MAX) { fprintf(stderr, "model_parse_pmf: too many bones (%i > %i)\n" , bone_count, MODEL_BONE_MAX); return NULL; } model_t *pmf = model_new(bone_count); if(pmf == NULL) { error_perror("model_parse_pmf"); return NULL; } pmf->udtype = UD_PMF; // then, for each body part, for(i = 0; i < (int)bone_count; i++) { // there's a null-terminated 16-byte string (max 15 chars) denoting the part const char *namebuf = p; p += 16; if(namebuf[15] != '\x00') { fprintf(stderr, "model_load_pmf: name not null terminated\n"); model_free(pmf); return NULL; } // then there's a uint32_t denoting how many points there are in this body part uint32_t pt_count = *(uint32_t *)p; p += 4; // (just allocating the bone here) model_bone_t *bone = model_bone_new(pmf, pt_count); pmf = bone->parent; memcpy(bone->name, namebuf, 16); if(bone == NULL) { error_perror("model_parse_pmf"); model_free(pmf); return NULL; } // then there's a whole bunch of this: // uint16_t radius; // int16_t x,y,z; // uint8_t b,g,r,reserved; int bonelen = sizeof(model_point_t)*pt_count; memcpy(bone->pts, p, bonelen); p += bonelen; bone->ptlen = pt_count; // "reserved" needs to be 0 or else you suck // NO SIDECHANNELING YOUR NAME IN THERE // i'm going to enforce this in the loader // and will outright reject files which don't have 0 in ALL of these slots for(j = 0; j < bone->ptmax; j++) if(bone->pts[j].resv1 != 0) { fprintf(stderr, "model_load_pmf: file corrupted or made by a smartass\n"); model_free(pmf); return NULL; } // rinse, lather, repeat // units are 8:8 fixed point in terms of the vxl grid by default } return pmf; }
/* * Initialize xenstore structure. * May have to be called multiple times. * * On the very first call always opens xs connection. * Aborts if unable to open xs connection in a reasonable time. * Always returns the very first time with xs != null. * * Also tries to initialize other xs structures. * If successful, returns with @initialized_xs = true. * If unsuccessful, returns with @initialized_xs = false and must be called * again later to retry the initialization. * * @pollfds defines of signal-handling descriptors to be watched if has to wait * during the initialization. Better be non-NULL on the first call, but can be * left NULL on subsequent calls (as they do not wait long). * * Will not touch pollfds[NPFD_XS]. */ static void initialize_xs(struct pollfd *pollfds) { XsTransactionStatus status; char *keyvalue = NULL; unsigned int len; int nretries; /* already initialized? */ if (initialized_xs) return; /* open a connection to xenstore*/ open_xs_connection(pollfds); /* * Try to reset the report key. */ for (nretries = 0; ;) { /* * Wait until xenstore "membalance/report_path" key and the key it points * to have been created by membalanced with appropriate access permissions. * * First try without actual transaction, to make the cost for * xenstore cheaper. */ if (membalance_report_path == NULL) { CHECK(begin_singleop_xs()); keyvalue = xs_read(xs, xst, membalance_report_link_path, &len); if (keyvalue == NULL) { if (errno != ENOENT) error_perror("cannot read xenstore (%s)", membalance_report_link_path); debug_msg(3, "%s does not exist yet", membalance_report_link_path); /* * Leave initialzed_xs = false, so will retry later */ abort_singleop_xs(); return; } membalance_report_path = keyvalue; abort_singleop_xs(); } if (nretries == 0) { CHECK(begin_singleop_xs()); keyvalue = xs_read(xs, xst, membalance_report_path, &len); if (keyvalue == NULL) { if (errno != ENOENT) error_perror("cannot read xenstore (%s)", membalance_report_path); debug_msg(3, "%s does not exist yet", membalance_report_path); /* * Leave initialzed_xs = false, so will retry later */ abort_singleop_xs(); return; } free(keyvalue); abort_singleop_xs(); } /* * Wait until a key for data reporting has been created in * xenstore by membalanced with appropriate access permissions. * * Now within a real transaction. */ CHECK(begin_xs()); keyvalue = xs_read(xs, xst, membalance_report_path, &len); if (keyvalue == NULL) { if (errno != ENOENT) error_perror("cannot read xenstore (%s)", membalance_report_path); debug_msg(3, "%s does not exist yet", membalance_report_path); /* * Leave initialzed_xs = false, so will retry later */ abort_xs(); return; } free(keyvalue); PCHECK(xs_write(xs, xst, membalance_report_path, "", strlen("")), "cannot write to xenstore"); status = commit_xs(&nretries); switch (status) { case XSTS_OK: break; /* done */ case XSTS_RETRY: continue; /* keep retrying */ case XSTS_NORETRY: CHECK(false); /* abort */ case XSTS_FAIL: CHECK(false); /* abort */ } break; } initialized_xs = true; try_subscribe_membalance_settings(); return; cleanup: terminate(); }
/* * Process next sample of memory statistics data taken after another @interval. * @pd1 = current reading * @pd0 = reading taken @interval ago */ static void process_sample(const struct paging_data *pd1, const struct paging_data *pd0) { int64_t ms; int64_t kbs, kbs_sec; double free_pct; char report[512]; char struct_version = 'A'; int nretries = 0; /* discard sample if weird timing */ ms = timespec_diff_ms(pd1->ts, pd0->ts); if (ms < tolerance_ms || ms > interval * MSEC_PER_SEC * 10) return; /* discard the sample if weird data */ kbs = (int64_t) (pd1->pgpgin - pd0->pgpgin); if (kbs < 0) return; kbs_sec = (kbs * MSEC_PER_SEC) / ms; free_pct = 100.0 * (double) pd1->nr_free_pages / (double) pd1->mem_pages; /* manual override (development time only) */ if (simulated_kbs >= 0) kbs_sec = simulated_kbs; if (simulated_free_pct >= 0) free_pct = simulated_free_pct; if (log_fp && debug_level >= 3) { fprintf(log_fp, "pgpgin=%llu, nr_free_pages=%llu, kbs=%lu, kbs_sec=%lu, free%%=%f\n", (unsigned long long) pd1->pgpgin, (unsigned long long) pd1->nr_free_pages, (unsigned long) kbs, (unsigned long) kbs_sec, free_pct); } /* format memory pressure report string */ /* (could use json if data structure were more complicated and changeable) */ sprintf(report, "%c\n" "action: report\n" "progname: %s\n" "progversion: %s\n" "seq: %llu\n" "kb: %lu\n" "kbsec: %lu\n" "freepct: %f\n", struct_version, progname, progversion, report_seq++, (unsigned long) kbs, (unsigned long) kbs_sec, free_pct); /* write report data to xenstore */ for (;;) { if (!begin_singleop_xs()) break; if (!xs_write(xs, xst, membalance_report_path, report, strlen(report))) { error_perror("unable to write xenstore"); abort_singleop_xs(); break; } if (commit_singleop_xs(&nretries) != XSTS_RETRY) break; } }