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

wsp_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 /* wsp_pdu.c - pack and unpack WSP packets
00058  *
00059  * Generates packing and unpacking code from wsp_pdu.def.
00060  * Code is very similar to wsp_pdu.c, please make any changes in both files.
00061  *
00062  * Richard Braakman
00063  */
00064 
00065 #include "gwlib/gwlib.h"
00066 #include "wsp_pdu.h"
00067 
00068 WSP_PDU *wsp_pdu_create(int type) {
00069     WSP_PDU *pdu;
00070     
00071     pdu = gw_malloc(sizeof(*pdu));
00072     pdu->type = type;
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 #include "wsp_pdu.def"
00087 #undef RESERVED
00088 #undef TYPE
00089 #undef REST
00090 #undef OCTSTR
00091 #undef UINTVAR
00092 #undef UINT
00093 #undef PDU
00094     default:
00095         panic(0, "Internal error: Unknown PDU type %d", pdu->type);
00096         break;
00097     }
00098 
00099     return pdu;
00100 }
00101 
00102 void wsp_pdu_destroy(WSP_PDU *pdu) {
00103     if (pdu == NULL)
00104         return;
00105 
00106     switch (pdu->type) {
00107 #define PDU(name, docstring, fields, is_valid) \
00108     case name: {\
00109     struct name *p; p = &pdu->u.name; \
00110     fields \
00111     } break;
00112 #define UINT(field, docstring, bits)
00113 #define UINTVAR(field, docstring)
00114 #define OCTSTR(field, docstring, lengthfield) octstr_destroy(p->field);
00115 #define REST(field, docstring) octstr_destroy(p->field);
00116 #define TYPE(bits, value)
00117 #define RESERVED(bits)
00118 #include "wsp_pdu.def"
00119 #undef RESERVED
00120 #undef TYPE
00121 #undef REST
00122 #undef OCTSTR
00123 #undef UINTVAR
00124 #undef UINT
00125 #undef PDU
00126     default:
00127         panic(0, "Cannot destroy unknown WSP PDU type %d", pdu->type);
00128         break;
00129     }
00130 
00131     gw_free(pdu);
00132 }
00133 
00134 /* Determine which type of PDU this is, using the TYPE macros in
00135  * the definition file. */
00136 static int wsp_pdu_type(Octstr *data) {
00137     long bitpos;
00138     long lastpos = -1;
00139     long lastnumbits = -1;
00140     long lastval = -1;
00141     int thistype;
00142 
00143     /* This code looks slow, but an optimizing compiler will
00144      * reduce it considerably.  gcc -O2 will produce a single
00145      * call to octstr_get_bits, folllowed by a sequence of
00146      * tests on lastval. */
00147 
00148 /* Only UINT and RESERVED fields may precede the TYPE */
00149 #define PDU(name, docstring, fields, is_valid) \
00150     bitpos = 0; \
00151     thistype = name; \
00152     fields
00153 #define UINT(field, docstring, bits) bitpos += (bits);
00154 #define UINTVAR(field, docstring)
00155 #define OCTSTR(field, docstring, lengthfield)
00156 #define REST(field, docstring)
00157 #define TYPE(bits, value) \
00158     if ((bits) != lastnumbits || bitpos != lastpos) { \
00159         lastval = octstr_get_bits(data, bitpos, (bits)); \
00160     } \
00161     if (lastval == (value)) \
00162         return thistype; \
00163     lastnumbits = (bits); \
00164     lastpos = bitpos;
00165 #define RESERVED(bits) bitpos += (bits);
00166 #include "wsp_pdu.def"
00167 #undef RESERVED
00168 #undef TYPE
00169 #undef REST
00170 #undef OCTSTR
00171 #undef UINTVAR
00172 #undef UINT
00173 #undef PDU
00174 
00175     return -1;
00176 }
00177 
00178 WSP_PDU *wsp_pdu_unpack(Octstr *data) {
00179     WSP_PDU *pdu = NULL;
00180     long bitpos = 0;
00181 
00182     gw_assert(data != NULL);
00183 
00184     pdu = gw_malloc(sizeof(*pdu));
00185 
00186     pdu->type = wsp_pdu_type(data);
00187 
00188     switch (pdu->type) {
00189 #define PDU(name, docstring, fields, is_valid) \
00190     case name: { \
00191         struct name *p = &pdu->u.name; \
00192         fields \
00193         gw_assert(bitpos % 8 == 0); \
00194         if (bitpos / 8 != octstr_len(data)) { \
00195             warning(0, "Bad length for " #name " PDU, " \
00196                 "expected %ld", bitpos / 8); \
00197         } \
00198         if (!(is_valid)) { \
00199             warning(0, #name " PDU failed %s", #is_valid); \
00200         } \
00201     } break;
00202 #define UINT(field, docstring, bits) \
00203     p->field = octstr_get_bits(data, bitpos, (bits)); \
00204     bitpos += (bits);
00205 #define UINTVAR(field, docstring) \
00206     gw_assert(bitpos % 8 == 0); \
00207     p->field = octstr_get_bits(data, bitpos + 1, 7); \
00208     while (octstr_get_bits(data, bitpos, 1)) { \
00209         bitpos += 8; \
00210         p->field <<= 7; \
00211         p->field |= octstr_get_bits(data, bitpos + 1, 7); \
00212     } \
00213     bitpos += 8;
00214 #define OCTSTR(field, docstring, lengthfield) \
00215     gw_assert(bitpos % 8 == 0); \
00216     p->field = octstr_copy(data, bitpos / 8, p->lengthfield); \
00217     bitpos += 8 * p->lengthfield;
00218 #define REST(field, docstring) \
00219     gw_assert(bitpos % 8 == 0); \
00220     if (bitpos / 8 <= octstr_len(data)) { \
00221         p->field = octstr_copy(data, bitpos / 8, \
00222                 octstr_len(data) - bitpos / 8); \
00223         bitpos = octstr_len(data) * 8; \
00224     } else { \
00225         p->field = octstr_create(""); \
00226     }
00227 #define TYPE(bits, value) bitpos += (bits);
00228 #define RESERVED(bits) bitpos += (bits);
00229 #include "wsp_pdu.def"
00230 #undef RESERVED
00231 #undef TYPE
00232 #undef REST
00233 #undef OCTSTR
00234 #undef UINTVAR
00235 #undef UINT
00236 #undef PDU
00237     default:
00238         warning(0, "WSP PDU with unknown type %d", pdu->type);
00239         gw_free(pdu);
00240         return NULL;
00241     }
00242 
00243     return pdu;
00244 }
00245 
00246 static void fixup_length_fields(WSP_PDU *pdu) {
00247     switch (pdu->type) {
00248 #define PDU(name, docstring, fields, is_valid) \
00249     case name: { \
00250         struct name *p; p = &pdu->u.name; \
00251         fields \
00252     } break;
00253 #define UINT(field, docstring, bits)
00254 #define UINTVAR(field, docstring)
00255 #define OCTSTR(field, docstring, lengthfield) \
00256     p->lengthfield = octstr_len(p->field);
00257 #define REST(field, docstring)
00258 #define TYPE(bits, value)
00259 #define RESERVED(bits)
00260 #include "wsp_pdu.def"
00261 #undef RESERVED
00262 #undef TYPE
00263 #undef REST
00264 #undef OCTSTR
00265 #undef UINTVAR
00266 #undef UINT
00267 #undef PDU
00268     }
00269 }
00270 
00271 Octstr *wsp_pdu_pack(WSP_PDU *pdu) {
00272     Octstr *data;
00273     long bitpos;
00274 
00275     /* We rely on octstr_set_bits to lengthen our octstr as needed. */
00276     data = octstr_create("");
00277 
00278     fixup_length_fields(pdu);
00279 
00280     bitpos = 0;
00281     switch (pdu->type) {
00282 #define PDU(name, docstring, fields, is_valid) \
00283     case name: { \
00284         struct name *p = &pdu->u.name; \
00285         fields \
00286         gw_assert(bitpos % 8 == 0); \
00287     } break;
00288 #define UINT(field, docstring, bits) \
00289     octstr_set_bits(data, bitpos, (bits), p->field); \
00290     bitpos += (bits);
00291 #define UINTVAR(field, docstring) \
00292     gw_assert(bitpos % 8 == 0); \
00293     octstr_append_uintvar(data, p->field); \
00294     bitpos = 8 * octstr_len(data);
00295 #define OCTSTR(field, docstring, lengthfield) \
00296     gw_assert(bitpos % 8 == 0); \
00297     if (p->field != NULL) \
00298         octstr_append(data, p->field); \
00299     bitpos += 8 * octstr_len(p->field);
00300 #define REST(field, docstring) \
00301     gw_assert(bitpos % 8 == 0); \
00302     if (p->field != NULL) \
00303         octstr_append(data, p->field); \
00304     bitpos += 8 * octstr_len(p->field);
00305 #define TYPE(bits, value) \
00306     octstr_set_bits(data, bitpos, (bits), (value)); \
00307     bitpos += (bits);
00308 #define RESERVED(bits) bitpos += (bits);
00309 #include "wsp_pdu.def"
00310 #undef RESERVED
00311 #undef TYPE
00312 #undef REST
00313 #undef OCTSTR
00314 #undef UINTVAR
00315 #undef UINT
00316 #undef PDU
00317     default:
00318         panic(0, "Packing unknown WSP PDU type %ld", (long) pdu->type);
00319     }
00320 
00321     return data;
00322 }
00323 
00324 void wsp_pdu_dump(WSP_PDU *pdu, int level) {
00325     char *dbg = "wap.wsp";
00326 
00327     switch (pdu->type) {
00328 #define PDU(name, docstring, fields, is_valid) \
00329     case name: { \
00330         struct name *p = &pdu->u.name; \
00331         debug(dbg, 0, "%*sWSP %s PDU at %p:", \
00332             level, "", #name, (void *)pdu); \
00333         fields \
00334     } break;
00335 #define UINT(field, docstring, bits) \
00336     debug(dbg, 0, "%*s %s: %lu", level, "", docstring, p->field);
00337 #define UINTVAR(field, docstring) \
00338     debug(dbg, 0, "%*s %s: %lu", level, "", docstring, p->field);
00339 #define OCTSTR(field, docstring, lengthfield) \
00340     debug(dbg, 0, "%*s %s:", level, "", docstring); \
00341     octstr_dump(p->field, level + 1);
00342 #define REST(field, docstring) \
00343     debug(dbg, 0, "%*s %s:", level, "", docstring); \
00344     octstr_dump(p->field, level + 1);
00345 #define TYPE(bits, value)
00346 #define RESERVED(bits)
00347 #include "wsp_pdu.def"
00348 #undef RESERVED
00349 #undef TYPE
00350 #undef REST
00351 #undef OCTSTR
00352 #undef UINTVAR
00353 #undef UINT
00354 #undef PDU
00355     default:
00356         debug(dbg, 0, "%*sWSP PDU at %p:", level, "", (void *)pdu);
00357         debug(dbg, 0, "%*s unknown type %u", level, "", pdu->type);
00358         break;
00359     }
00360     debug("wap.wsp", 0, "%*sWSP PDU dump ends.", level, "");
00361 }
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.