Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

wtp_pdu.c

Go to the documentation of this file.
00001 /* ==================================================================== 
00002  * The Kannel Software License, Version 1.0 
00003  * 
00004  * Copyright (c) 2001-2008 Kannel Group  
00005  * Copyright (c) 1998-2001 WapIT Ltd.   
00006  * All rights reserved. 
00007  * 
00008  * Redistribution and use in source and binary forms, with or without 
00009  * modification, are permitted provided that the following conditions 
00010  * are met: 
00011  * 
00012  * 1. Redistributions of source code must retain the above copyright 
00013  *    notice, this list of conditions and the following disclaimer. 
00014  * 
00015  * 2. Redistributions in binary form must reproduce the above copyright 
00016  *    notice, this list of conditions and the following disclaimer in 
00017  *    the documentation and/or other materials provided with the 
00018  *    distribution. 
00019  * 
00020  * 3. The end-user documentation included with the redistribution, 
00021  *    if any, must include the following acknowledgment: 
00022  *       "This product includes software developed by the 
00023  *        Kannel Group (http://www.kannel.org/)." 
00024  *    Alternately, this acknowledgment may appear in the software itself, 
00025  *    if and wherever such third-party acknowledgments normally appear. 
00026  * 
00027  * 4. The names "Kannel" and "Kannel Group" must not be used to 
00028  *    endorse or promote products derived from this software without 
00029  *    prior written permission. For written permission, please  
00030  *    contact org@kannel.org. 
00031  * 
00032  * 5. Products derived from this software may not be called "Kannel", 
00033  *    nor may "Kannel" appear in their name, without prior written 
00034  *    permission of the Kannel Group. 
00035  * 
00036  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 
00037  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
00038  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
00039  * DISCLAIMED.  IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS 
00040  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,  
00041  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  
00042  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR  
00043  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
00044  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE  
00045  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  
00046  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
00047  * ==================================================================== 
00048  * 
00049  * This software consists of voluntary contributions made by many 
00050  * individuals on behalf of the Kannel Group.  For more information on  
00051  * the Kannel Group, please see <http://www.kannel.org/>. 
00052  * 
00053  * Portions of this software are based upon software originally written at  
00054  * WapIT Ltd., Helsinki, Finland for the Kannel project.  
00055  */ 
00056 
00057 /* wtp_pdu.c - pack and unpack WTP packets
00058  *
00059  * Generates packing and unpacking code from wtp_pdu.def.
00060  *
00061  * Richard Braakman
00062  */
00063 
00064 #include "gwlib/gwlib.h"
00065 #include "wtp_pdu.h"
00066 
00067 WTP_PDU *wtp_pdu_create(int type) {
00068     WTP_PDU *pdu;
00069     
00070     pdu = gw_malloc(sizeof(*pdu));
00071     pdu->type = type;
00072     pdu->options = NULL;
00073 
00074     switch (pdu->type) {
00075 #define PDU(name, docstring, fields, is_valid) \
00076     case name: {\
00077     struct name *p; p = &pdu->u.name; \
00078     fields \
00079     } break;
00080 #define UINT(field, docstring, bits) p->field = 0;
00081 #define UINTVAR(field, docstring) p->field = 0;
00082 #define OCTSTR(field, docstring, lengthfield) p->field = NULL;
00083 #define REST(field, docstring) p->field = NULL;
00084 #define TYPE(bits, value) 
00085 #define RESERVED(bits) 
00086 #define TPI(confield)
00087 #include "wtp_pdu.def"
00088 #undef TPI
00089 #undef RESERVED
00090 #undef TYPE
00091 #undef REST
00092 #undef OCTSTR
00093 #undef UINTVAR
00094 #undef UINT
00095 #undef PDU
00096     default:
00097         warning(0, "Cannot create unknown WTP PDU type %d", pdu->type);
00098         break;
00099     }
00100 
00101     return pdu;
00102 }
00103 
00104 void wtp_pdu_destroy(WTP_PDU *pdu) {
00105     if (pdu == NULL)
00106         return;
00107 
00108     switch (pdu->type) {
00109 #define PDU(name, docstring, fields, is_valid) \
00110     case name: {\
00111     struct name *p; p = &pdu->u.name; \
00112     fields \
00113     } break;
00114 #define UINT(field, docstring, bits)
00115 #define UINTVAR(field, docstring)
00116 #define OCTSTR(field, docstring, lengthfield) octstr_destroy(p->field);
00117 #define REST(field, docstring) octstr_destroy(p->field);
00118 #define TYPE(bits, value)
00119 #define RESERVED(bits)
00120 #define TPI(confield)
00121 #include "wtp_pdu.def"
00122 #undef TPI
00123 #undef RESERVED
00124 #undef TYPE
00125 #undef REST
00126 #undef OCTSTR
00127 #undef UINTVAR
00128 #undef UINT
00129 #undef PDU
00130     default:
00131         warning(0, "Cannot destroy unknown WTP PDU type %d", pdu->type);
00132         break;
00133     }
00134 
00135     if (pdu->options) {
00136         while (gwlist_len(pdu->options)) {
00137             wtp_tpi_destroy(gwlist_consume(pdu->options));
00138         }
00139         gwlist_destroy(pdu->options, NULL);
00140     }
00141 
00142     gw_free(pdu);
00143 }
00144 
00145 void wtp_tpi_destroy(WTP_TPI *p) {
00146     if (p == NULL)
00147         return;
00148 
00149     octstr_destroy(p->data);
00150     gw_free(p);
00151 }
00152 
00153 void wtp_pdu_append_tpi(WTP_PDU *pdu, int type, Octstr *data) {
00154     WTP_TPI *tpi;
00155 
00156     tpi = gw_malloc(sizeof(*tpi));
00157     tpi->type = type;
00158     tpi->data = data;
00159     if (pdu->options == NULL)
00160         pdu->options = gwlist_create();
00161     gwlist_append(pdu->options, tpi);
00162 }
00163 
00164 static long unpack_tpis(Octstr *data, long bitpos, WTP_PDU *pdu) {
00165     long length;
00166     int type;
00167     Octstr *tpidata;
00168     int another;
00169 
00170     do {
00171         another = octstr_get_bits(data, bitpos, 1);
00172         type = octstr_get_bits(data, bitpos + 1, 4);
00173         if (octstr_get_bits(data, bitpos + 5, 1)) {
00174             /* Long TPI */
00175             length = octstr_get_bits(data, bitpos + 8, 8);
00176             bitpos += 16;
00177         } else {
00178             /* Short TPI */
00179             length = octstr_get_bits(data, bitpos + 6, 2);
00180             bitpos += 8;
00181         }
00182         gw_assert(bitpos % 8 == 0);
00183         tpidata = octstr_copy(data, bitpos / 8, length);
00184         bitpos += 8 * length;
00185         wtp_pdu_append_tpi(pdu, type, tpidata);
00186     } while (another);
00187 
00188     return bitpos;
00189 }
00190 
00191 static long pack_tpis(Octstr *data, long bitpos, List *tpis) {
00192     long length;
00193     WTP_TPI *tpi;
00194     int i;
00195     int num_tpis;
00196 
00197     num_tpis = gwlist_len(tpis);
00198     for (i = 0; i < num_tpis; i++) {
00199         tpi = gwlist_get(tpis, i);
00200         length = octstr_len(tpi->data);
00201         octstr_set_bits(data, bitpos, 1, i + 1 < num_tpis);
00202         octstr_set_bits(data, bitpos + 1, 4, tpi->type);
00203         if (length >= 4) {
00204             /* Long TPI */
00205             octstr_set_bits(data, bitpos + 5, 1, 1);
00206             octstr_set_bits(data, bitpos + 8, 8, length);
00207             bitpos += 16;
00208         } else {
00209             /* Short TPI */
00210             octstr_set_bits(data, bitpos + 5, 1, 0);
00211             octstr_set_bits(data, bitpos + 6, 2, length);
00212             bitpos += 8;
00213         }
00214         gw_assert(bitpos % 8 == 0);
00215         octstr_append(data, tpi->data);
00216         bitpos += 8 * length;
00217     }
00218 
00219     return bitpos;
00220 }
00221 
00222 static void dump_tpis(List *tpis, int level) {
00223     int i;
00224     int num_tpis;
00225     WTP_TPI *tpi;
00226 
00227     if (tpis == NULL)
00228         return;
00229 
00230     num_tpis = gwlist_len(tpis);
00231     for (i = 0; i < num_tpis; i++) {
00232         tpi = gwlist_get(tpis, i);
00233         debug("wap.wtp", 0, "%*s TPI type %u:", level, "", tpi->type);
00234         octstr_dump(tpi->data, level + 1);
00235     }
00236 }
00237 
00238 /* Determine which type of PDU this is, using the TYPE macros in
00239  * the definition file. */
00240 static int wtp_pdu_type(Octstr *data) {
00241     long bitpos;
00242     long lastpos = -1;
00243     long lastnumbits = -1;
00244     long lastval = -1;
00245     int thistype;
00246 
00247     /* This code looks slow, but an optimizing compiler will
00248      * reduce it considerably.  gcc -O2 will produce a single
00249      * call to octstr_get_bits, folllowed by a sequence of
00250      * tests on lastval. */
00251 
00252 /* Only UINT and RESERVED fields may precede the TYPE */
00253 #define PDU(name, docstring, fields, is_valid) \
00254     bitpos = 0; \
00255     thistype = name; \
00256     fields
00257 #define UINT(field, docstring, bits) bitpos += (bits);
00258 #define UINTVAR(field, docstring)
00259 #define OCTSTR(field, docstring, lengthfield)
00260 #define REST(field, docstring)
00261 #define TYPE(bits, value) \
00262     if ((bits) != lastnumbits || bitpos != lastpos) { \
00263         lastval = octstr_get_bits(data, bitpos, (bits)); \
00264     } \
00265     if (lastval == (value)) \
00266         return thistype; \
00267     lastnumbits = (bits); \
00268     lastpos = bitpos;
00269 #define RESERVED(bits) bitpos += (bits);
00270 #define TPI(confield)
00271 #include "wtp_pdu.def"
00272 #undef TPI
00273 #undef RESERVED
00274 #undef TYPE
00275 #undef REST
00276 #undef OCTSTR
00277 #undef UINTVAR
00278 #undef UINT
00279 #undef PDU
00280 
00281     return -1;
00282 }
00283 
00284 WTP_PDU *wtp_pdu_unpack(Octstr *data) {
00285     WTP_PDU *pdu = NULL;
00286     long bitpos = 0;
00287 
00288     gw_assert(data != NULL);
00289 
00290     pdu = gw_malloc(sizeof(*pdu));
00291 
00292     pdu->type = wtp_pdu_type(data);
00293     pdu->options = NULL;
00294 
00295     switch (pdu->type) {
00296 #define PDU(name, docstring, fields, is_valid) \
00297     case name: { \
00298         struct name *p = &pdu->u.name; \
00299         fields \
00300         gw_assert(bitpos % 8 == 0); \
00301         if (bitpos / 8 != octstr_len(data)) { \
00302             warning(0, "Bad length for " #name " PDU, " \
00303                 "expected %ld", bitpos / 8); \
00304         } \
00305         if (!(is_valid)) { \
00306             warning(0, #name " PDU failed %s", #is_valid); \
00307                         return NULL; \
00308         } \
00309     } break;
00310 #define UINT(field, docstring, bits) \
00311     p->field = octstr_get_bits(data, bitpos, (bits)); \
00312     bitpos += (bits);
00313 #define UINTVAR(field, docstring) \
00314     gw_assert(bitpos % 8 == 0); \
00315     p->field = octstr_get_bits(data, bitpos + 1, 7); \
00316     while (octstr_get_bits(data, bitpos, 1)) { \
00317         bitpos += 8; \
00318         p->field <<= 7; \
00319         p->field |= octstr_get_bits(data, bitpos + 1, 7); \
00320     } \
00321     bitpos += 8;
00322 #define OCTSTR(field, docstring, lengthfield) \
00323     gw_assert(bitpos % 8 == 0); \
00324     p->field = octstr_copy(data, bitpos / 8, p->lengthfield); \
00325     bitpos += 8 * p->lengthfield;
00326 #define REST(field, docstring) \
00327     gw_assert(bitpos % 8 == 0); \
00328     if (bitpos / 8 <= octstr_len(data)) { \
00329         p->field = octstr_copy(data, bitpos / 8, \
00330                 octstr_len(data) - bitpos / 8); \
00331         bitpos = octstr_len(data) * 8; \
00332     } else { \
00333         p->field = octstr_create(""); \
00334     }
00335 #define TYPE(bits, value) bitpos += (bits);
00336 #define RESERVED(bits) bitpos += (bits);
00337 #define TPI(confield) \
00338     if (p->confield) { \
00339         pdu->options = gwlist_create(); \
00340         bitpos = unpack_tpis(data, bitpos, pdu); \
00341     }
00342 #include "wtp_pdu.def"
00343 #undef TPI
00344 #undef RESERVED
00345 #undef TYPE
00346 #undef REST
00347 #undef OCTSTR
00348 #undef UINTVAR
00349 #undef UINT
00350 #undef PDU
00351     default:
00352         warning(0, "WTP PDU with unknown type %d", pdu->type);
00353         gw_free(pdu);
00354         return NULL;
00355     }
00356 
00357     return pdu;
00358 }
00359 
00360 static void fixup_length_fields(WTP_PDU *pdu) {
00361     switch (pdu->type) {
00362 #define PDU(name, docstring, fields, is_valid) \
00363     case name: { \
00364         struct name *p = &pdu->u.name; \
00365         fields \
00366     } break;
00367 #define UINT(field, docstring, bits)
00368 #define UINTVAR(field, docstring)
00369 #define OCTSTR(field, docstring, lengthfield) \
00370     p->lengthfield = octstr_len(p->field);
00371 #define REST(field, docstring)
00372 #define TYPE(bits, value)
00373 #define RESERVED(bits)
00374 #define TPI(confield) \
00375     p->confield = pdu->options != NULL && gwlist_len(pdu->options) > 0;
00376 #include "wtp_pdu.def"
00377 #undef TPI
00378 #undef RESERVED
00379 #undef TYPE
00380 #undef REST
00381 #undef OCTSTR
00382 #undef UINTVAR
00383 #undef UINT
00384 #undef PDU
00385     }
00386 }
00387 
00388 Octstr *wtp_pdu_pack(WTP_PDU *pdu) {
00389     Octstr *data;
00390     long bitpos;
00391 
00392     /* We rely on octstr_set_bits to lengthen our octstr as needed. */
00393     data = octstr_create("");
00394 
00395     fixup_length_fields(pdu);
00396 
00397     bitpos = 0;
00398     switch (pdu->type) {
00399 #define PDU(name, docstring, fields, is_valid) \
00400     case name: { \
00401         struct name *p = &pdu->u.name; \
00402         fields \
00403         gw_assert(bitpos % 8 == 0); \
00404     } break;
00405 #define UINT(field, docstring, bits) \
00406     octstr_set_bits(data, bitpos, (bits), p->field); \
00407     bitpos += (bits);
00408 #define UINTVAR(field, docstring) \
00409     gw_assert(bitpos % 8 == 0); \
00410     octstr_append_uintvar(data, p->field); \
00411     bitpos = 8 * octstr_len(data);
00412 #define OCTSTR(field, docstring, lengthfield) \
00413     gw_assert(bitpos % 8 == 0); \
00414     if (p->field != NULL) \
00415         octstr_append(data, p->field); \
00416     bitpos += 8 * octstr_len(p->field);
00417 #define REST(field, docstring) \
00418     gw_assert(bitpos % 8 == 0); \
00419     if (p->field != NULL) \
00420         octstr_append(data, p->field); \
00421     bitpos += 8 * octstr_len(p->field);
00422 #define TYPE(bits, value) \
00423     octstr_set_bits(data, bitpos, (bits), (value)); \
00424     bitpos += (bits);
00425 #define RESERVED(bits) bitpos += (bits);
00426 #define TPI(confield) \
00427     if (p->confield) { \
00428         bitpos = pack_tpis(data, bitpos, pdu->options); \
00429     }
00430 #include "wtp_pdu.def"
00431 #undef TPI
00432 #undef RESERVED
00433 #undef TYPE
00434 #undef REST
00435 #undef OCTSTR
00436 #undef UINTVAR
00437 #undef UINT
00438 #undef PDU
00439     default:
00440         panic(0, "Packing unknown WTP PDU type %ld", (long) pdu->type);
00441     }
00442 
00443     return data;
00444 }
00445 
00446 void wtp_pdu_dump(WTP_PDU *pdu, int level) {
00447      char *dbg = "wap.wtp";
00448 
00449     switch (pdu->type) {
00450 #define PDU(name, docstring, fields, is_valid) \
00451     case name: { \
00452         struct name *p = &pdu->u.name; \
00453         debug(dbg, 0, "%*sWTP %s PDU at %p:", \
00454             level, "", #name, (void *)pdu); \
00455         fields \
00456     } break;
00457 #define UINT(field, docstring, bits) \
00458     debug(dbg, 0, "%*s %s: %lu", level, "", docstring, p->field);
00459 #define UINTVAR(field, docstring) \
00460     debug(dbg, 0, "%*s %s: %lu", level, "", docstring, p->field);
00461 #define OCTSTR(field, docstring, lengthfield) \
00462     debug(dbg, 0, "%*s %s:", level, "", docstring); \
00463     octstr_dump(p->field, level + 1);
00464 #define REST(field, docstring) \
00465     debug(dbg, 0, "%*s %s:", level, "", docstring); \
00466     octstr_dump(p->field, level + 1);
00467 #define TYPE(bits, value)
00468 #define RESERVED(bits)
00469 #define TPI(confield) dump_tpis(pdu->options, level);
00470 #include "wtp_pdu.def"
00471 #undef TPI
00472 #undef RESERVED
00473 #undef TYPE
00474 #undef REST
00475 #undef OCTSTR
00476 #undef UINTVAR
00477 #undef UINT
00478 #undef PDU
00479     default:
00480         debug(dbg, 0, "%*sWTP PDU at %p:", level, "", (void *)pdu);
00481         debug(dbg, 0, "%*s unknown type %u", level, "", pdu->type);
00482         break;
00483     }
00484 }
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.