data.c 27 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088
  1. /*
  2. * Copyright (c) 2001-2010 Willem Dijkstra
  3. * All rights reserved.
  4. *
  5. * The crc routine is by Rob Warnock <rpw3@sgi.com>, from the
  6. * comp.compression FAQ.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * - Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. * - Redistributions in binary form must reproduce the above
  15. * copyright notice, this list of conditions and the following
  16. * disclaimer in the documentation and/or other materials provided
  17. * with the distribution.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  22. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  23. * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  24. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  25. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  26. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  27. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  28. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  29. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  30. * POSSIBILITY OF SUCH DAMAGE.
  31. * */
  32. /* Terminology:
  33. *
  34. * A host carrying a 'symon' is considered a 'source' of information. A single
  35. * data 'stream' of information has a particular type: cpu, mem, etc. A
  36. * source can provide multiple 'streams' simultaneously. A source spools
  37. * information towards a 'mux'. A 'stream' that has been converted to network
  38. * representation is called a 'packedstream'.
  39. */
  40. #include <sys/param.h>
  41. #include <assert.h>
  42. #include <limits.h>
  43. #include <stdarg.h>
  44. #include <string.h>
  45. #include <stdio.h>
  46. #include <time.h>
  47. #include <unistd.h>
  48. #include "conf.h"
  49. #include "data.h"
  50. #include "error.h"
  51. #include "lex.h"
  52. #include "net.h"
  53. #include "xmalloc.h"
  54. __BEGIN_DECLS
  55. int bytelenvar(char);
  56. int checklen(int, int, int);
  57. struct stream *create_stream(int, char *);
  58. char *formatstrvar(char);
  59. char *rrdstrvar(char);
  60. int strlenvar(char);
  61. __END_DECLS
  62. /* Stream formats
  63. *
  64. * Format specifications are strings of characters:
  65. *
  66. * L = u_int64
  67. * D = 7.6f <= int64
  68. * l = u_int32
  69. * s = u_int16
  70. * c = 3.2f <= u_int14 <= u_int16 (used in percentages)
  71. * b = u_int8
  72. */
  73. struct {
  74. char type;
  75. char *rrdformat;
  76. char *strformat;
  77. int strlen;
  78. int bytelen;
  79. u_int64_t max;
  80. } streamvar[] = {
  81. { 'L', ":%llu", " %20llu", 22, sizeof(u_int64_t), (u_int64_t) 0xffffffffffffffffLL },
  82. { 'D', ":%7.6f", " %7.6f", 23, sizeof(int64_t), (u_int64_t) 0xffffffffffffffffLL },
  83. { 'l', ":%lu", " %10lu", 12, sizeof(u_int32_t), (u_int64_t) 0xffffffff },
  84. { 's', ":%u", " %5u", 7, sizeof(u_int16_t), (u_int64_t) 0xffff },
  85. { 'c', ":%3.2f", " %3.2f", 8, sizeof(u_int16_t), (u_int64_t) 100 },
  86. { 'b', ":%u", " %3u", 5, sizeof(u_int8_t), (u_int64_t) 255 },
  87. { '\0', NULL, NULL, 0, 0, 0 }
  88. };
  89. /* streams of <type> have the packedstream <form> */
  90. struct {
  91. int type;
  92. char *form;
  93. } streamform[] = {
  94. { MT_IO1, "LLL" },
  95. { MT_CPU, "ccccc" },
  96. { MT_MEM1, "lllll" },
  97. { MT_IF1, "llllllllll" },
  98. { MT_PF, "LLLLLLLLLLLLLLLLLLLLLL" },
  99. { MT_DEBUG, "llllllllllllllllllll" },
  100. { MT_PROC, "lLLLlcll" },
  101. { MT_MBUF, "lllllllllllllll" },
  102. { MT_SENSOR, "D" },
  103. { MT_IO2, "LLLLL" },
  104. { MT_PFQ, "LLLL" },
  105. { MT_DF, "LLLLLLL" },
  106. { MT_MEM2, "LLLLL" },
  107. { MT_IF2, "LLLLLLLLLL" },
  108. { MT_CPUIOW, "cccccc" },
  109. { MT_SMART, "bbbbbbbbbbbb" },
  110. { MT_LOAD, "ccc" },
  111. { MT_FLUKSO, "D" },
  112. { MT_TEST, "LLLLDDDDllllssssccccbbbb" },
  113. { MT_EOT, "" }
  114. };
  115. struct {
  116. int type;
  117. int token;
  118. } streamtoken[] = {
  119. { MT_IO1, LXT_IO1 },
  120. { MT_CPU, LXT_CPU },
  121. { MT_MEM1, LXT_MEM1 },
  122. { MT_IF1, LXT_IF1 },
  123. { MT_PF, LXT_PF },
  124. { MT_DEBUG, LXT_DEBUG },
  125. { MT_PROC, LXT_PROC },
  126. { MT_MBUF, LXT_MBUF },
  127. { MT_SENSOR, LXT_SENSOR },
  128. { MT_IO2, LXT_IO },
  129. { MT_PFQ, LXT_PFQ },
  130. { MT_DF, LXT_DF },
  131. { MT_MEM2, LXT_MEM },
  132. { MT_IF2, LXT_IF },
  133. { MT_CPUIOW, LXT_CPUIOW },
  134. { MT_SMART, LXT_SMART },
  135. { MT_LOAD, LXT_LOAD },
  136. { MT_FLUKSO, LXT_FLUKSO },
  137. { MT_EOT, LXT_BADTOKEN }
  138. };
  139. /* parallel crc32 table */
  140. u_int32_t
  141. crc32_table[256];
  142. /* Convert lexical entities to stream entities */
  143. int
  144. token2type(const int token)
  145. {
  146. int i;
  147. for (i = 0; streamtoken[i].type < MT_EOT; i++)
  148. if (streamtoken[i].token == token)
  149. return streamtoken[i].type;
  150. fatal("%s:%d: internal error: token (%d) could not be translated into a stream type",
  151. __FILE__, __LINE__, token);
  152. /* NOT REACHED */
  153. return 0;
  154. }
  155. /* Convert stream entities to their ascii representation */
  156. char *
  157. type2str(const int streamtype)
  158. {
  159. int i;
  160. for (i = 0; streamtoken[i].type < MT_EOT; i++)
  161. if (streamtoken[i].type == streamtype)
  162. return parse_opcode(streamtoken[i].token);
  163. fatal("%s:%d: internal error: type (%d) could not be translated into ascii representation",
  164. __FILE__, __LINE__, streamtype);
  165. /* NOT REACHED */
  166. return 0;
  167. }
  168. /* Return the maximum lenght of the ascii representation of type <type> */
  169. int
  170. strlentype(int type)
  171. {
  172. int i = 0;
  173. int sum = 0;
  174. while (streamform[type].form[i])
  175. sum += strlenvar(streamform[type].form[i++]);
  176. return sum;
  177. }
  178. /* Return the maximum lenght of the ascii representation of streamvar <var> */
  179. int
  180. strlenvar(char var)
  181. {
  182. int i;
  183. for (i = 0; streamvar[i].type > '\0'; i++)
  184. if (streamvar[i].type == var)
  185. return streamvar[i].strlen;
  186. fatal("%s:%d: internal error: type spefication for stream var '%c' not found",
  187. __FILE__, __LINE__, var);
  188. /* NOT REACHED */
  189. return 0;
  190. }
  191. /* Return the maximum lenght of the network representation of streamvar <var> */
  192. int
  193. bytelenvar(char var)
  194. {
  195. int i;
  196. for (i = 0; streamvar[i].type > '\0'; i++)
  197. if (streamvar[i].type == var)
  198. return streamvar[i].bytelen;
  199. fatal("%s:%d: internal error: type spefication for stream var '%c' not found",
  200. __FILE__, __LINE__, var);
  201. /* NOT REACHED */
  202. return 0;
  203. }
  204. /* Return the ascii format string for streamvar <var> */
  205. char *
  206. formatstrvar(char var)
  207. {
  208. int i;
  209. for (i = 0; streamvar[i].type > '\0'; i++)
  210. if (streamvar[i].type == var)
  211. return streamvar[i].strformat;
  212. fatal("%s:%d: internal error: type spefication for stream var '%c' not found",
  213. __FILE__, __LINE__, var);
  214. /* NOT REACHED */
  215. return "";
  216. }
  217. /* Return the rrd format string for streamvar <var> */
  218. char *
  219. rrdstrvar(char var)
  220. {
  221. int i;
  222. for (i = 0; streamvar[i].type > '\0'; i++)
  223. if (streamvar[i].type == var)
  224. return streamvar[i].rrdformat;
  225. fatal("internal error: type spefication for stream var '%c' not found", var);
  226. /* NOT REACHED */
  227. return "";
  228. }
  229. /* Check whether <extra> more bytes fit in <maxlen> when we are already at <start> */
  230. int
  231. checklen(int maxlen, int current, int extra)
  232. {
  233. if ((current + extra) < maxlen) {
  234. return 0;
  235. } else {
  236. warning("buffer overflow: max=%d, current=%d, extra=%d",
  237. maxlen, current, extra);
  238. return 1;
  239. }
  240. }
  241. int
  242. setheader(char *buf, struct symonpacketheader *hph)
  243. {
  244. struct symonpacketheader nph;
  245. char *p;
  246. nph.timestamp = htonq(hph->timestamp);
  247. nph.crc = htonl(hph->crc);
  248. nph.length = htons(hph->length);
  249. nph.symon_version = hph->symon_version;
  250. p = buf;
  251. bcopy(&nph.crc, p, sizeof(u_int32_t));
  252. p += sizeof(u_int32_t);
  253. bcopy(&nph.timestamp, p, sizeof(u_int64_t));
  254. p += sizeof(u_int64_t);
  255. bcopy(&nph.length, p, sizeof(u_int16_t));
  256. p += sizeof(u_int16_t);
  257. bcopy(&nph.symon_version, p, sizeof(u_int8_t));
  258. p += sizeof(u_int8_t);
  259. return (p - buf);
  260. }
  261. int
  262. getheader(char *buf, struct symonpacketheader *hph)
  263. {
  264. char *p;
  265. p = buf;
  266. bcopy(p, &hph->crc, sizeof(u_int32_t));
  267. p += sizeof(u_int32_t);
  268. bcopy(p, &hph->timestamp, sizeof(u_int64_t));
  269. p += sizeof(u_int64_t);
  270. bcopy(p, &hph->length, sizeof(u_int16_t));
  271. p += sizeof(u_int16_t);
  272. bcopy(p, &hph->symon_version, sizeof(u_int8_t));
  273. p += sizeof(u_int8_t);
  274. hph->timestamp = ntohq(hph->timestamp);
  275. hph->crc = ntohl(hph->crc);
  276. hph->length = ntohs(hph->length);
  277. return (p - buf);
  278. }
  279. /*
  280. * Pack multiple arguments of a MT_TYPE into a network order bytestream.
  281. * snpack returns the number of bytes actually stored.
  282. */
  283. int
  284. snpack(char *buf, int maxlen, char *id, int type,...)
  285. {
  286. int result;
  287. va_list ap;
  288. /* default to v2 packets */
  289. va_start(ap, type);
  290. result = snpackx(SYMON_PS_ARGLENV2, buf, maxlen, id, type, ap);
  291. va_end(ap);
  292. return result;
  293. }
  294. int
  295. snpack1(char *buf, int maxlen, char *id, int type, ...)
  296. {
  297. int result;
  298. va_list ap;
  299. va_start(ap, type);
  300. result = snpackx(SYMON_PS_ARGLENV1, buf, maxlen, id, type, ap);
  301. va_end(ap);
  302. return result;
  303. }
  304. int
  305. snpack2(char *buf, int maxlen, char *id, int type, ...)
  306. {
  307. int result;
  308. va_list ap;
  309. va_start(ap, type);
  310. result = snpackx(SYMON_PS_ARGLENV2, buf, maxlen, id, type, ap);
  311. va_end(ap);
  312. return result;
  313. }
  314. int
  315. snpackx(size_t maxarglen, char *buf, int maxlen, char *id, int type, va_list ap)
  316. {
  317. u_int16_t b;
  318. u_int16_t s;
  319. u_int16_t c;
  320. u_int32_t l;
  321. u_int64_t q;
  322. int64_t d;
  323. double D;
  324. int i = 0;
  325. int offset = 0;
  326. int arglen = 0;
  327. if (type > MT_EOT) {
  328. warning("stream type (%d) out of range", type);
  329. return 0;
  330. }
  331. if (maxlen < 2) {
  332. fatal("%s:%d: maxlen too small", __FILE__, __LINE__);
  333. } else {
  334. buf[offset++] = type & 0xff;
  335. }
  336. if (id) {
  337. arglen = MIN(strlen(id), SYMON_PS_ARGLENV2 - 1);
  338. } else {
  339. id = "\0";
  340. arglen = 1;
  341. }
  342. if (checklen(maxlen, offset, arglen)) {
  343. return offset;
  344. } else {
  345. strncpy(&buf[offset], id, arglen);
  346. offset += arglen + 1;
  347. }
  348. while (streamform[type].form[i] != '\0') {
  349. if (checklen(maxlen, offset, bytelenvar(streamform[type].form[i])))
  350. return offset;
  351. /*
  352. * all values smaller than 32 bytes are transferred using ints on the
  353. * stack. This is to ensure that we get the correct value, if the
  354. * compiler decided to upgrade our short to a 32bit int. -- cheers
  355. * dhartmei@openbsd.org
  356. */
  357. switch (streamform[type].form[i]) {
  358. case 'b':
  359. b = va_arg(ap, int);
  360. buf[offset++] = b;
  361. break;
  362. case 'c':
  363. D = va_arg(ap, double);
  364. c = (u_int16_t) (D * 100.0);
  365. c = htons(c);
  366. bcopy(&c, buf + offset, sizeof(u_int16_t));
  367. offset += sizeof(u_int16_t);
  368. break;
  369. case 's':
  370. s = va_arg(ap, int);
  371. s = htons(s);
  372. bcopy(&s, buf + offset, sizeof(u_int16_t));
  373. offset += sizeof(u_int16_t);
  374. break;
  375. case 'l':
  376. l = va_arg(ap, u_int32_t);
  377. l = htonl(l);
  378. bcopy(&l, buf + offset, sizeof(u_int32_t));
  379. offset += sizeof(u_int32_t);
  380. break;
  381. case 'L':
  382. q = va_arg(ap, u_int64_t);
  383. q = htonq(q);
  384. bcopy(&q, buf + offset, sizeof(u_int64_t));
  385. offset += sizeof(u_int64_t);
  386. break;
  387. case 'D':
  388. D = va_arg(ap, double);
  389. d = (int64_t) (D * 1000 * 1000);
  390. d = htonq(d);
  391. bcopy(&d, buf + offset, sizeof(int64_t));
  392. offset += sizeof(int64_t);
  393. break;
  394. default:
  395. warning("unknown stream format identifier %c in type %d",
  396. streamform[type].form[i],
  397. type);
  398. return 0;
  399. }
  400. i++;
  401. }
  402. return offset;
  403. }
  404. /*
  405. * Unpack a packedstream in buf into a struct packetstream. Returns the number
  406. * of bytes actually read.
  407. *
  408. * Note that this function does "automatic" bounds checking; it uses a
  409. * description of the packedstream (streamform) to parse the actual bytes. This
  410. * description corresponds to the amount of bytes that will fit inside the
  411. * packedstream structure. */
  412. int
  413. sunpack(char *buf, struct packedstream *ps)
  414. {
  415. /* default to version 2 */
  416. return sunpackx(SYMON_PS_ARGLENV2, buf, ps);
  417. }
  418. int
  419. sunpack1(char *buf, struct packedstream *ps)
  420. {
  421. return sunpackx(SYMON_PS_ARGLENV1, buf, ps);
  422. }
  423. int
  424. sunpack2(char *buf, struct packedstream *ps)
  425. {
  426. return sunpackx(SYMON_PS_ARGLENV2, buf, ps);
  427. }
  428. int
  429. sunpackx(size_t arglen, char *buf, struct packedstream *ps)
  430. {
  431. char *in, *out;
  432. int i = 0;
  433. int type;
  434. u_int16_t s;
  435. u_int16_t c;
  436. u_int32_t l;
  437. u_int64_t q;
  438. int64_t d;
  439. bzero(ps, sizeof(struct packedstream));
  440. in = buf;
  441. if ((*in) > MT_EOT) {
  442. warning("unpack failure: stream type (%d) out of range", (*in));
  443. return -1;
  444. }
  445. type = ps->type = (*in);
  446. in++;
  447. if ((*in) != '\0') {
  448. strncpy(ps->arg, in, arglen);
  449. ps->arg[arglen - 1] = '\0';
  450. in += strlen(ps->arg) + 1;
  451. } else {
  452. ps->arg[0] = '\0';
  453. in++;
  454. }
  455. out = (char *) (&ps->data);
  456. while (streamform[type].form[i] != '\0') {
  457. switch (streamform[type].form[i]) {
  458. case 'b':
  459. bcopy((void *) in, (void *) out, sizeof(u_int8_t));
  460. in++;
  461. out++;
  462. break;
  463. case 'c':
  464. bcopy((void *) in, &c, sizeof(u_int16_t));
  465. c = ntohs(c);
  466. bcopy(&c, (void *) out, sizeof(u_int16_t));
  467. in += sizeof(u_int16_t);
  468. out += sizeof(u_int16_t);
  469. break;
  470. case 's':
  471. bcopy((void *) in, &s, sizeof(u_int16_t));
  472. s = ntohs(s);
  473. bcopy(&s, (void *) out, sizeof(u_int16_t));
  474. in += sizeof(u_int16_t);
  475. out += sizeof(u_int16_t);
  476. break;
  477. case 'l':
  478. bcopy((void *) in, &l, sizeof(u_int32_t));
  479. l = ntohl(l);
  480. bcopy(&l, (void *) out, sizeof(u_int32_t));
  481. in += sizeof(u_int32_t);
  482. out += sizeof(u_int32_t);
  483. break;
  484. case 'L':
  485. bcopy((void *) in, &q, sizeof(u_int64_t));
  486. q = ntohq(q);
  487. bcopy(&q, (void *) out, sizeof(u_int64_t));
  488. in += sizeof(u_int64_t);
  489. out += sizeof(u_int64_t);
  490. break;
  491. case 'D':
  492. bcopy((void *) in, &d, sizeof(int64_t));
  493. d = ntohq(d);
  494. bcopy(&d, (void *) out, sizeof(int64_t));
  495. in += sizeof(int64_t);
  496. out += sizeof(int64_t);
  497. break;
  498. default:
  499. warning("unknown stream format identifier %c in type %d",
  500. streamform[type].form[i],
  501. type);
  502. return 0;
  503. }
  504. i++;
  505. }
  506. return (in - buf);
  507. }
  508. /* Get the RRD or 'pretty' ascii representation of packedstream */
  509. int
  510. ps2strn(struct packedstream * ps, char *buf, const int maxlen, int pretty)
  511. {
  512. u_int16_t b;
  513. u_int16_t s;
  514. u_int16_t c;
  515. u_int64_t q;
  516. u_int32_t l;
  517. int64_t d;
  518. double D;
  519. int i = 0;
  520. char *formatstr;
  521. char *in, *out;
  522. char vartype;
  523. in = (char *) (&ps->data);
  524. out = (char *) buf;
  525. while ((vartype = streamform[ps->type].form[i]) != '\0') {
  526. /* check buffer overflow */
  527. if (checklen(maxlen, (out - buf), strlenvar(vartype)))
  528. return 0;
  529. switch (pretty) {
  530. case PS2STR_PRETTY:
  531. formatstr = formatstrvar(vartype);
  532. break;
  533. case PS2STR_RRD:
  534. formatstr = rrdstrvar(vartype);
  535. break;
  536. default:
  537. warning("%s:%d: unknown pretty identifier", __FILE__, __LINE__);
  538. return 0;
  539. }
  540. switch (vartype) {
  541. case 'b':
  542. bcopy(in, &b, sizeof(u_int8_t));
  543. b &= 0xff;
  544. snprintf(out, strlenvar(vartype), formatstr, b);
  545. in++;
  546. break;
  547. case 'c':
  548. bcopy(in, &c, sizeof(u_int16_t));
  549. D = (double) c / 100.0;
  550. snprintf(out, strlenvar(vartype), formatstr, D);
  551. in += sizeof(u_int16_t);
  552. break;
  553. case 's':
  554. bcopy(in, &s, sizeof(u_int16_t));
  555. snprintf(out, strlenvar(vartype), formatstr, s);
  556. in += sizeof(u_int16_t);
  557. break;
  558. case 'l':
  559. bcopy(in, &l, sizeof(u_int32_t));
  560. snprintf(out, strlenvar(vartype), formatstr, l);
  561. in += sizeof(u_int32_t);
  562. break;
  563. case 'L':
  564. bcopy(in, &q, sizeof(u_int64_t));
  565. snprintf(out, strlenvar(vartype), formatstr, q);
  566. in += sizeof(u_int64_t);
  567. break;
  568. case 'D':
  569. bcopy(in, &d, sizeof(int64_t));
  570. D = (double) (d / 1000.0 / 1000.0);
  571. snprintf(out, strlenvar(vartype), formatstr, D);
  572. in += sizeof(int64_t);
  573. break;
  574. default:
  575. warning("unknown stream format identifier %c", vartype);
  576. return 0;
  577. }
  578. out += strlen(out);
  579. i++;
  580. }
  581. return (out - buf);
  582. }
  583. struct stream *
  584. create_stream(int type, char *args)
  585. {
  586. struct stream *p;
  587. if (type < 0 || type >= MT_EOT)
  588. fatal("%s:%d: internal error: stream type unknown", __FILE__, __LINE__);
  589. p = (struct stream *) xmalloc(sizeof(struct stream));
  590. bzero(p, sizeof(struct stream));
  591. p->type = type;
  592. if (args != NULL)
  593. p->arg = xstrdup(args);
  594. return p;
  595. }
  596. /* Find the stream handle in a source */
  597. struct stream *
  598. find_source_stream(struct source * source, int type, char *args)
  599. {
  600. struct stream *p;
  601. if (source == NULL || args == NULL)
  602. return NULL;
  603. SLIST_FOREACH(p, &source->sl, streams) {
  604. if (((void *) p != NULL) && (p->type == type)
  605. && (((void *) args != (void *) p)
  606. && strncmp(args, p->arg, _POSIX2_LINE_MAX) == 0))
  607. return p;
  608. }
  609. return NULL;
  610. }
  611. /* Add a stream to a source */
  612. struct stream *
  613. add_source_stream(struct source * source, int type, char *args)
  614. {
  615. struct stream *p;
  616. if (source == NULL)
  617. return NULL;
  618. if (find_source_stream(source, type, args) != NULL)
  619. return NULL;
  620. p = create_stream(type, args);
  621. SLIST_INSERT_HEAD(&source->sl, p, streams);
  622. return p;
  623. }
  624. /* Find a stream in a mux */
  625. struct stream *
  626. find_mux_stream(struct mux * mux, int type, char *args)
  627. {
  628. struct stream *p;
  629. if (mux == NULL || args == NULL)
  630. return NULL;
  631. SLIST_FOREACH(p, &mux->sl, streams) {
  632. if (((void *) p != NULL) && (p->type == type)
  633. && (((void *) args != (void *) p)
  634. && strncmp(args, p->arg, _POSIX2_LINE_MAX) == 0))
  635. return p;
  636. }
  637. return NULL;
  638. }
  639. /* Add a stream to a mux */
  640. struct stream *
  641. add_mux_stream(struct mux * mux, int type, char *args)
  642. {
  643. struct stream *p;
  644. if (mux == NULL)
  645. return NULL;
  646. if (find_mux_stream(mux, type, args) != NULL)
  647. return NULL;
  648. p = create_stream(type, args);
  649. SLIST_INSERT_HEAD(&mux->sl, p, streams);
  650. return p;
  651. }
  652. /* Find a source by name in a sourcelist */
  653. struct source *
  654. find_source(struct sourcelist * sol, char *name)
  655. {
  656. struct source *p;
  657. if (sol == NULL || SLIST_EMPTY(sol) || name == NULL)
  658. return NULL;
  659. SLIST_FOREACH(p, sol, sources) {
  660. if (((void *) p != NULL) && ((void *) name != (void *) p)
  661. && strncmp(name, p->addr, _POSIX2_LINE_MAX) == 0)
  662. return p;
  663. }
  664. return NULL;
  665. }
  666. /* Find a source by ip in a sourcelist */
  667. struct source *
  668. find_source_sockaddr(struct sourcelist * sol, struct sockaddr * addr)
  669. {
  670. struct source *p;
  671. if (sol == NULL || SLIST_EMPTY(sol))
  672. return NULL;
  673. SLIST_FOREACH(p, sol, sources) {
  674. if (cmpsock_addr((struct sockaddr *) & p->sockaddr, addr))
  675. return p;
  676. }
  677. return NULL;
  678. }
  679. /* Add a source with to a sourcelist */
  680. struct source *
  681. add_source(struct sourcelist * sol, char *name)
  682. {
  683. struct source *p;
  684. if (sol == NULL)
  685. return NULL;
  686. if (find_source(sol, name) != NULL)
  687. return NULL;
  688. p = (struct source *) xmalloc(sizeof(struct source));
  689. bzero(p, sizeof(struct source));
  690. p->addr = xstrdup(name);
  691. SLIST_INSERT_HEAD(sol, p, sources);
  692. return p;
  693. }
  694. /* Find a mux by name in a muxlist */
  695. struct mux *
  696. find_mux(struct muxlist * mul, char *name)
  697. {
  698. struct mux *p;
  699. if (mul == NULL || SLIST_EMPTY(mul) || name == NULL)
  700. return NULL;
  701. SLIST_FOREACH(p, mul, muxes) {
  702. if (((void *) p != NULL) && ((void *) name != (void *) p)
  703. && strncmp(name, p->name, _POSIX2_LINE_MAX) == 0)
  704. return p;
  705. }
  706. return NULL;
  707. }
  708. /* Add a mux to a muxlist */
  709. struct mux *
  710. add_mux(struct muxlist * mul, char *name)
  711. {
  712. struct mux *p;
  713. if (mul == NULL)
  714. return NULL;
  715. if (find_mux(mul, name) != NULL)
  716. return NULL;
  717. p = (struct mux *) xmalloc(sizeof(struct mux));
  718. bzero(p, sizeof(struct mux));
  719. p->name = xstrdup(name);
  720. SLIST_INSERT_HEAD(mul, p, muxes);
  721. SLIST_INIT(&p->sol);
  722. return p;
  723. }
  724. /* Rename a mux */
  725. struct mux *
  726. rename_mux(struct muxlist * mul, struct mux * mux, char *name)
  727. {
  728. if (mul == NULL || mux == NULL)
  729. return NULL;
  730. if (find_mux(mul, name) != NULL)
  731. return NULL;
  732. if (mux->name != NULL)
  733. xfree(mux->name);
  734. mux->name = xstrdup(name);
  735. return mux;
  736. }
  737. void
  738. free_muxlist(struct muxlist * mul)
  739. {
  740. struct mux *p, *np;
  741. int i;
  742. if (mul == NULL || SLIST_EMPTY(mul))
  743. return;
  744. p = SLIST_FIRST(mul);
  745. while (p) {
  746. np = SLIST_NEXT(p, muxes);
  747. if (p->name != NULL)
  748. xfree(p->name);
  749. if (p->addr != NULL)
  750. xfree(p->addr);
  751. if (p->port != NULL)
  752. xfree(p->port);
  753. if (p->clientsocket)
  754. close(p->clientsocket);
  755. if (p->symuxsocket)
  756. close(p->symuxsocket);
  757. if (p->packet.data)
  758. xfree(p->packet.data);
  759. for (i = 0; i < AF_MAX; i++)
  760. if (p->symonsocket[i])
  761. close(p->symonsocket[i]);
  762. free_streamlist(&p->sl);
  763. free_sourcelist(&p->sol);
  764. xfree(p);
  765. p = np;
  766. }
  767. }
  768. void
  769. free_streamlist(struct streamlist * sl)
  770. {
  771. struct stream *p, *np;
  772. if (sl == NULL || SLIST_EMPTY(sl))
  773. return;
  774. p = SLIST_FIRST(sl);
  775. while (p) {
  776. np = SLIST_NEXT(p, streams);
  777. if (p->arg != NULL)
  778. xfree(p->arg);
  779. if (p->file != NULL)
  780. xfree(p->file);
  781. xfree(p);
  782. p = np;
  783. }
  784. }
  785. void
  786. free_sourcelist(struct sourcelist * sol)
  787. {
  788. struct source *p, *np;
  789. if (sol == NULL || SLIST_EMPTY(sol))
  790. return;
  791. p = SLIST_FIRST(sol);
  792. while (p) {
  793. np = SLIST_NEXT(p, sources);
  794. if (p->addr != NULL)
  795. xfree(p->addr);
  796. free_streamlist(&p->sl);
  797. xfree(p);
  798. p = np;
  799. }
  800. }
  801. /* Calculate maximum buffer space needed for a single symon measurement run,
  802. * excluding the packet header
  803. */
  804. int
  805. bytelen_streamlist(struct streamlist * sl)
  806. {
  807. struct stream *stream;
  808. int len = 0;
  809. int i;
  810. SLIST_FOREACH(stream, sl, streams) {
  811. len += 1; /* type */
  812. len += strlen(stream->arg) + 1; /* arg */
  813. for (i = 0; streamform[stream->type].form[i] != 0; i++) /* packedstream */
  814. len += bytelenvar(streamform[stream->type].form[i]);
  815. }
  816. return len;
  817. }
  818. /* Calculate maximum buffer symux space needed for a single symon hit,
  819. * excluding the packet header
  820. */
  821. int
  822. bytelen_sourcelist(struct sourcelist * sol)
  823. {
  824. struct source *source;
  825. int maxlen;
  826. int len;
  827. len = maxlen = 0;
  828. /* determine maximum packet size for a single source */
  829. SLIST_FOREACH(source, sol, sources) {
  830. len = bytelen_streamlist(&source->sl);
  831. if (len > maxlen)
  832. maxlen = len;
  833. }
  834. return maxlen;
  835. }
  836. /* Calculate maximum buffer symux space needed for a single symon hit */
  837. int
  838. strlen_sourcelist(struct sourcelist * sol)
  839. {
  840. char buf[_POSIX2_LINE_MAX];
  841. struct source *source;
  842. struct stream *stream;
  843. int maxlen;
  844. int len;
  845. int n;
  846. len = n = 0;
  847. source = NULL;
  848. stream = NULL;
  849. maxlen = 0;
  850. /* determine maximum string size for a single source */
  851. SLIST_FOREACH(source, sol, sources) {
  852. len = snprintf(&buf[0], _POSIX2_LINE_MAX, "%s;", source->addr);
  853. SLIST_FOREACH(stream, &source->sl, streams) {
  854. len += strlen(type2str(stream->type)) + strlen(":");
  855. len += strlen(stream->arg) + strlen(":");
  856. len += (sizeof(time_t) * 3) + strlen(":"); /* 3 > ln(255) / ln(10) */
  857. len += strlentype(stream->type);
  858. n++;
  859. }
  860. if (len > maxlen)
  861. maxlen = len;
  862. }
  863. return maxlen;
  864. }
  865. void
  866. init_symon_packet(struct mux * mux)
  867. {
  868. if (mux->packet.data)
  869. xfree(mux->packet.data);
  870. mux->packet.size = sizeof(struct symonpacketheader) +
  871. bytelen_streamlist(&mux->sl);
  872. if (mux->packet.size > SYMON_MAXPACKET) {
  873. warning("transport max packet size is not enough to transport all streams");
  874. mux->packet.size = SYMON_MAXPACKET;
  875. }
  876. mux->packet.data = xmalloc(mux->packet.size);
  877. bzero(mux->packet.data, mux->packet.size);
  878. debug("symon packet size=%d", mux->packet.size);
  879. }
  880. void
  881. init_symux_packet(struct mux * mux)
  882. {
  883. if (mux->packet.data)
  884. xfree(mux->packet.data);
  885. /* determine optimal packet size */
  886. mux->packet.size = sizeof(struct symonpacketheader) +
  887. bytelen_sourcelist(&mux->sol);
  888. if (mux->packet.size > SYMON_MAXPACKET) {
  889. warning("transport max packet size is not enough to transport all streams");
  890. mux->packet.size = SYMON_MAXPACKET;
  891. }
  892. /* multiply by 2 to allow users to detect symon.conf/symux.conf stream
  893. * configuration differences
  894. */
  895. mux->packet.size = ((mux->packet.size << 1) > SYMON_MAXPACKET)?
  896. SYMON_MAXPACKET:
  897. mux->packet.size << 1;
  898. mux->packet.data = xmalloc(mux->packet.size);
  899. bzero(mux->packet.data, mux->packet.size);
  900. debug("symux packet size=%d", mux->packet.size);
  901. }
  902. /* Big endian CRC32 */
  903. u_int32_t
  904. crc32(const void *buf, unsigned int len)
  905. {
  906. u_int8_t *p;
  907. u_int32_t crc;
  908. crc = 0xffffffff;
  909. for (p = (u_int8_t *) buf; len > 0; ++p, --len)
  910. crc = (crc << 8) ^ crc32_table[(crc >> 24) ^ *p];
  911. return ~crc;
  912. }
  913. /* Init table for CRC32 */
  914. void
  915. init_crc32()
  916. {
  917. unsigned int i, j;
  918. u_int32_t c;
  919. for (i = 0; i < 256; ++i) {
  920. c = i << 24;
  921. for (j = 8; j > 0; --j)
  922. c = c & 0x80000000 ? (c << 1) ^ SYMON_CRCPOLY : (c << 1);
  923. crc32_table[i] = c;
  924. }
  925. }
  926. int
  927. gcd(int a, int b)
  928. {
  929. for(;;) {
  930. if (a == 0)
  931. return b;
  932. b %= a;
  933. if (b == 0)
  934. return a;
  935. a %= b;
  936. }
  937. }