wtp_pdu.c
上传用户:gzpyjq
上传日期:2013-01-31
资源大小:1852k
文件大小:10k
源码类别:

手机WAP编程

开发平台:

WINDOWS

  1. /* wtp_pdu.c - pack and unpack WTP packets
  2.  *
  3.  * Generates packing and unpacking code from wtp_pdu.def.
  4.  *
  5.  * Richard Braakman
  6.  */
  7. #include "gwlib/gwlib.h"
  8. #include "wtp_pdu.h"
  9. WTP_PDU *wtp_pdu_create(int type) {
  10. WTP_PDU *pdu;
  11. pdu = gw_malloc(sizeof(*pdu));
  12. pdu->type = type;
  13. pdu->options = NULL;
  14. switch (pdu->type) {
  15. #define PDU(name, docstring, fields, is_valid) 
  16. case name: {
  17. struct name *p; p = &pdu->u.name; 
  18. fields 
  19. } break;
  20. #define UINT(field, docstring, bits) p->field = 0;
  21. #define UINTVAR(field, docstring) p->field = 0;
  22. #define OCTSTR(field, docstring, lengthfield) p->field = NULL;
  23. #define REST(field, docstring) p->field = NULL;
  24. #define TYPE(bits, value) 
  25. #define RESERVED(bits) 
  26. #define TPI(confield)
  27. #include "wtp_pdu.def"
  28. #undef TPI
  29. #undef RESERVED
  30. #undef TYPE
  31. #undef REST
  32. #undef OCTSTR
  33. #undef UINTVAR
  34. #undef UINT
  35. #undef PDU
  36. default:
  37. warning(0, "Cannot destroy unknown WTP PDU type %d", pdu->type);
  38. break;
  39. }
  40. return pdu;
  41. }
  42. void wtp_pdu_destroy(WTP_PDU *pdu) {
  43. if (pdu == NULL)
  44. return;
  45. switch (pdu->type) {
  46. #define PDU(name, docstring, fields, is_valid) 
  47. case name: {
  48. struct name *p; p = &pdu->u.name; 
  49. fields 
  50. } break;
  51. #define UINT(field, docstring, bits)
  52. #define UINTVAR(field, docstring)
  53. #define OCTSTR(field, docstring, lengthfield) octstr_destroy(p->field);
  54. #define REST(field, docstring) octstr_destroy(p->field);
  55. #define TYPE(bits, value)
  56. #define RESERVED(bits)
  57. #define TPI(confield)
  58. #include "wtp_pdu.def"
  59. #undef TPI
  60. #undef RESERVED
  61. #undef TYPE
  62. #undef REST
  63. #undef OCTSTR
  64. #undef UINTVAR
  65. #undef UINT
  66. #undef PDU
  67. default:
  68. warning(0, "Cannot destroy unknown WTP PDU type %d", pdu->type);
  69. break;
  70. }
  71. if (pdu->options) {
  72. while (list_len(pdu->options)) {
  73. wtp_tpi_destroy(list_consume(pdu->options));
  74. }
  75. list_destroy(pdu->options, NULL);
  76. }
  77. gw_free(pdu);
  78. }
  79. void wtp_tpi_destroy(WTP_TPI *p) {
  80. if (p == NULL)
  81. return;
  82. octstr_destroy(p->data);
  83. gw_free(p);
  84. }
  85. void wtp_pdu_append_tpi(WTP_PDU *pdu, int type, Octstr *data) {
  86. WTP_TPI *tpi;
  87. tpi = gw_malloc(sizeof(*tpi));
  88. tpi->type = type;
  89. tpi->data = data;
  90. if (pdu->options == NULL)
  91. pdu->options = list_create();
  92. list_append(pdu->options, tpi);
  93. }
  94. static long unpack_tpis(Octstr *data, long bitpos, WTP_PDU *pdu) {
  95. long length;
  96. int type;
  97. Octstr *tpidata;
  98. int another;
  99. do {
  100. another = octstr_get_bits(data, bitpos, 1);
  101. type = octstr_get_bits(data, bitpos + 1, 4);
  102. if (octstr_get_bits(data, bitpos + 5, 1)) {
  103. /* Long TPI */
  104. length = octstr_get_bits(data, bitpos + 8, 8);
  105. bitpos += 16;
  106. } else {
  107. /* Short TPI */
  108. length = octstr_get_bits(data, bitpos + 6, 2);
  109. bitpos += 8;
  110. }
  111. gw_assert(bitpos % 8 == 0);
  112. tpidata = octstr_copy(data, bitpos / 8, length);
  113. bitpos += 8 * length;
  114. wtp_pdu_append_tpi(pdu, type, tpidata);
  115. } while (another);
  116. return bitpos;
  117. }
  118. static long pack_tpis(Octstr *data, long bitpos, List *tpis) {
  119. long length;
  120. WTP_TPI *tpi;
  121. int i;
  122. int num_tpis;
  123. num_tpis = list_len(tpis);
  124. for (i = 0; i < num_tpis; i++) {
  125. tpi = list_get(tpis, i);
  126. length = octstr_len(tpi->data);
  127. octstr_set_bits(data, bitpos, 1, i + 1 < num_tpis);
  128. octstr_set_bits(data, bitpos + 1, 4, tpi->type);
  129. if (length >= 4) {
  130. /* Long TPI */
  131. octstr_set_bits(data, bitpos + 5, 1, 1);
  132. octstr_set_bits(data, bitpos + 8, 8, length);
  133. bitpos += 16;
  134. } else {
  135. /* Short TPI */
  136. octstr_set_bits(data, bitpos + 5, 1, 0);
  137. octstr_set_bits(data, bitpos + 6, 2, length);
  138. bitpos += 8;
  139. }
  140. gw_assert(bitpos % 8 == 0);
  141. octstr_append(data, tpi->data);
  142. bitpos += 8 * length;
  143. }
  144. return bitpos;
  145. }
  146. static void dump_tpis(List *tpis, int level) {
  147. int i;
  148. int num_tpis;
  149. WTP_TPI *tpi;
  150. if (tpis == NULL)
  151. return;
  152. num_tpis = list_len(tpis);
  153. for (i = 0; i < num_tpis; i++) {
  154. tpi = list_get(tpis, i);
  155. debug("wap.wtp", 0, "%*s TPI type %u:", level, "", tpi->type);
  156. octstr_dump(tpi->data, level + 1);
  157. }
  158. }
  159. /* Determine which type of PDU this is, using the TYPE macros in
  160.  * the definition file. */
  161. static int wtp_pdu_type(Octstr *data) {
  162. long bitpos;
  163. long lastpos = -1;
  164. long lastnumbits = -1;
  165. long lastval = -1;
  166. int thistype;
  167. /* This code looks slow, but an optimizing compiler will
  168.  * reduce it considerably.  gcc -O2 will produce a single
  169.  * call to octstr_get_bits, folllowed by a sequence of
  170.  * tests on lastval. */
  171. /* Only UINT and RESERVED fields may precede the TYPE */
  172. #define PDU(name, docstring, fields, is_valid) 
  173. bitpos = 0; 
  174. thistype = name; 
  175. fields
  176. #define UINT(field, docstring, bits) bitpos += (bits);
  177. #define UINTVAR(field, docstring)
  178. #define OCTSTR(field, docstring, lengthfield)
  179. #define REST(field, docstring)
  180. #define TYPE(bits, value) 
  181. if ((bits) != lastnumbits || bitpos != lastpos) { 
  182. lastval = octstr_get_bits(data, bitpos, (bits)); 
  183. if (lastval == (value)) 
  184. return thistype; 
  185. lastnumbits = (bits); 
  186. lastpos = bitpos;
  187. #define RESERVED(bits) bitpos += (bits);
  188. #define TPI(confield)
  189. #include "wtp_pdu.def"
  190. #undef TPI
  191. #undef RESERVED
  192. #undef TYPE
  193. #undef REST
  194. #undef OCTSTR
  195. #undef UINTVAR
  196. #undef UINT
  197. #undef PDU
  198. return -1;
  199. }
  200. WTP_PDU *wtp_pdu_unpack(Octstr *data) {
  201. WTP_PDU *pdu = NULL;
  202. long bitpos = 0;
  203. gw_assert(data != NULL);
  204. pdu = gw_malloc(sizeof(*pdu));
  205. pdu->type = wtp_pdu_type(data);
  206. pdu->options = NULL;
  207. switch (pdu->type) {
  208. #define PDU(name, docstring, fields, is_valid) 
  209. case name: { 
  210. struct name *p = &pdu->u.name; 
  211. fields 
  212. gw_assert(bitpos % 8 == 0); 
  213. if (bitpos / 8 != octstr_len(data)) { 
  214. warning(0, "Bad length for " #name " PDU, " 
  215. "expected %ld", bitpos / 8); 
  216. if (!(is_valid)) { 
  217. warning(0, #name " PDU failed %s", #is_valid); 
  218.                         return NULL; 
  219. } break;
  220. #define UINT(field, docstring, bits) 
  221. p->field = octstr_get_bits(data, bitpos, (bits)); 
  222. bitpos += (bits);
  223. #define UINTVAR(field, docstring) 
  224. gw_assert(bitpos % 8 == 0); 
  225. p->field = octstr_get_bits(data, bitpos + 1, 7); 
  226. while (octstr_get_bits(data, bitpos, 1)) { 
  227. bitpos += 8; 
  228. p->field <<= 7; 
  229. p->field |= octstr_get_bits(data, bitpos + 1, 7); 
  230. bitpos += 8;
  231. #define OCTSTR(field, docstring, lengthfield) 
  232. gw_assert(bitpos % 8 == 0); 
  233. p->field = octstr_copy(data, bitpos / 8, p->lengthfield); 
  234. bitpos += 8 * p->lengthfield;
  235. #define REST(field, docstring) 
  236. gw_assert(bitpos % 8 == 0); 
  237. if (bitpos / 8 <= octstr_len(data)) { 
  238. p->field = octstr_copy(data, bitpos / 8, 
  239. octstr_len(data) - bitpos / 8); 
  240. bitpos = octstr_len(data) * 8; 
  241. } else { 
  242. p->field = octstr_create(""); 
  243. }
  244. #define TYPE(bits, value) bitpos += (bits);
  245. #define RESERVED(bits) bitpos += (bits);
  246. #define TPI(confield) 
  247. if (p->confield) { 
  248. pdu->options = list_create(); 
  249. bitpos = unpack_tpis(data, bitpos, pdu); 
  250. }
  251. #include "wtp_pdu.def"
  252. #undef TPI
  253. #undef RESERVED
  254. #undef TYPE
  255. #undef REST
  256. #undef OCTSTR
  257. #undef UINTVAR
  258. #undef UINT
  259. #undef PDU
  260. default:
  261. warning(0, "WTP PDU with unknown type %d", pdu->type);
  262. gw_free(pdu);
  263. return NULL;
  264. }
  265. return pdu;
  266. }
  267. static void fixup_length_fields(WTP_PDU *pdu) {
  268. switch (pdu->type) {
  269. #define PDU(name, docstring, fields, is_valid) 
  270. case name: { 
  271. struct name *p = &pdu->u.name; 
  272. fields 
  273. } break;
  274. #define UINT(field, docstring, bits)
  275. #define UINTVAR(field, docstring)
  276. #define OCTSTR(field, docstring, lengthfield) 
  277. p->lengthfield = octstr_len(p->field);
  278. #define REST(field, docstring)
  279. #define TYPE(bits, value)
  280. #define RESERVED(bits)
  281. #define TPI(confield) 
  282. p->confield = pdu->options != NULL && list_len(pdu->options) > 0;
  283. #include "wtp_pdu.def"
  284. #undef TPI
  285. #undef RESERVED
  286. #undef TYPE
  287. #undef REST
  288. #undef OCTSTR
  289. #undef UINTVAR
  290. #undef UINT
  291. #undef PDU
  292. }
  293. }
  294. Octstr *wtp_pdu_pack(WTP_PDU *pdu) {
  295. Octstr *data;
  296. long bitpos;
  297. /* We rely on octstr_set_bits to lengthen our octstr as needed. */
  298. data = octstr_create("");
  299. fixup_length_fields(pdu);
  300. bitpos = 0;
  301. switch (pdu->type) {
  302. #define PDU(name, docstring, fields, is_valid) 
  303. case name: { 
  304. struct name *p = &pdu->u.name; 
  305. fields 
  306. gw_assert(bitpos % 8 == 0); 
  307. } break;
  308. #define UINT(field, docstring, bits) 
  309. octstr_set_bits(data, bitpos, (bits), p->field); 
  310. bitpos += (bits);
  311. #define UINTVAR(field, docstring) 
  312. gw_assert(bitpos % 8 == 0); 
  313. octstr_append_uintvar(data, p->field); 
  314. bitpos = 8 * octstr_len(data);
  315. #define OCTSTR(field, docstring, lengthfield) 
  316. gw_assert(bitpos % 8 == 0); 
  317. if (p->field != NULL) 
  318. octstr_append(data, p->field); 
  319. bitpos += 8 * octstr_len(p->field);
  320. #define REST(field, docstring) 
  321. gw_assert(bitpos % 8 == 0); 
  322. if (p->field != NULL) 
  323. octstr_append(data, p->field); 
  324. bitpos += 8 * octstr_len(p->field);
  325. #define TYPE(bits, value) 
  326. octstr_set_bits(data, bitpos, (bits), (value)); 
  327. bitpos += (bits);
  328. #define RESERVED(bits) bitpos += (bits);
  329. #define TPI(confield) 
  330. if (p->confield) { 
  331. bitpos = pack_tpis(data, bitpos, pdu->options); 
  332. }
  333. #include "wtp_pdu.def"
  334. #undef TPI
  335. #undef RESERVED
  336. #undef TYPE
  337. #undef REST
  338. #undef OCTSTR
  339. #undef UINTVAR
  340. #undef UINT
  341. #undef PDU
  342. default:
  343. panic(0, "Packing unknown WTP PDU type %ld", (long) pdu->type);
  344. }
  345. return data;
  346. }
  347. void wtp_pdu_dump(WTP_PDU *pdu, int level) {
  348. unsigned char *dbg = "wap.wtp";
  349. switch (pdu->type) {
  350. #define PDU(name, docstring, fields, is_valid) 
  351. case name: { 
  352. struct name *p = &pdu->u.name; 
  353. debug(dbg, 0, "%*sWTP %s PDU at %p:", 
  354. level, "", #name, (void *)pdu); 
  355. fields 
  356. } break;
  357. #define UINT(field, docstring, bits) 
  358. debug(dbg, 0, "%*s %s: %lu", level, "", docstring, p->field);
  359. #define UINTVAR(field, docstring) 
  360. debug(dbg, 0, "%*s %s: %lu", level, "", docstring, p->field);
  361. #define OCTSTR(field, docstring, lengthfield) 
  362. debug(dbg, 0, "%*s %s:", level, "", docstring); 
  363. octstr_dump(p->field, level + 1);
  364. #define REST(field, docstring) 
  365. debug(dbg, 0, "%*s %s:", level, "", docstring); 
  366. octstr_dump(p->field, level + 1);
  367. #define TYPE(bits, value)
  368. #define RESERVED(bits)
  369. #define TPI(confield) dump_tpis(pdu->options, level);
  370. #include "wtp_pdu.def"
  371. #undef TPI
  372. #undef RESERVED
  373. #undef TYPE
  374. #undef REST
  375. #undef OCTSTR
  376. #undef UINTVAR
  377. #undef UINT
  378. #undef PDU
  379. default:
  380. debug(dbg, 0, "%*sWTP PDU at %p:", level, "", (void *)pdu);
  381. debug(dbg, 0, "%*s unknown type %u", level, "", pdu->type);
  382. break;
  383. }
  384. }